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