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