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 (*)(sd_bus_message*); 24 verifyCallback_t verifyCallback = nullptr; 25 26 static constexpr auto SERVICE = "sdbusplus.test.message.append"; 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().release(); 50 51 if (m == nullptr) 52 { 53 bus.wait(); 54 continue; 55 } 56 57 if (sd_bus_message_is_method_call(m, INTERFACE, TEST_METHOD)) 58 { 59 // Verify the message type matches what the test expects. 60 TEST_ASSERT(verifyTypeString == 61 sd_bus_message_get_signature(m, true)); 62 if (verifyCallback) 63 { 64 verifyCallback(m); 65 verifyCallback = nullptr; 66 } 67 else 68 { 69 std::cout << "Warning: No verification for " << verifyTypeString 70 << std::endl; 71 } 72 // Reply to client. 73 sd_bus_reply_method_return(m, nullptr); 74 } 75 else if (sd_bus_message_is_method_call(m, INTERFACE, QUIT_METHOD)) 76 { 77 // Reply and exit. 78 sd_bus_reply_method_return(m, nullptr); 79 sd_bus_message_unref(m); 80 break; 81 } 82 83 sd_bus_message_unref(m); 84 } 85 86 return nullptr; 87 } 88 89 auto newMethodCall__test(sdbusplus::bus::bus& b) 90 { 91 // Allocate a method-call message for INTERFACE,TEST_METHOD. 92 return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD); 93 } 94 95 void runTests() 96 { 97 using namespace std::literals; 98 99 auto b = sdbusplus::bus::new_default(); 100 101 // Test r-value int. 102 { 103 auto m = newMethodCall__test(b); 104 m.append(1); 105 verifyTypeString = "i"; 106 107 struct verify 108 { 109 static void op(sd_bus_message* m) 110 { 111 int32_t i = 0; 112 sd_bus_message_read_basic(m, 'i', &i); 113 TEST_ASSERT(i == 1); 114 } 115 }; 116 verifyCallback = &verify::op; 117 118 b.call_noreply(m); 119 } 120 // Test l-value int. 121 { 122 auto m = newMethodCall__test(b); 123 int a = 1; 124 m.append(a, a); 125 verifyTypeString = "ii"; 126 127 struct verify 128 { 129 static void op(sd_bus_message* m) 130 { 131 int32_t a = 0, b = 0; 132 sd_bus_message_read(m, "ii", &a, &b); 133 TEST_ASSERT(a == 1); 134 TEST_ASSERT(b == 1); 135 } 136 }; 137 verifyCallback = &verify::op; 138 139 b.call_noreply(m); 140 } 141 142 // Test multiple ints. 143 { 144 auto m = newMethodCall__test(b); 145 m.append(1, 2, 3, 4, 5); 146 verifyTypeString = "iiiii"; 147 148 struct verify 149 { 150 static void op(sd_bus_message* m) 151 { 152 int32_t a = 0, b = 0, c = 0, d = 0, e = 0; 153 sd_bus_message_read(m, "iiiii", &a, &b, &c, &d, &e); 154 TEST_ASSERT(a == 1); 155 TEST_ASSERT(b == 2); 156 TEST_ASSERT(c == 3); 157 TEST_ASSERT(d == 4); 158 TEST_ASSERT(e == 5); 159 } 160 }; 161 verifyCallback = &verify::op; 162 163 b.call_noreply(m); 164 } 165 166 // Test double and bool. 167 { 168 auto m = newMethodCall__test(b); 169 bool t = true; 170 bool f = false; 171 bool f2 = false; 172 m.append(t, true, f, std::move(f2), false, 1.1); 173 verifyTypeString = "bbbbbd"; 174 175 struct verify 176 { 177 static void op(sd_bus_message* m) 178 { 179 bool t1, t2, f1, f2, f3; 180 double d; 181 sd_bus_message_read(m, "bbbbbd", &t1, &t2, &f1, &f2, &f3, &d); 182 TEST_ASSERT(t1); 183 TEST_ASSERT(t2); 184 TEST_ASSERT(!f1); 185 TEST_ASSERT(!f2); 186 TEST_ASSERT(!f3); 187 TEST_ASSERT(d == 1.1); 188 } 189 }; 190 verifyCallback = &verify::op; 191 192 b.call_noreply(m); 193 } 194 195 // Test r-value string. 196 { 197 auto m = newMethodCall__test(b); 198 m.append("asdf"s); 199 verifyTypeString = "s"; 200 201 struct verify 202 { 203 static void op(sd_bus_message* m) 204 { 205 const char* s = nullptr; 206 sd_bus_message_read_basic(m, 's', &s); 207 TEST_ASSERT(0 == strcmp("asdf", s)); 208 } 209 }; 210 verifyCallback = &verify::op; 211 212 b.call_noreply(m); 213 } 214 215 // Test const string owned by const struct. openbmc/openbmc#1025 216 { 217 struct 218 { 219 const char* foo; 220 221 void insert(sdbusplus::message::message& m) 222 { 223 m.append(foo); 224 } 225 } s; 226 227 auto m = newMethodCall__test(b); 228 s.foo = "1234"; 229 s.insert(m); 230 231 verifyTypeString = "s"; 232 233 struct verify 234 { 235 static void op(sd_bus_message* m) 236 { 237 const char* s = nullptr; 238 sd_bus_message_read_basic(m, 's', &s); 239 TEST_ASSERT(0 == strcmp("1234", s)); 240 } 241 }; 242 verifyCallback = &verify::op; 243 244 b.call_noreply(m); 245 } 246 247 // Test multiple strings, various forms. 248 { 249 auto m = newMethodCall__test(b); 250 auto str = "jkl;"s; 251 auto str2 = "JKL:"s; 252 const char* str3 = "1234"; 253 const char* const str4 = "5678"; 254 const auto str5 = "!@#$"; 255 m.append(1, "asdf", "ASDF"s, str, std::move(str2), str3, str4, str5, 5); 256 verifyTypeString = "isssssssi"; 257 258 struct verify 259 { 260 static void op(sd_bus_message* m) 261 { 262 int32_t a = 0, b = 0; 263 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr, 264 *s3 = nullptr, *s4 = nullptr, *s5 = nullptr, 265 *s6 = nullptr; 266 sd_bus_message_read(m, "isssssssi", &a, &s0, &s1, &s2, &s3, &s4, 267 &s5, &s6, &b); 268 TEST_ASSERT(a == 1); 269 TEST_ASSERT(b == 5); 270 TEST_ASSERT(0 == strcmp("asdf", s0)); 271 TEST_ASSERT(0 == strcmp("ASDF", s1)); 272 TEST_ASSERT(0 == strcmp("jkl;", s2)); 273 TEST_ASSERT(0 == strcmp("JKL:", s3)); 274 TEST_ASSERT(0 == strcmp("1234", s4)); 275 TEST_ASSERT(0 == strcmp("5678", s5)); 276 TEST_ASSERT(0 == strcmp("!@#$", s6)); 277 TEST_ASSERT(b == 5); 278 } 279 }; 280 verifyCallback = &verify::op; 281 282 b.call_noreply(m); 283 } 284 285 // Test object_path and signature. 286 { 287 auto m = newMethodCall__test(b); 288 auto o = sdbusplus::message::object_path("/asdf"); 289 auto s = sdbusplus::message::signature("iii"); 290 m.append(1, o, s, 4); 291 verifyTypeString = "iogi"; 292 293 struct verify 294 { 295 static void op(sd_bus_message* m) 296 { 297 int32_t a = 0, b = 0; 298 const char *s0 = nullptr, *s1 = nullptr; 299 sd_bus_message_read(m, "iogi", &a, &s0, &s1, &b); 300 TEST_ASSERT(a == 1); 301 TEST_ASSERT(b == 4); 302 TEST_ASSERT(0 == strcmp("/asdf", s0)); 303 TEST_ASSERT(0 == strcmp("iii", s1)); 304 } 305 }; 306 verifyCallback = &verify::op; 307 308 b.call_noreply(m); 309 } 310 311 // Test vector. 312 { 313 auto m = newMethodCall__test(b); 314 std::vector<std::string> s{"1", "2", "3"}; 315 m.append(1, s, 2); 316 verifyTypeString = "iasi"; 317 318 struct verify 319 { 320 static void op(sd_bus_message* m) 321 { 322 int32_t a = 0; 323 sd_bus_message_read(m, "i", &a); 324 TEST_ASSERT(a == 1); 325 326 auto rc = 327 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s"); 328 TEST_ASSERT(0 <= rc); 329 330 const char* s = nullptr; 331 sd_bus_message_read_basic(m, 's', &s); 332 TEST_ASSERT(0 == strcmp("1", s)); 333 sd_bus_message_read_basic(m, 's', &s); 334 TEST_ASSERT(0 == strcmp("2", s)); 335 sd_bus_message_read_basic(m, 's', &s); 336 TEST_ASSERT(0 == strcmp("3", s)); 337 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 338 339 sd_bus_message_exit_container(m); 340 341 sd_bus_message_read(m, "i", &a); 342 TEST_ASSERT(a == 2); 343 } 344 }; 345 verifyCallback = &verify::op; 346 347 b.call_noreply(m); 348 } 349 350 // Test map. 351 { 352 auto m = newMethodCall__test(b); 353 std::map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}}; 354 m.append(1, s, 2); 355 verifyTypeString = "ia{si}i"; 356 357 struct verify 358 { 359 static void op(sd_bus_message* m) 360 { 361 int32_t a = 0; 362 sd_bus_message_read(m, "i", &a); 363 TEST_ASSERT(a == 1); 364 365 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, 366 "{si}"); 367 TEST_ASSERT(0 <= rc); 368 369 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 370 "si"); 371 TEST_ASSERT(0 <= rc); 372 373 const char* s = nullptr; 374 sd_bus_message_read_basic(m, 's', &s); 375 TEST_ASSERT(0 == strcmp("asdf", s)); 376 sd_bus_message_read_basic(m, 'i', &a); 377 TEST_ASSERT(a == 3); 378 379 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 380 sd_bus_message_exit_container(m); 381 382 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 383 "si"); 384 TEST_ASSERT(0 <= rc); 385 386 sd_bus_message_read_basic(m, 's', &s); 387 TEST_ASSERT(0 == strcmp("jkl;", s)); 388 sd_bus_message_read_basic(m, 'i', &a); 389 TEST_ASSERT(a == 4); 390 391 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 392 sd_bus_message_exit_container(m); 393 394 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 395 sd_bus_message_exit_container(m); 396 397 sd_bus_message_read(m, "i", &a); 398 TEST_ASSERT(a == 2); 399 } 400 }; 401 verifyCallback = &verify::op; 402 403 b.call_noreply(m); 404 } 405 406 // Test unordered_map. 407 { 408 auto m = newMethodCall__test(b); 409 std::unordered_map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}}; 410 m.append(1, s, 2); 411 verifyTypeString = "ia{si}i"; 412 413 struct verify 414 { 415 static void op(sd_bus_message* m) 416 { 417 int32_t a = 0; 418 sd_bus_message_read(m, "i", &a); 419 TEST_ASSERT(a == 1); 420 421 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, 422 "{si}"); 423 TEST_ASSERT(0 <= rc); 424 425 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 426 "si"); 427 TEST_ASSERT(0 <= rc); 428 429 const char* s = nullptr; 430 sd_bus_message_read_basic(m, 's', &s); 431 sd_bus_message_read_basic(m, 'i', &a); 432 TEST_ASSERT((0 == strcmp("asdf", s) && a == 3) || 433 (a = 4 && 0 == strcmp("jkl;", s))); 434 435 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 436 sd_bus_message_exit_container(m); 437 438 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 439 "si"); 440 TEST_ASSERT(0 <= rc); 441 442 sd_bus_message_read_basic(m, 's', &s); 443 sd_bus_message_read_basic(m, 'i', &a); 444 TEST_ASSERT((0 == strcmp("asdf", s) && a == 3) || 445 (a = 4 && 0 == strcmp("jkl;", s))); 446 447 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 448 sd_bus_message_exit_container(m); 449 450 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 451 sd_bus_message_exit_container(m); 452 453 sd_bus_message_read(m, "i", &a); 454 TEST_ASSERT(a == 2); 455 } 456 }; 457 verifyCallback = &verify::op; 458 459 b.call_noreply(m); 460 } 461 462 // Test set. 463 { 464 auto m = newMethodCall__test(b); 465 std::set<std::string> s = {{"asdf"}, {"jkl;"}}; 466 m.append(1, s, 2); 467 verifyTypeString = "iasi"; 468 469 struct verify 470 { 471 static void op(sd_bus_message* m) 472 { 473 int32_t a = 0; 474 sd_bus_message_read(m, "i", &a); 475 TEST_ASSERT(a == 1); 476 477 auto rc = 478 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s"); 479 TEST_ASSERT(0 <= rc); 480 481 const char* s = nullptr; 482 sd_bus_message_read_basic(m, 's', &s); 483 TEST_ASSERT(0 == strcmp("asdf", s)); 484 485 sd_bus_message_read_basic(m, 's', &s); 486 TEST_ASSERT(0 == strcmp("jkl;", s)); 487 488 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 489 sd_bus_message_exit_container(m); 490 491 sd_bus_message_read(m, "i", &a); 492 TEST_ASSERT(a == 2); 493 } 494 }; 495 verifyCallback = &verify::op; 496 497 b.call_noreply(m); 498 } 499 500 // Test array. 501 { 502 auto m = newMethodCall__test(b); 503 std::array<std::string, 3> s{"1", "2", "3"}; 504 m.append(1, s, 2); 505 verifyTypeString = "iasi"; 506 507 struct verify 508 { 509 static void op(sd_bus_message* m) 510 { 511 int32_t a = 0; 512 sd_bus_message_read(m, "i", &a); 513 TEST_ASSERT(a == 1); 514 515 auto rc = 516 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s"); 517 TEST_ASSERT(0 <= rc); 518 519 const char* s = nullptr; 520 sd_bus_message_read_basic(m, 's', &s); 521 TEST_ASSERT(0 == strcmp("1", s)); 522 sd_bus_message_read_basic(m, 's', &s); 523 TEST_ASSERT(0 == strcmp("2", s)); 524 sd_bus_message_read_basic(m, 's', &s); 525 TEST_ASSERT(0 == strcmp("3", s)); 526 TEST_ASSERT(1 == sd_bus_message_at_end(m, false)); 527 528 sd_bus_message_exit_container(m); 529 530 sd_bus_message_read(m, "i", &a); 531 TEST_ASSERT(a == 2); 532 } 533 }; 534 verifyCallback = &verify::op; 535 536 b.call_noreply(m); 537 } 538 539 // Test tuple. 540 { 541 auto m = newMethodCall__test(b); 542 std::tuple<int, double, std::string> a{3, 4.1, "asdf"}; 543 m.append(1, a, 2); 544 verifyTypeString = "i(ids)i"; 545 546 struct verify 547 { 548 static void op(sd_bus_message* m) 549 { 550 int32_t a = 0; 551 double b = 0; 552 const char* c = nullptr; 553 554 sd_bus_message_read(m, "i", &a); 555 TEST_ASSERT(a == 1); 556 557 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, 558 "ids"); 559 TEST_ASSERT(0 <= rc); 560 561 sd_bus_message_read(m, "ids", &a, &b, &c); 562 TEST_ASSERT(a == 3); 563 TEST_ASSERT(b == 4.1); 564 TEST_ASSERT(0 == strcmp(c, "asdf")); 565 566 sd_bus_message_exit_container(m); 567 568 sd_bus_message_read(m, "i", &a); 569 TEST_ASSERT(a == 2); 570 } 571 }; 572 verifyCallback = &verify::op; 573 574 b.call_noreply(m); 575 } 576 577 // Test variant. 578 { 579 auto m = newMethodCall__test(b); 580 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 581 m.append(1, a1, a2, 2); 582 verifyTypeString = "ivvi"; 583 584 struct verify 585 { 586 static void op(sd_bus_message* m) 587 { 588 int32_t a = 0; 589 double b = 0; 590 591 sd_bus_message_read(m, "i", &a); 592 TEST_ASSERT(a == 1); 593 594 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 595 sd_bus_message_read(m, "d", &b); 596 TEST_ASSERT(b == 3.1); 597 sd_bus_message_exit_container(m); 598 599 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 600 sd_bus_message_read(m, "i", &a); 601 TEST_ASSERT(a == 4); 602 sd_bus_message_exit_container(m); 603 604 sd_bus_message_read(m, "i", &a); 605 TEST_ASSERT(a == 2); 606 } 607 }; 608 verifyCallback = &verify::op; 609 610 b.call_noreply(m); 611 } 612 613 // Test map-variant. 614 { 615 auto m = newMethodCall__test(b); 616 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = { 617 {"asdf", 3}, {"jkl;", 4.1}}; 618 m.append(1, a1, 2); 619 verifyTypeString = "ia{sv}i"; 620 621 struct verify 622 { 623 static void op(sd_bus_message* m) 624 { 625 int32_t a = 0; 626 double b = 0; 627 const char* c = nullptr; 628 629 sd_bus_message_read(m, "i", &a); 630 TEST_ASSERT(a == 1); 631 632 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); 633 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 634 sd_bus_message_read(m, "s", &c); 635 TEST_ASSERT(0 == strcmp("asdf", c)); 636 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 637 sd_bus_message_read(m, "i", &a); 638 TEST_ASSERT(a == 3); 639 sd_bus_message_exit_container(m); 640 sd_bus_message_exit_container(m); 641 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 642 sd_bus_message_read(m, "s", &c); 643 TEST_ASSERT(0 == strcmp("jkl;", c)); 644 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 645 sd_bus_message_read(m, "d", &b); 646 TEST_ASSERT(b == 4.1); 647 sd_bus_message_exit_container(m); 648 sd_bus_message_exit_container(m); 649 sd_bus_message_exit_container(m); 650 651 sd_bus_message_read(m, "i", &a); 652 TEST_ASSERT(a == 2); 653 } 654 }; 655 verifyCallback = &verify::op; 656 657 b.call_noreply(m); 658 } 659 660 // Shutdown server. 661 { 662 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 663 b.call_noreply(m); 664 } 665 } 666 667 int main() 668 { 669 670 // Initialize and start server thread. 671 pthread_t t; 672 { 673 auto b = serverInit(); 674 pthread_create(&t, NULL, server, b.release()); 675 } 676 677 runTests(); 678 679 // Wait for server thread to exit. 680 pthread_join(t, NULL); 681 682 return 0; 683 } 684