xref: /openbmc/sdbusplus/test/message/read.cpp (revision 874e82e5)
1 #include <iostream>
2 #include <cassert>
3 #include <sdbusplus/message.hpp>
4 #include <sdbusplus/bus.hpp>
5 #include <unordered_map>
6 #include <set>
7 
8 // Make sure even in non-debug mode we use asserts
9 #define TEST_ASSERT(n)                                                         \
10     do                                                                         \
11     {                                                                          \
12         if (!(n))                                                              \
13         {                                                                      \
14             fprintf(stderr, "%s:%d %s: Assertion `%s` failed\n", __FILE__,     \
15                     __LINE__, __func__, #n);                                   \
16             abort();                                                           \
17         }                                                                      \
18     } while (0)
19 
20 // Global to share the dbus type string between client and server.
21 static std::string verifyTypeString;
22 
23 using verifyCallback_t = void (*)(sdbusplus::message::message&);
24 verifyCallback_t verifyCallback = nullptr;
25 
26 static constexpr auto SERVICE = "sdbusplus.test.message.read";
27 static constexpr auto INTERFACE = SERVICE;
28 static constexpr auto TEST_METHOD = "test";
29 static constexpr auto QUIT_METHOD = "quit";
30 
31 // Open up the sdbus and claim SERVICE name.
32 auto serverInit()
33 {
34     auto b = sdbusplus::bus::new_default();
35     b.request_name(SERVICE);
36 
37     return std::move(b);
38 }
39 
40 // Thread to run the dbus server.
41 void* server(void* b)
42 {
43     auto bus = sdbusplus::bus::bus(reinterpret_cast<sdbusplus::bus::busp_t>(b),
44                                    std::false_type());
45 
46     while (1)
47     {
48         // Wait for messages.
49         auto m = bus.process();
50 
51         if (!m)
52         {
53             bus.wait();
54             continue;
55         }
56 
57         if (m.is_method_call(INTERFACE, TEST_METHOD))
58         {
59             // Verify the message type matches what the test expects.
60             TEST_ASSERT(verifyTypeString == m.get_signature());
61 
62             if (verifyCallback)
63             {
64 
65                 verifyCallback(m);
66                 verifyCallback = nullptr;
67             }
68             else
69             {
70                 std::cout << "Warning: No verification for " << verifyTypeString
71                           << std::endl;
72             }
73             // Reply to client.
74             auto sd_m = m.release();
75             sd_bus_reply_method_return(sd_m, nullptr);
76             sd_bus_message_unref(sd_m);
77         }
78         else if (m.is_method_call(INTERFACE, QUIT_METHOD))
79         {
80             // Reply and exit.
81             auto sd_m = m.release();
82             sd_bus_reply_method_return(sd_m, nullptr);
83             sd_bus_message_unref(sd_m);
84             break;
85         }
86     }
87 
88     return nullptr;
89 }
90 
91 auto newMethodCall__test(sdbusplus::bus::bus& b)
92 {
93     // Allocate a method-call message for INTERFACE,TEST_METHOD.
94     return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD);
95 }
96 
97 void runTests()
98 {
99     using namespace std::literals;
100 
101     auto b = sdbusplus::bus::new_default();
102 
103     // Test r-value int.
104     {
105         auto m = newMethodCall__test(b);
106         m.append(1);
107         verifyTypeString = "i";
108 
109         struct verify
110         {
111             static void op(sdbusplus::message::message& m)
112             {
113                 int32_t i = 0;
114                 m.read(i);
115                 TEST_ASSERT(i == 1);
116             }
117         };
118         verifyCallback = &verify::op;
119 
120         b.call_noreply(m);
121     }
122     // Test l-value int.
123     {
124         auto m = newMethodCall__test(b);
125         int a = 1;
126         m.append(a, a);
127         verifyTypeString = "ii";
128 
129         struct verify
130         {
131             static void op(sdbusplus::message::message& m)
132             {
133                 int32_t a = 0, b = 0;
134                 m.read(a, b);
135                 TEST_ASSERT(a == 1);
136                 TEST_ASSERT(b == 1);
137             }
138         };
139         verifyCallback = &verify::op;
140 
141         b.call_noreply(m);
142     }
143 
144     // Test multiple ints.
145     {
146         auto m = newMethodCall__test(b);
147         m.append(1, 2, 3, 4, 5);
148         verifyTypeString = "iiiii";
149 
150         struct verify
151         {
152             static void op(sdbusplus::message::message& m)
153             {
154                 int32_t a = 0, b = 0, c = 0, d = 0, e = 0;
155                 m.read(a, b, c, d, e);
156                 TEST_ASSERT(a == 1);
157                 TEST_ASSERT(b == 2);
158                 TEST_ASSERT(c == 3);
159                 TEST_ASSERT(d == 4);
160                 TEST_ASSERT(e == 5);
161             }
162         };
163         verifyCallback = &verify::op;
164 
165         b.call_noreply(m);
166     }
167 
168     // Test double and bool.
169     {
170         auto m = newMethodCall__test(b);
171         bool t = true;
172         bool f = false;
173         bool f2 = false;
174         m.append(t, true, f, std::move(f2), false, 1.1);
175         verifyTypeString = "bbbbbd";
176 
177         struct verify
178         {
179             static void op(sdbusplus::message::message& m)
180             {
181                 bool t1, t2, f1, f2, f3;
182                 double d;
183                 m.read(t1, t2, f1, f2, f3, d);
184                 TEST_ASSERT(t1);
185                 TEST_ASSERT(t2);
186                 TEST_ASSERT(!f1);
187                 TEST_ASSERT(!f2);
188                 TEST_ASSERT(!f3);
189                 TEST_ASSERT(d == 1.1);
190             }
191         };
192         verifyCallback = &verify::op;
193 
194         b.call_noreply(m);
195     }
196 
197     // Test r-value string.
198     {
199         auto m = newMethodCall__test(b);
200         m.append("asdf"s);
201         verifyTypeString = "s";
202 
203         struct verify
204         {
205             static void op(sdbusplus::message::message& m)
206             {
207                 const char* s = nullptr;
208                 m.read(s);
209                 TEST_ASSERT(0 == strcmp("asdf", s));
210             }
211         };
212         verifyCallback = &verify::op;
213 
214         b.call_noreply(m);
215     }
216 
217     // Test multiple strings, various forms.
218     {
219         auto m = newMethodCall__test(b);
220         auto str = "jkl;"s;
221         auto str2 = "JKL:"s;
222         m.append(1, "asdf", "ASDF"s, str, std::move(str2), 5);
223         verifyTypeString = "issssi";
224 
225         struct verify
226         {
227             static void op(sdbusplus::message::message& m)
228             {
229                 int32_t a = 0, b = 0;
230                 std::string s0, s1, s2, s3;
231                 m.read(a, s0, s1, s2, s3, b);
232                 TEST_ASSERT(a == 1);
233                 TEST_ASSERT(b == 5);
234                 TEST_ASSERT(s0 == "asdf"s);
235                 TEST_ASSERT(s1 == "ASDF"s);
236                 TEST_ASSERT(s2 == "jkl;"s);
237                 TEST_ASSERT(s3 == "JKL:");
238             }
239         };
240         verifyCallback = &verify::op;
241 
242         b.call_noreply(m);
243     }
244 
245     // Test object_path and signature.
246     {
247         auto m = newMethodCall__test(b);
248         auto o = sdbusplus::message::object_path("/asdf");
249         auto s = sdbusplus::message::signature("iii");
250         m.append(1, o, s, 4);
251         verifyTypeString = "iogi";
252 
253         struct verify
254         {
255             static void op(sdbusplus::message::message& m)
256             {
257                 int32_t a = 0, b = 0;
258                 sdbusplus::message::object_path o;
259                 sdbusplus::message::signature s;
260                 m.read(a, o, s, b);
261                 TEST_ASSERT(a == 1);
262                 TEST_ASSERT(b == 4);
263                 TEST_ASSERT(std::string(o) == "/asdf"s);
264                 TEST_ASSERT(std::string(s) == "iii"s);
265             }
266         };
267         verifyCallback = &verify::op;
268 
269         b.call_noreply(m);
270     }
271 
272     // Test vector.
273     {
274         auto m = newMethodCall__test(b);
275         std::vector<std::string> s{"1", "2", "3"};
276         m.append(1, s, 2);
277         verifyTypeString = "iasi";
278 
279         struct verify
280         {
281             static void op(sdbusplus::message::message& m)
282             {
283                 int32_t a = 0;
284                 std::vector<std::string> s;
285                 m.read(a, s);
286                 TEST_ASSERT(a == 1);
287                 TEST_ASSERT(s[0] == "1");
288                 TEST_ASSERT(s[1] == "2");
289                 TEST_ASSERT(s[2] == "3");
290                 decltype(s) s2 = {"1", "2", "3"};
291                 TEST_ASSERT(s == s2);
292             }
293         };
294         verifyCallback = &verify::op;
295 
296         b.call_noreply(m);
297     }
298 
299     // Test map.
300     {
301         auto m = newMethodCall__test(b);
302         std::map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}};
303         m.append(1, s, 2);
304         verifyTypeString = "ia{si}i";
305 
306         struct verify
307         {
308             static void op(sdbusplus::message::message& m)
309             {
310                 int32_t a = 0, b = 0;
311                 std::map<std::string, int> s{};
312 
313                 m.read(a, s, b);
314                 TEST_ASSERT(a == 1);
315                 TEST_ASSERT(s.size() == 2);
316                 TEST_ASSERT(s["asdf"] == 3);
317                 TEST_ASSERT(s["jkl;"] == 4);
318                 TEST_ASSERT(b == 2);
319             }
320         };
321         verifyCallback = &verify::op;
322 
323         b.call_noreply(m);
324     }
325 
326     // Test unordered_map.
327     {
328         auto m = newMethodCall__test(b);
329         std::unordered_map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}};
330         m.append(1, s, 2);
331         verifyTypeString = "ia{si}i";
332 
333         struct verify
334         {
335             static void op(sdbusplus::message::message& m)
336             {
337                 int32_t a = 0, b = 0;
338                 std::unordered_map<std::string, int> s{};
339 
340                 m.read(a, s, b);
341                 TEST_ASSERT(a == 1);
342                 TEST_ASSERT(s.size() == 2);
343                 TEST_ASSERT(s["asdf"] == 3);
344                 TEST_ASSERT(s["jkl;"] == 4);
345                 TEST_ASSERT(b == 2);
346             }
347         };
348         verifyCallback = &verify::op;
349 
350         b.call_noreply(m);
351     }
352 
353     // Test set.
354     {
355         auto m = newMethodCall__test(b);
356         std::set<std::string> s = {{"asdf"}, {"jkl;"}};
357         m.append(1, s, 2);
358         verifyTypeString = "iasi";
359 
360         struct verify
361         {
362             static void op(sdbusplus::message::message& m)
363             {
364                 int32_t a = 0, b = 0;
365                 std::set<std::string> s{};
366 
367                 m.read(a, s, b);
368                 TEST_ASSERT(a == 1);
369                 TEST_ASSERT(s.size() == 2);
370                 TEST_ASSERT(s.find("asdf") != s.end());
371                 TEST_ASSERT(s.find("jkl;") != s.end());
372                 TEST_ASSERT(b == 2);
373             }
374         };
375         verifyCallback = &verify::op;
376 
377         b.call_noreply(m);
378     }
379 
380     // Test tuple.
381     {
382         auto m = newMethodCall__test(b);
383         std::tuple<int, double, std::string> a{3, 4.1, "asdf"};
384         m.append(1, a, 2);
385         verifyTypeString = "i(ids)i";
386 
387         struct verify
388         {
389             static void op(sdbusplus::message::message& m)
390             {
391                 int32_t a = 0, b = 0;
392                 std::tuple<int, double, std::string> c{};
393 
394                 m.read(a, c, b);
395                 TEST_ASSERT(a == 1);
396                 TEST_ASSERT(b == 2);
397                 TEST_ASSERT(c == std::make_tuple(3, 4.1, "asdf"s));
398             }
399         };
400         verifyCallback = &verify::op;
401 
402         b.call_noreply(m);
403     }
404 
405     // Test variant.
406     {
407         auto m = newMethodCall__test(b);
408         sdbusplus::message::variant<int, double> a1{3.1}, a2{4};
409         m.append(1, a1, a2, 2);
410         verifyTypeString = "ivvi";
411 
412         struct verify
413         {
414             static void op(sdbusplus::message::message& m)
415             {
416                 int32_t a, b;
417                 sdbusplus::message::variant<int, double> a1{}, a2{};
418 
419                 m.read(a, a1, a2, b);
420                 TEST_ASSERT(a == 1);
421                 TEST_ASSERT(a1 == 3.1);
422                 TEST_ASSERT(a2 == 4);
423                 TEST_ASSERT(b == 2);
424             }
425         };
426         verifyCallback = &verify::op;
427 
428         b.call_noreply(m);
429     }
430 
431     // Test variant with missing/wrong type.
432     {
433         auto m = newMethodCall__test(b);
434         sdbusplus::message::variant<uint64_t, double> a1{3.1}, a2{uint64_t(4)};
435         m.append(1, a1, a2, 2);
436         verifyTypeString = "ivvi";
437 
438         struct verify
439         {
440             static void op(sdbusplus::message::message& m)
441             {
442                 int32_t a, b;
443                 sdbusplus::message::variant<uint8_t, double> a1{}, a2{};
444 
445                 m.read(a, a1, a2, b);
446                 TEST_ASSERT(a == 1);
447                 TEST_ASSERT(a1 == 3.1);
448                 TEST_ASSERT(a2 == uint8_t());
449                 TEST_ASSERT(b == 2);
450             }
451         };
452         verifyCallback = &verify::op;
453 
454         b.call_noreply(m);
455     }
456 
457     // Test map-variant.
458     {
459         auto m = newMethodCall__test(b);
460         std::map<std::string, sdbusplus::message::variant<int, double>> a1 = {
461             {"asdf", 3}, {"jkl;", 4.1}};
462         m.append(1, a1, 2);
463         verifyTypeString = "ia{sv}i";
464 
465         struct verify
466         {
467             static void op(sdbusplus::message::message& m)
468             {
469                 int32_t a = 0, b = 0;
470                 std::map<std::string, sdbusplus::message::variant<int, double>>
471                     a1{};
472 
473                 m.read(a, a1, b);
474                 TEST_ASSERT(a == 1);
475                 TEST_ASSERT(a1["asdf"] == 3);
476                 TEST_ASSERT(a1["jkl;"] == 4.1);
477                 TEST_ASSERT(b == 2);
478             }
479         };
480         verifyCallback = &verify::op;
481 
482         b.call_noreply(m);
483     }
484 
485     // Shutdown server.
486     {
487         auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);
488         b.call_noreply(m);
489     }
490 }
491 
492 int main()
493 {
494 
495     // Initialize and start server thread.
496     pthread_t t;
497     {
498         auto b = serverInit();
499         pthread_create(&t, NULL, server, b.release());
500     }
501 
502     runTests();
503 
504     // Wait for server thread to exit.
505     pthread_join(t, NULL);
506 
507     return 0;
508 }
509