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