xref: /openbmc/sdbusplus/test/message/append.cpp (revision 5302a466)
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";
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 
68 auto newMethodCall__test(sdbusplus::bus::bus& b)
69 {
70     // Allocate a method-call message for INTERFACE,TEST_METHOD.
71     return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD);
72 }
73 
74 void runTests()
75 {
76     using namespace std::literals;
77 
78     auto b = sdbusplus::bus::new_default();
79 
80     // Test r-value int.
81     {
82         auto m = newMethodCall__test(b);
83         m.append(1);
84         verifyTypeString = "i";
85 
86         struct verify
87         {
88             static void op(sd_bus_message* m)
89             {
90                 int32_t i = 0;
91                 sd_bus_message_read_basic(m, 'i', &i);
92                 assert(i == 1);
93             }
94         };
95         verifyCallback = &verify::op;
96 
97         b.call_noreply(m);
98     }
99     // Test l-value int.
100     {
101         auto m = newMethodCall__test(b);
102         int a = 1;
103         m.append(a, a);
104         verifyTypeString = "ii";
105 
106         struct verify
107         {
108             static void op(sd_bus_message* m)
109             {
110                 int32_t a = 0, b = 0;
111                 sd_bus_message_read(m, "ii", &a, &b);
112                 assert(a == 1);
113                 assert(b == 1);
114             }
115         };
116         verifyCallback = &verify::op;
117 
118         b.call_noreply(m);
119     }
120 
121     // Test multiple ints.
122     {
123         auto m = newMethodCall__test(b);
124         m.append(1, 2, 3, 4, 5);
125         verifyTypeString = "iiiii";
126 
127         struct verify
128         {
129             static void op(sd_bus_message* m)
130             {
131                 int32_t a = 0, b = 0, c = 0, d = 0, e = 0;
132                 sd_bus_message_read(m, "iiiii", &a, &b, &c, &d, &e);
133                 assert(a == 1);
134                 assert(b == 2);
135                 assert(c == 3);
136                 assert(d == 4);
137                 assert(e == 5);
138             }
139         };
140         verifyCallback = &verify::op;
141 
142         b.call_noreply(m);
143     }
144 
145     // Test double and bool.
146     {
147         auto m = newMethodCall__test(b);
148         bool t = true;
149         m.append(t, true, false, 1.1);
150         verifyTypeString = "bbbd";
151 
152         struct verify
153         {
154             static void op(sd_bus_message* m)
155             {
156                 bool t1, t2, f1;
157                 double d;
158                 sd_bus_message_read(m, "bbbd", &t1, &t2, &f1, &d);
159                 assert(t1);
160                 assert(t2);
161                 assert(!f1);
162                 assert(d == 1.1);
163             }
164         };
165         verifyCallback = &verify::op;
166 
167         b.call_noreply(m);
168     }
169 
170     // Test r-value string.
171     {
172         auto m = newMethodCall__test(b);
173         m.append("asdf"s);
174         verifyTypeString = "s";
175 
176         struct verify
177         {
178             static void op(sd_bus_message* m)
179             {
180                 const char* s = nullptr;
181                 sd_bus_message_read_basic(m, 's', &s);
182                 assert(0 == strcmp("asdf", s));
183             }
184         };
185         verifyCallback = &verify::op;
186 
187         b.call_noreply(m);
188     }
189 
190     // Test multiple strings, various forms.
191     {
192         auto m = newMethodCall__test(b);
193         auto str = "jkl;"s;
194         auto str2 = "JKL:"s;
195         m.append(1, "asdf", "ASDF"s, str,
196                  std::move(str2), 5);
197         verifyTypeString = "issssi";
198 
199         struct verify
200         {
201             static void op(sd_bus_message* m)
202             {
203                 int32_t a = 0, b = 0;
204                 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr,
205                            *s3 = nullptr;
206                 sd_bus_message_read(m, "issssi", &a, &s0, &s1, &s2, &s3, &b);
207                 assert(a == 1);
208                 assert(b == 5);
209                 assert(0 == strcmp("asdf", s0));
210                 assert(0 == strcmp("ASDF", s1));
211                 assert(0 == strcmp("jkl;", s2));
212                 assert(0 == strcmp("JKL:", s3));
213             }
214         };
215         verifyCallback = &verify::op;
216 
217         b.call_noreply(m);
218     }
219 
220     // Test vector.
221     {
222         auto m = newMethodCall__test(b);
223         std::vector<std::string> s{ "1", "2", "3"};
224         m.append(1, s, 2);
225         verifyTypeString = "iasi";
226 
227         struct verify
228         {
229             static void op(sd_bus_message* m)
230             {
231                 int32_t a = 0;
232                 sd_bus_message_read(m, "i", &a);
233                 assert(a == 1);
234 
235                 auto rc = sd_bus_message_enter_container(m,
236                                                          SD_BUS_TYPE_ARRAY,
237                                                          "s");
238                 assert(0 <= rc);
239 
240                 const char* s = nullptr;
241                 sd_bus_message_read_basic(m, 's', &s);
242                 assert(0 == strcmp("1", s));
243                 sd_bus_message_read_basic(m, 's', &s);
244                 assert(0 == strcmp("2", s));
245                 sd_bus_message_read_basic(m, 's', &s);
246                 assert(0 == strcmp("3", s));
247                 assert(1 == sd_bus_message_at_end(m, false));
248 
249                 sd_bus_message_exit_container(m);
250 
251                 sd_bus_message_read(m, "i", &a);
252                 assert(a == 2);
253 
254             }
255         };
256         verifyCallback = &verify::op;
257 
258 
259         b.call_noreply(m);
260     }
261 
262     // Test map.
263     {
264         auto m = newMethodCall__test(b);
265         std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } };
266         m.append(1, s, 2);
267         verifyTypeString = "ia{si}i";
268 
269         struct verify
270         {
271             static void op(sd_bus_message* m)
272             {
273                 int32_t a = 0;
274                 sd_bus_message_read(m, "i", &a);
275                 assert(a == 1);
276 
277                 auto rc = sd_bus_message_enter_container(m,
278                                                          SD_BUS_TYPE_ARRAY,
279                                                          "{si}");
280                 assert(0 <= rc);
281 
282                 rc = sd_bus_message_enter_container(m,
283                                                     SD_BUS_TYPE_DICT_ENTRY,
284                                                     "si");
285                 assert(0 <= rc);
286 
287                 const char* s = nullptr;
288                 sd_bus_message_read_basic(m, 's', &s);
289                 assert(0 == strcmp("asdf", s));
290                 sd_bus_message_read_basic(m, 'i', &a);
291                 assert(a == 3);
292 
293                 assert(1 == sd_bus_message_at_end(m, false));
294                 sd_bus_message_exit_container(m);
295 
296                 rc = sd_bus_message_enter_container(m,
297                                                     SD_BUS_TYPE_DICT_ENTRY,
298                                                     "si");
299                 assert(0 <= rc);
300 
301                 sd_bus_message_read_basic(m, 's', &s);
302                 assert(0 == strcmp("jkl;", s));
303                 sd_bus_message_read_basic(m, 'i', &a);
304                 assert(a == 4);
305 
306                 assert(1 == sd_bus_message_at_end(m, false));
307                 sd_bus_message_exit_container(m);
308 
309                 assert(1 == sd_bus_message_at_end(m, false));
310                 sd_bus_message_exit_container(m);
311 
312                 sd_bus_message_read(m, "i", &a);
313                 assert(a == 2);
314             }
315         };
316         verifyCallback = &verify::op;
317 
318         b.call_noreply(m);
319     }
320 
321     // Test tuple.
322     {
323         auto m = newMethodCall__test(b);
324         std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" };
325         m.append(1, a, 2);
326         verifyTypeString = "i(ids)i";
327 
328         struct verify
329         {
330             static void op(sd_bus_message* m)
331             {
332                 int32_t a = 0;
333                 double b = 0;
334                 const char* c = nullptr;
335 
336                 sd_bus_message_read(m, "i", &a);
337                 assert(a == 1);
338 
339                 auto rc = sd_bus_message_enter_container(m,
340                                                          SD_BUS_TYPE_STRUCT,
341                                                          "ids");
342                 assert(0 <= rc);
343 
344                 sd_bus_message_read(m, "ids", &a, &b, &c);
345                 assert(a == 3);
346                 assert(b == 4.1);
347                 assert(0 == strcmp(c, "asdf"));
348 
349                 sd_bus_message_exit_container(m);
350 
351                 sd_bus_message_read(m, "i", &a);
352                 assert(a == 2);
353             }
354         };
355         verifyCallback = &verify::op;
356 
357         b.call_noreply(m);
358     }
359 
360     // Test variant.
361     {
362         auto m = newMethodCall__test(b);
363         sdbusplus::message::variant<int, double> a1{3.1}, a2{4};
364         m.append(1, a1, a2, 2);
365         verifyTypeString = "ivvi";
366 
367         struct verify
368         {
369             static void op(sd_bus_message* m)
370             {
371                 int32_t a = 0;
372                 double b = 0;
373 
374                 sd_bus_message_read(m, "i", &a);
375                 assert(a == 1);
376 
377                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
378                 sd_bus_message_read(m, "d", &b);
379                 assert(b == 3.1);
380                 sd_bus_message_exit_container(m);
381 
382                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
383                 sd_bus_message_read(m, "i", &a);
384                 assert(a == 4);
385                 sd_bus_message_exit_container(m);
386 
387                 sd_bus_message_read(m, "i", &a);
388                 assert(a == 2);
389             }
390         };
391         verifyCallback = &verify::op;
392 
393         b.call_noreply(m);
394     }
395 
396     // Test map-variant.
397     {
398         auto m = newMethodCall__test(b);
399         std::map<std::string, sdbusplus::message::variant<int, double>> a1 =
400                 { { "asdf", 3 }, { "jkl;", 4.1 } };
401         m.append(1, a1, 2);
402         verifyTypeString = "ia{sv}i";
403 
404         struct verify
405         {
406             static void op(sd_bus_message* m)
407             {
408                 int32_t a = 0;
409                 double b = 0;
410                 const char* c = nullptr;
411 
412                 sd_bus_message_read(m, "i", &a);
413                 assert(a == 1);
414 
415                 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
416                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
417                 sd_bus_message_read(m, "s", &c);
418                 assert(0 == strcmp("asdf", c));
419                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
420                 sd_bus_message_read(m, "i", &a);
421                 assert(a == 3);
422                 sd_bus_message_exit_container(m);
423                 sd_bus_message_exit_container(m);
424                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
425                 sd_bus_message_read(m, "s", &c);
426                 assert(0 == strcmp("jkl;", c));
427                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
428                 sd_bus_message_read(m, "d", &b);
429                 assert(b == 4.1);
430                 sd_bus_message_exit_container(m);
431                 sd_bus_message_exit_container(m);
432                 sd_bus_message_exit_container(m);
433 
434                 sd_bus_message_read(m, "i", &a);
435                 assert(a == 2);
436             }
437         };
438         verifyCallback = &verify::op;
439 
440         b.call_noreply(m);
441     }
442 
443     // Shutdown server.
444     {
445         auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);
446         b.call_noreply(m);
447     }
448 }
449 
450 int main()
451 {
452 
453     // Initialize and start server thread.
454     pthread_t t;
455     {
456         auto b = serverInit();
457         pthread_create(&t, NULL, server, b.release());
458     }
459 
460     runTests();
461 
462     // Wait for server thread to exit.
463     pthread_join(t, NULL);
464 
465     return 0;
466 }
467