xref: /openbmc/sdbusplus/test/message/append.cpp (revision 24fb2968)
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         m.append(t, true, false, 1.1);
152         verifyTypeString = "bbbd";
153 
154         struct verify
155         {
156             static void op(sd_bus_message* m)
157             {
158                 bool t1, t2, f1;
159                 double d;
160                 sd_bus_message_read(m, "bbbd", &t1, &t2, &f1, &d);
161                 assert(t1);
162                 assert(t2);
163                 assert(!f1);
164                 assert(d == 1.1);
165             }
166         };
167         verifyCallback = &verify::op;
168 
169         b.call_noreply(m);
170     }
171 
172     // Test r-value string.
173     {
174         auto m = newMethodCall__test(b);
175         m.append("asdf"s);
176         verifyTypeString = "s";
177 
178         struct verify
179         {
180             static void op(sd_bus_message* m)
181             {
182                 const char* s = nullptr;
183                 sd_bus_message_read_basic(m, 's', &s);
184                 assert(0 == strcmp("asdf", s));
185             }
186         };
187         verifyCallback = &verify::op;
188 
189         b.call_noreply(m);
190     }
191 
192     // Test multiple strings, various forms.
193     {
194         auto m = newMethodCall__test(b);
195         auto str = "jkl;"s;
196         auto str2 = "JKL:"s;
197         m.append(1, "asdf", "ASDF"s, str,
198                  std::move(str2), 5);
199         verifyTypeString = "issssi";
200 
201         struct verify
202         {
203             static void op(sd_bus_message* m)
204             {
205                 int32_t a = 0, b = 0;
206                 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr,
207                            *s3 = nullptr;
208                 sd_bus_message_read(m, "issssi", &a, &s0, &s1, &s2, &s3, &b);
209                 assert(a == 1);
210                 assert(b == 5);
211                 assert(0 == strcmp("asdf", s0));
212                 assert(0 == strcmp("ASDF", s1));
213                 assert(0 == strcmp("jkl;", s2));
214                 assert(0 == strcmp("JKL:", s3));
215             }
216         };
217         verifyCallback = &verify::op;
218 
219         b.call_noreply(m);
220     }
221 
222     // Test vector.
223     {
224         auto m = newMethodCall__test(b);
225         std::vector<std::string> s{ "1", "2", "3"};
226         m.append(1, s, 2);
227         verifyTypeString = "iasi";
228 
229         struct verify
230         {
231             static void op(sd_bus_message* m)
232             {
233                 int32_t a = 0;
234                 sd_bus_message_read(m, "i", &a);
235                 assert(a == 1);
236 
237                 auto rc = sd_bus_message_enter_container(m,
238                                                          SD_BUS_TYPE_ARRAY,
239                                                          "s");
240                 assert(0 <= rc);
241 
242                 const char* s = nullptr;
243                 sd_bus_message_read_basic(m, 's', &s);
244                 assert(0 == strcmp("1", s));
245                 sd_bus_message_read_basic(m, 's', &s);
246                 assert(0 == strcmp("2", s));
247                 sd_bus_message_read_basic(m, 's', &s);
248                 assert(0 == strcmp("3", s));
249                 assert(1 == sd_bus_message_at_end(m, false));
250 
251                 sd_bus_message_exit_container(m);
252 
253                 sd_bus_message_read(m, "i", &a);
254                 assert(a == 2);
255 
256             }
257         };
258         verifyCallback = &verify::op;
259 
260 
261         b.call_noreply(m);
262     }
263 
264     // Test map.
265     {
266         auto m = newMethodCall__test(b);
267         std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } };
268         m.append(1, s, 2);
269         verifyTypeString = "ia{si}i";
270 
271         struct verify
272         {
273             static void op(sd_bus_message* m)
274             {
275                 int32_t a = 0;
276                 sd_bus_message_read(m, "i", &a);
277                 assert(a == 1);
278 
279                 auto rc = sd_bus_message_enter_container(m,
280                                                          SD_BUS_TYPE_ARRAY,
281                                                          "{si}");
282                 assert(0 <= rc);
283 
284                 rc = sd_bus_message_enter_container(m,
285                                                     SD_BUS_TYPE_DICT_ENTRY,
286                                                     "si");
287                 assert(0 <= rc);
288 
289                 const char* s = nullptr;
290                 sd_bus_message_read_basic(m, 's', &s);
291                 assert(0 == strcmp("asdf", s));
292                 sd_bus_message_read_basic(m, 'i', &a);
293                 assert(a == 3);
294 
295                 assert(1 == sd_bus_message_at_end(m, false));
296                 sd_bus_message_exit_container(m);
297 
298                 rc = sd_bus_message_enter_container(m,
299                                                     SD_BUS_TYPE_DICT_ENTRY,
300                                                     "si");
301                 assert(0 <= rc);
302 
303                 sd_bus_message_read_basic(m, 's', &s);
304                 assert(0 == strcmp("jkl;", s));
305                 sd_bus_message_read_basic(m, 'i', &a);
306                 assert(a == 4);
307 
308                 assert(1 == sd_bus_message_at_end(m, false));
309                 sd_bus_message_exit_container(m);
310 
311                 assert(1 == sd_bus_message_at_end(m, false));
312                 sd_bus_message_exit_container(m);
313 
314                 sd_bus_message_read(m, "i", &a);
315                 assert(a == 2);
316             }
317         };
318         verifyCallback = &verify::op;
319 
320         b.call_noreply(m);
321     }
322 
323     // Test tuple.
324     {
325         auto m = newMethodCall__test(b);
326         std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" };
327         m.append(1, a, 2);
328         verifyTypeString = "i(ids)i";
329 
330         struct verify
331         {
332             static void op(sd_bus_message* m)
333             {
334                 int32_t a = 0;
335                 double b = 0;
336                 const char* c = nullptr;
337 
338                 sd_bus_message_read(m, "i", &a);
339                 assert(a == 1);
340 
341                 auto rc = sd_bus_message_enter_container(m,
342                                                          SD_BUS_TYPE_STRUCT,
343                                                          "ids");
344                 assert(0 <= rc);
345 
346                 sd_bus_message_read(m, "ids", &a, &b, &c);
347                 assert(a == 3);
348                 assert(b == 4.1);
349                 assert(0 == strcmp(c, "asdf"));
350 
351                 sd_bus_message_exit_container(m);
352 
353                 sd_bus_message_read(m, "i", &a);
354                 assert(a == 2);
355             }
356         };
357         verifyCallback = &verify::op;
358 
359         b.call_noreply(m);
360     }
361 
362     // Test variant.
363     {
364         auto m = newMethodCall__test(b);
365         sdbusplus::message::variant<int, double> a1{3.1}, a2{4};
366         m.append(1, a1, a2, 2);
367         verifyTypeString = "ivvi";
368 
369         struct verify
370         {
371             static void op(sd_bus_message* m)
372             {
373                 int32_t a = 0;
374                 double b = 0;
375 
376                 sd_bus_message_read(m, "i", &a);
377                 assert(a == 1);
378 
379                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
380                 sd_bus_message_read(m, "d", &b);
381                 assert(b == 3.1);
382                 sd_bus_message_exit_container(m);
383 
384                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
385                 sd_bus_message_read(m, "i", &a);
386                 assert(a == 4);
387                 sd_bus_message_exit_container(m);
388 
389                 sd_bus_message_read(m, "i", &a);
390                 assert(a == 2);
391             }
392         };
393         verifyCallback = &verify::op;
394 
395         b.call_noreply(m);
396     }
397 
398     // Test map-variant.
399     {
400         auto m = newMethodCall__test(b);
401         std::map<std::string, sdbusplus::message::variant<int, double>> a1 =
402                 { { "asdf", 3 }, { "jkl;", 4.1 } };
403         m.append(1, a1, 2);
404         verifyTypeString = "ia{sv}i";
405 
406         struct verify
407         {
408             static void op(sd_bus_message* m)
409             {
410                 int32_t a = 0;
411                 double b = 0;
412                 const char* c = nullptr;
413 
414                 sd_bus_message_read(m, "i", &a);
415                 assert(a == 1);
416 
417                 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
418                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
419                 sd_bus_message_read(m, "s", &c);
420                 assert(0 == strcmp("asdf", c));
421                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i");
422                 sd_bus_message_read(m, "i", &a);
423                 assert(a == 3);
424                 sd_bus_message_exit_container(m);
425                 sd_bus_message_exit_container(m);
426                 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
427                 sd_bus_message_read(m, "s", &c);
428                 assert(0 == strcmp("jkl;", c));
429                 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d");
430                 sd_bus_message_read(m, "d", &b);
431                 assert(b == 4.1);
432                 sd_bus_message_exit_container(m);
433                 sd_bus_message_exit_container(m);
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     // Shutdown server.
446     {
447         auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);
448         b.call_noreply(m);
449     }
450 }
451 
452 int main()
453 {
454 
455     // Initialize and start server thread.
456     pthread_t t;
457     {
458         auto b = serverInit();
459         pthread_create(&t, NULL, server, b.release());
460     }
461 
462     runTests();
463 
464     // Wait for server thread to exit.
465     pthread_join(t, NULL);
466 
467     return 0;
468 }
469