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