xref: /openbmc/sdbusplus/test/message/append.cpp (revision 8a30a8fb)
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 multiple strings, various forms.
197     {
198         auto m = newMethodCall__test(b);
199         auto str = "jkl;"s;
200         auto str2 = "JKL:"s;
201         m.append(1, "asdf", "ASDF"s, str,
202                  std::move(str2), 5);
203         verifyTypeString = "issssi";
204 
205         struct verify
206         {
207             static void op(sd_bus_message* m)
208             {
209                 int32_t a = 0, b = 0;
210                 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr,
211                            *s3 = nullptr;
212                 sd_bus_message_read(m, "issssi", &a, &s0, &s1, &s2, &s3, &b);
213                 assert(a == 1);
214                 assert(b == 5);
215                 assert(0 == strcmp("asdf", s0));
216                 assert(0 == strcmp("ASDF", s1));
217                 assert(0 == strcmp("jkl;", s2));
218                 assert(0 == strcmp("JKL:", s3));
219             }
220         };
221         verifyCallback = &verify::op;
222 
223         b.call_noreply(m);
224     }
225 
226     // Test object_path and signature.
227     {
228         auto m = newMethodCall__test(b);
229         auto o = sdbusplus::message::object_path("/asdf");
230         auto s = sdbusplus::message::signature("iii");
231         m.append(1, o, s, 4);
232         verifyTypeString = "iogi";
233 
234         struct verify
235         {
236             static void op(sd_bus_message* m)
237             {
238                 int32_t a = 0, b = 0;
239                 const char *s0 = nullptr, *s1 = nullptr;
240                 sd_bus_message_read(m, "iogi", &a, &s0, &s1, &b);
241                 assert(a == 1);
242                 assert(b == 4);
243                 assert(0 == strcmp("/asdf", s0));
244                 assert(0 == strcmp("iii", s1));
245 
246             }
247         };
248         verifyCallback = &verify::op;
249 
250         b.call_noreply(m);
251     }
252 
253     // Test vector.
254     {
255         auto m = newMethodCall__test(b);
256         std::vector<std::string> s{ "1", "2", "3"};
257         m.append(1, s, 2);
258         verifyTypeString = "iasi";
259 
260         struct verify
261         {
262             static void op(sd_bus_message* m)
263             {
264                 int32_t a = 0;
265                 sd_bus_message_read(m, "i", &a);
266                 assert(a == 1);
267 
268                 auto rc = sd_bus_message_enter_container(m,
269                                                          SD_BUS_TYPE_ARRAY,
270                                                          "s");
271                 assert(0 <= rc);
272 
273                 const char* s = nullptr;
274                 sd_bus_message_read_basic(m, 's', &s);
275                 assert(0 == strcmp("1", s));
276                 sd_bus_message_read_basic(m, 's', &s);
277                 assert(0 == strcmp("2", s));
278                 sd_bus_message_read_basic(m, 's', &s);
279                 assert(0 == strcmp("3", s));
280                 assert(1 == sd_bus_message_at_end(m, false));
281 
282                 sd_bus_message_exit_container(m);
283 
284                 sd_bus_message_read(m, "i", &a);
285                 assert(a == 2);
286 
287             }
288         };
289         verifyCallback = &verify::op;
290 
291 
292         b.call_noreply(m);
293     }
294 
295     // Test map.
296     {
297         auto m = newMethodCall__test(b);
298         std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } };
299         m.append(1, s, 2);
300         verifyTypeString = "ia{si}i";
301 
302         struct verify
303         {
304             static void op(sd_bus_message* m)
305             {
306                 int32_t a = 0;
307                 sd_bus_message_read(m, "i", &a);
308                 assert(a == 1);
309 
310                 auto rc = sd_bus_message_enter_container(m,
311                                                          SD_BUS_TYPE_ARRAY,
312                                                          "{si}");
313                 assert(0 <= rc);
314 
315                 rc = sd_bus_message_enter_container(m,
316                                                     SD_BUS_TYPE_DICT_ENTRY,
317                                                     "si");
318                 assert(0 <= rc);
319 
320                 const char* s = nullptr;
321                 sd_bus_message_read_basic(m, 's', &s);
322                 assert(0 == strcmp("asdf", s));
323                 sd_bus_message_read_basic(m, 'i', &a);
324                 assert(a == 3);
325 
326                 assert(1 == sd_bus_message_at_end(m, false));
327                 sd_bus_message_exit_container(m);
328 
329                 rc = sd_bus_message_enter_container(m,
330                                                     SD_BUS_TYPE_DICT_ENTRY,
331                                                     "si");
332                 assert(0 <= rc);
333 
334                 sd_bus_message_read_basic(m, 's', &s);
335                 assert(0 == strcmp("jkl;", s));
336                 sd_bus_message_read_basic(m, 'i', &a);
337                 assert(a == 4);
338 
339                 assert(1 == sd_bus_message_at_end(m, false));
340                 sd_bus_message_exit_container(m);
341 
342                 assert(1 == sd_bus_message_at_end(m, false));
343                 sd_bus_message_exit_container(m);
344 
345                 sd_bus_message_read(m, "i", &a);
346                 assert(a == 2);
347             }
348         };
349         verifyCallback = &verify::op;
350 
351         b.call_noreply(m);
352     }
353 
354     // Test tuple.
355     {
356         auto m = newMethodCall__test(b);
357         std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" };
358         m.append(1, a, 2);
359         verifyTypeString = "i(ids)i";
360 
361         struct verify
362         {
363             static void op(sd_bus_message* m)
364             {
365                 int32_t a = 0;
366                 double b = 0;
367                 const char* c = nullptr;
368 
369                 sd_bus_message_read(m, "i", &a);
370                 assert(a == 1);
371 
372                 auto rc = sd_bus_message_enter_container(m,
373                                                          SD_BUS_TYPE_STRUCT,
374                                                          "ids");
375                 assert(0 <= rc);
376 
377                 sd_bus_message_read(m, "ids", &a, &b, &c);
378                 assert(a == 3);
379                 assert(b == 4.1);
380                 assert(0 == strcmp(c, "asdf"));
381 
382                 sd_bus_message_exit_container(m);
383 
384                 sd_bus_message_read(m, "i", &a);
385                 assert(a == 2);
386             }
387         };
388         verifyCallback = &verify::op;
389 
390         b.call_noreply(m);
391     }
392 
393     // Test variant.
394     {
395         auto m = newMethodCall__test(b);
396         sdbusplus::message::variant<int, double> a1{3.1}, a2{4};
397         m.append(1, a1, a2, 2);
398         verifyTypeString = "ivvi";
399 
400         struct verify
401         {
402             static void op(sd_bus_message* m)
403             {
404                 int32_t a = 0;
405                 double b = 0;
406 
407                 sd_bus_message_read(m, "i", &a);
408                 assert(a == 1);
409 
410                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
411                 sd_bus_message_read(m, "d", &b);
412                 assert(b == 3.1);
413                 sd_bus_message_exit_container(m);
414 
415                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
416                 sd_bus_message_read(m, "i", &a);
417                 assert(a == 4);
418                 sd_bus_message_exit_container(m);
419 
420                 sd_bus_message_read(m, "i", &a);
421                 assert(a == 2);
422             }
423         };
424         verifyCallback = &verify::op;
425 
426         b.call_noreply(m);
427     }
428 
429     // Test map-variant.
430     {
431         auto m = newMethodCall__test(b);
432         std::map<std::string, sdbusplus::message::variant<int, double>> a1 =
433                 { { "asdf", 3 }, { "jkl;", 4.1 } };
434         m.append(1, a1, 2);
435         verifyTypeString = "ia{sv}i";
436 
437         struct verify
438         {
439             static void op(sd_bus_message* m)
440             {
441                 int32_t a = 0;
442                 double b = 0;
443                 const char* c = nullptr;
444 
445                 sd_bus_message_read(m, "i", &a);
446                 assert(a == 1);
447 
448                 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
449                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
450                 sd_bus_message_read(m, "s", &c);
451                 assert(0 == strcmp("asdf", c));
452                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
453                 sd_bus_message_read(m, "i", &a);
454                 assert(a == 3);
455                 sd_bus_message_exit_container(m);
456                 sd_bus_message_exit_container(m);
457                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
458                 sd_bus_message_read(m, "s", &c);
459                 assert(0 == strcmp("jkl;", c));
460                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
461                 sd_bus_message_read(m, "d", &b);
462                 assert(b == 4.1);
463                 sd_bus_message_exit_container(m);
464                 sd_bus_message_exit_container(m);
465                 sd_bus_message_exit_container(m);
466 
467                 sd_bus_message_read(m, "i", &a);
468                 assert(a == 2);
469             }
470         };
471         verifyCallback = &verify::op;
472 
473         b.call_noreply(m);
474     }
475 
476     // Shutdown server.
477     {
478         auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);
479         b.call_noreply(m);
480     }
481 }
482 
483 int main()
484 {
485 
486     // Initialize and start server thread.
487     pthread_t t;
488     {
489         auto b = serverInit();
490         pthread_create(&t, NULL, server, b.release());
491     }
492 
493     runTests();
494 
495     // Wait for server thread to exit.
496     pthread_join(t, NULL);
497 
498     return 0;
499 }
500