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