xref: /openbmc/sdbusplus/test/message/append.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 (*)(sd_bus_message*);
24 verifyCallback_t verifyCallback = nullptr;
25 
26 static constexpr auto SERVICE = "sdbusplus.test.message.append";
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().release();
50 
51         if (m == nullptr)
52         {
53             bus.wait();
54             continue;
55         }
56 
57         if (sd_bus_message_is_method_call(m, INTERFACE, TEST_METHOD))
58         {
59             // Verify the message type matches what the test expects.
60             TEST_ASSERT(verifyTypeString ==
61                         sd_bus_message_get_signature(m, true));
62             if (verifyCallback)
63             {
64                 verifyCallback(m);
65                 verifyCallback = nullptr;
66             }
67             else
68             {
69                 std::cout << "Warning: No verification for " << verifyTypeString
70                           << std::endl;
71             }
72             // Reply to client.
73             sd_bus_reply_method_return(m, nullptr);
74         }
75         else if (sd_bus_message_is_method_call(m, INTERFACE, QUIT_METHOD))
76         {
77             // Reply and exit.
78             sd_bus_reply_method_return(m, nullptr);
79             sd_bus_message_unref(m);
80             break;
81         }
82 
83         sd_bus_message_unref(m);
84     }
85 
86     return nullptr;
87 }
88 
89 auto newMethodCall__test(sdbusplus::bus::bus& b)
90 {
91     // Allocate a method-call message for INTERFACE,TEST_METHOD.
92     return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD);
93 }
94 
95 void runTests()
96 {
97     using namespace std::literals;
98 
99     auto b = sdbusplus::bus::new_default();
100 
101     // Test r-value int.
102     {
103         auto m = newMethodCall__test(b);
104         m.append(1);
105         verifyTypeString = "i";
106 
107         struct verify
108         {
109             static void op(sd_bus_message* m)
110             {
111                 int32_t i = 0;
112                 sd_bus_message_read_basic(m, 'i', &i);
113                 TEST_ASSERT(i == 1);
114             }
115         };
116         verifyCallback = &verify::op;
117 
118         b.call_noreply(m);
119     }
120     // Test l-value int.
121     {
122         auto m = newMethodCall__test(b);
123         int a = 1;
124         m.append(a, a);
125         verifyTypeString = "ii";
126 
127         struct verify
128         {
129             static void op(sd_bus_message* m)
130             {
131                 int32_t a = 0, b = 0;
132                 sd_bus_message_read(m, "ii", &a, &b);
133                 TEST_ASSERT(a == 1);
134                 TEST_ASSERT(b == 1);
135             }
136         };
137         verifyCallback = &verify::op;
138 
139         b.call_noreply(m);
140     }
141 
142     // Test multiple ints.
143     {
144         auto m = newMethodCall__test(b);
145         m.append(1, 2, 3, 4, 5);
146         verifyTypeString = "iiiii";
147 
148         struct verify
149         {
150             static void op(sd_bus_message* m)
151             {
152                 int32_t a = 0, b = 0, c = 0, d = 0, e = 0;
153                 sd_bus_message_read(m, "iiiii", &a, &b, &c, &d, &e);
154                 TEST_ASSERT(a == 1);
155                 TEST_ASSERT(b == 2);
156                 TEST_ASSERT(c == 3);
157                 TEST_ASSERT(d == 4);
158                 TEST_ASSERT(e == 5);
159             }
160         };
161         verifyCallback = &verify::op;
162 
163         b.call_noreply(m);
164     }
165 
166     // Test double and bool.
167     {
168         auto m = newMethodCall__test(b);
169         bool t = true;
170         bool f = false;
171         bool f2 = false;
172         m.append(t, true, f, std::move(f2), false, 1.1);
173         verifyTypeString = "bbbbbd";
174 
175         struct verify
176         {
177             static void op(sd_bus_message* m)
178             {
179                 bool t1, t2, f1, f2, f3;
180                 double d;
181                 sd_bus_message_read(m, "bbbbbd", &t1, &t2, &f1, &f2, &f3, &d);
182                 TEST_ASSERT(t1);
183                 TEST_ASSERT(t2);
184                 TEST_ASSERT(!f1);
185                 TEST_ASSERT(!f2);
186                 TEST_ASSERT(!f3);
187                 TEST_ASSERT(d == 1.1);
188             }
189         };
190         verifyCallback = &verify::op;
191 
192         b.call_noreply(m);
193     }
194 
195     // Test r-value string.
196     {
197         auto m = newMethodCall__test(b);
198         m.append("asdf"s);
199         verifyTypeString = "s";
200 
201         struct verify
202         {
203             static void op(sd_bus_message* m)
204             {
205                 const char* s = nullptr;
206                 sd_bus_message_read_basic(m, 's', &s);
207                 TEST_ASSERT(0 == strcmp("asdf", s));
208             }
209         };
210         verifyCallback = &verify::op;
211 
212         b.call_noreply(m);
213     }
214 
215     // Test const string owned by const struct.  openbmc/openbmc#1025
216     {
217         struct
218         {
219             const char* foo;
220 
221             void insert(sdbusplus::message::message& m)
222             {
223                 m.append(foo);
224             }
225         } s;
226 
227         auto m = newMethodCall__test(b);
228         s.foo = "1234";
229         s.insert(m);
230 
231         verifyTypeString = "s";
232 
233         struct verify
234         {
235             static void op(sd_bus_message* m)
236             {
237                 const char* s = nullptr;
238                 sd_bus_message_read_basic(m, 's', &s);
239                 TEST_ASSERT(0 == strcmp("1234", s));
240             }
241         };
242         verifyCallback = &verify::op;
243 
244         b.call_noreply(m);
245     }
246 
247     // Test multiple strings, various forms.
248     {
249         auto m = newMethodCall__test(b);
250         auto str = "jkl;"s;
251         auto str2 = "JKL:"s;
252         const char* str3 = "1234";
253         const char* const str4 = "5678";
254         const auto str5 = "!@#$";
255         m.append(1, "asdf", "ASDF"s, str, std::move(str2), str3, str4, str5, 5);
256         verifyTypeString = "isssssssi";
257 
258         struct verify
259         {
260             static void op(sd_bus_message* m)
261             {
262                 int32_t a = 0, b = 0;
263                 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr,
264                            *s3 = nullptr, *s4 = nullptr, *s5 = nullptr,
265                            *s6 = nullptr;
266                 sd_bus_message_read(m, "isssssssi", &a, &s0, &s1, &s2, &s3, &s4,
267                                     &s5, &s6, &b);
268                 TEST_ASSERT(a == 1);
269                 TEST_ASSERT(b == 5);
270                 TEST_ASSERT(0 == strcmp("asdf", s0));
271                 TEST_ASSERT(0 == strcmp("ASDF", s1));
272                 TEST_ASSERT(0 == strcmp("jkl;", s2));
273                 TEST_ASSERT(0 == strcmp("JKL:", s3));
274                 TEST_ASSERT(0 == strcmp("1234", s4));
275                 TEST_ASSERT(0 == strcmp("5678", s5));
276                 TEST_ASSERT(0 == strcmp("!@#$", s6));
277                 TEST_ASSERT(b == 5);
278             }
279         };
280         verifyCallback = &verify::op;
281 
282         b.call_noreply(m);
283     }
284 
285     // Test object_path and signature.
286     {
287         auto m = newMethodCall__test(b);
288         auto o = sdbusplus::message::object_path("/asdf");
289         auto s = sdbusplus::message::signature("iii");
290         m.append(1, o, s, 4);
291         verifyTypeString = "iogi";
292 
293         struct verify
294         {
295             static void op(sd_bus_message* m)
296             {
297                 int32_t a = 0, b = 0;
298                 const char *s0 = nullptr, *s1 = nullptr;
299                 sd_bus_message_read(m, "iogi", &a, &s0, &s1, &b);
300                 TEST_ASSERT(a == 1);
301                 TEST_ASSERT(b == 4);
302                 TEST_ASSERT(0 == strcmp("/asdf", s0));
303                 TEST_ASSERT(0 == strcmp("iii", s1));
304             }
305         };
306         verifyCallback = &verify::op;
307 
308         b.call_noreply(m);
309     }
310 
311     // Test vector.
312     {
313         auto m = newMethodCall__test(b);
314         std::vector<std::string> s{"1", "2", "3"};
315         m.append(1, s, 2);
316         verifyTypeString = "iasi";
317 
318         struct verify
319         {
320             static void op(sd_bus_message* m)
321             {
322                 int32_t a = 0;
323                 sd_bus_message_read(m, "i", &a);
324                 TEST_ASSERT(a == 1);
325 
326                 auto rc =
327                     sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
328                 TEST_ASSERT(0 <= rc);
329 
330                 const char* s = nullptr;
331                 sd_bus_message_read_basic(m, 's', &s);
332                 TEST_ASSERT(0 == strcmp("1", s));
333                 sd_bus_message_read_basic(m, 's', &s);
334                 TEST_ASSERT(0 == strcmp("2", s));
335                 sd_bus_message_read_basic(m, 's', &s);
336                 TEST_ASSERT(0 == strcmp("3", s));
337                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
338 
339                 sd_bus_message_exit_container(m);
340 
341                 sd_bus_message_read(m, "i", &a);
342                 TEST_ASSERT(a == 2);
343             }
344         };
345         verifyCallback = &verify::op;
346 
347         b.call_noreply(m);
348     }
349 
350     // Test map.
351     {
352         auto m = newMethodCall__test(b);
353         std::map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}};
354         m.append(1, s, 2);
355         verifyTypeString = "ia{si}i";
356 
357         struct verify
358         {
359             static void op(sd_bus_message* m)
360             {
361                 int32_t a = 0;
362                 sd_bus_message_read(m, "i", &a);
363                 TEST_ASSERT(a == 1);
364 
365                 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY,
366                                                          "{si}");
367                 TEST_ASSERT(0 <= rc);
368 
369                 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
370                                                     "si");
371                 TEST_ASSERT(0 <= rc);
372 
373                 const char* s = nullptr;
374                 sd_bus_message_read_basic(m, 's', &s);
375                 TEST_ASSERT(0 == strcmp("asdf", s));
376                 sd_bus_message_read_basic(m, 'i', &a);
377                 TEST_ASSERT(a == 3);
378 
379                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
380                 sd_bus_message_exit_container(m);
381 
382                 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
383                                                     "si");
384                 TEST_ASSERT(0 <= rc);
385 
386                 sd_bus_message_read_basic(m, 's', &s);
387                 TEST_ASSERT(0 == strcmp("jkl;", s));
388                 sd_bus_message_read_basic(m, 'i', &a);
389                 TEST_ASSERT(a == 4);
390 
391                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
392                 sd_bus_message_exit_container(m);
393 
394                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
395                 sd_bus_message_exit_container(m);
396 
397                 sd_bus_message_read(m, "i", &a);
398                 TEST_ASSERT(a == 2);
399             }
400         };
401         verifyCallback = &verify::op;
402 
403         b.call_noreply(m);
404     }
405 
406     // Test unordered_map.
407     {
408         auto m = newMethodCall__test(b);
409         std::unordered_map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}};
410         m.append(1, s, 2);
411         verifyTypeString = "ia{si}i";
412 
413         struct verify
414         {
415             static void op(sd_bus_message* m)
416             {
417                 int32_t a = 0;
418                 sd_bus_message_read(m, "i", &a);
419                 TEST_ASSERT(a == 1);
420 
421                 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY,
422                                                          "{si}");
423                 TEST_ASSERT(0 <= rc);
424 
425                 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
426                                                     "si");
427                 TEST_ASSERT(0 <= rc);
428 
429                 const char* s = nullptr;
430                 sd_bus_message_read_basic(m, 's', &s);
431                 sd_bus_message_read_basic(m, 'i', &a);
432                 TEST_ASSERT((0 == strcmp("asdf", s) && a == 3) ||
433                             (a = 4 && 0 == strcmp("jkl;", s)));
434 
435                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
436                 sd_bus_message_exit_container(m);
437 
438                 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY,
439                                                     "si");
440                 TEST_ASSERT(0 <= rc);
441 
442                 sd_bus_message_read_basic(m, 's', &s);
443                 sd_bus_message_read_basic(m, 'i', &a);
444                 TEST_ASSERT((0 == strcmp("asdf", s) && a == 3) ||
445                             (a = 4 && 0 == strcmp("jkl;", s)));
446 
447                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
448                 sd_bus_message_exit_container(m);
449 
450                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
451                 sd_bus_message_exit_container(m);
452 
453                 sd_bus_message_read(m, "i", &a);
454                 TEST_ASSERT(a == 2);
455             }
456         };
457         verifyCallback = &verify::op;
458 
459         b.call_noreply(m);
460     }
461 
462     // Test set.
463     {
464         auto m = newMethodCall__test(b);
465         std::set<std::string> s = {{"asdf"}, {"jkl;"}};
466         m.append(1, s, 2);
467         verifyTypeString = "iasi";
468 
469         struct verify
470         {
471             static void op(sd_bus_message* m)
472             {
473                 int32_t a = 0;
474                 sd_bus_message_read(m, "i", &a);
475                 TEST_ASSERT(a == 1);
476 
477                 auto rc =
478                     sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
479                 TEST_ASSERT(0 <= rc);
480 
481                 const char* s = nullptr;
482                 sd_bus_message_read_basic(m, 's', &s);
483                 TEST_ASSERT(0 == strcmp("asdf", s));
484 
485                 sd_bus_message_read_basic(m, 's', &s);
486                 TEST_ASSERT(0 == strcmp("jkl;", s));
487 
488                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
489                 sd_bus_message_exit_container(m);
490 
491                 sd_bus_message_read(m, "i", &a);
492                 TEST_ASSERT(a == 2);
493             }
494         };
495         verifyCallback = &verify::op;
496 
497         b.call_noreply(m);
498     }
499 
500     // Test array.
501     {
502         auto m = newMethodCall__test(b);
503         std::array<std::string, 3> s{"1", "2", "3"};
504         m.append(1, s, 2);
505         verifyTypeString = "iasi";
506 
507         struct verify
508         {
509             static void op(sd_bus_message* m)
510             {
511                 int32_t a = 0;
512                 sd_bus_message_read(m, "i", &a);
513                 TEST_ASSERT(a == 1);
514 
515                 auto rc =
516                     sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
517                 TEST_ASSERT(0 <= rc);
518 
519                 const char* s = nullptr;
520                 sd_bus_message_read_basic(m, 's', &s);
521                 TEST_ASSERT(0 == strcmp("1", s));
522                 sd_bus_message_read_basic(m, 's', &s);
523                 TEST_ASSERT(0 == strcmp("2", s));
524                 sd_bus_message_read_basic(m, 's', &s);
525                 TEST_ASSERT(0 == strcmp("3", s));
526                 TEST_ASSERT(1 == sd_bus_message_at_end(m, false));
527 
528                 sd_bus_message_exit_container(m);
529 
530                 sd_bus_message_read(m, "i", &a);
531                 TEST_ASSERT(a == 2);
532             }
533         };
534         verifyCallback = &verify::op;
535 
536         b.call_noreply(m);
537     }
538 
539     // Test tuple.
540     {
541         auto m = newMethodCall__test(b);
542         std::tuple<int, double, std::string> a{3, 4.1, "asdf"};
543         m.append(1, a, 2);
544         verifyTypeString = "i(ids)i";
545 
546         struct verify
547         {
548             static void op(sd_bus_message* m)
549             {
550                 int32_t a = 0;
551                 double b = 0;
552                 const char* c = nullptr;
553 
554                 sd_bus_message_read(m, "i", &a);
555                 TEST_ASSERT(a == 1);
556 
557                 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT,
558                                                          "ids");
559                 TEST_ASSERT(0 <= rc);
560 
561                 sd_bus_message_read(m, "ids", &a, &b, &c);
562                 TEST_ASSERT(a == 3);
563                 TEST_ASSERT(b == 4.1);
564                 TEST_ASSERT(0 == strcmp(c, "asdf"));
565 
566                 sd_bus_message_exit_container(m);
567 
568                 sd_bus_message_read(m, "i", &a);
569                 TEST_ASSERT(a == 2);
570             }
571         };
572         verifyCallback = &verify::op;
573 
574         b.call_noreply(m);
575     }
576 
577     // Test variant.
578     {
579         auto m = newMethodCall__test(b);
580         sdbusplus::message::variant<int, double> a1{3.1}, a2{4};
581         m.append(1, a1, a2, 2);
582         verifyTypeString = "ivvi";
583 
584         struct verify
585         {
586             static void op(sd_bus_message* m)
587             {
588                 int32_t a = 0;
589                 double b = 0;
590 
591                 sd_bus_message_read(m, "i", &a);
592                 TEST_ASSERT(a == 1);
593 
594                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
595                 sd_bus_message_read(m, "d", &b);
596                 TEST_ASSERT(b == 3.1);
597                 sd_bus_message_exit_container(m);
598 
599                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
600                 sd_bus_message_read(m, "i", &a);
601                 TEST_ASSERT(a == 4);
602                 sd_bus_message_exit_container(m);
603 
604                 sd_bus_message_read(m, "i", &a);
605                 TEST_ASSERT(a == 2);
606             }
607         };
608         verifyCallback = &verify::op;
609 
610         b.call_noreply(m);
611     }
612 
613     // Test map-variant.
614     {
615         auto m = newMethodCall__test(b);
616         std::map<std::string, sdbusplus::message::variant<int, double>> a1 = {
617             {"asdf", 3}, {"jkl;", 4.1}};
618         m.append(1, a1, 2);
619         verifyTypeString = "ia{sv}i";
620 
621         struct verify
622         {
623             static void op(sd_bus_message* m)
624             {
625                 int32_t a = 0;
626                 double b = 0;
627                 const char* c = nullptr;
628 
629                 sd_bus_message_read(m, "i", &a);
630                 TEST_ASSERT(a == 1);
631 
632                 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
633                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
634                 sd_bus_message_read(m, "s", &c);
635                 TEST_ASSERT(0 == strcmp("asdf", c));
636                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
637                 sd_bus_message_read(m, "i", &a);
638                 TEST_ASSERT(a == 3);
639                 sd_bus_message_exit_container(m);
640                 sd_bus_message_exit_container(m);
641                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
642                 sd_bus_message_read(m, "s", &c);
643                 TEST_ASSERT(0 == strcmp("jkl;", c));
644                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
645                 sd_bus_message_read(m, "d", &b);
646                 TEST_ASSERT(b == 4.1);
647                 sd_bus_message_exit_container(m);
648                 sd_bus_message_exit_container(m);
649                 sd_bus_message_exit_container(m);
650 
651                 sd_bus_message_read(m, "i", &a);
652                 TEST_ASSERT(a == 2);
653             }
654         };
655         verifyCallback = &verify::op;
656 
657         b.call_noreply(m);
658     }
659 
660     // Shutdown server.
661     {
662         auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);
663         b.call_noreply(m);
664     }
665 }
666 
667 int main()
668 {
669 
670     // Initialize and start server thread.
671     pthread_t t;
672     {
673         auto b = serverInit();
674         pthread_create(&t, NULL, server, b.release());
675     }
676 
677     runTests();
678 
679     // Wait for server thread to exit.
680     pthread_join(t, NULL);
681 
682     return 0;
683 }
684