1 //===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h" 10 #include "QueueChannel.h" 11 #include "gtest/gtest.h" 12 13 #include <queue> 14 15 using namespace llvm; 16 using namespace llvm::orc; 17 using namespace llvm::orc::shared; 18 19 class RPCFoo {}; 20 21 namespace llvm { 22 namespace orc { 23 namespace shared { 24 25 template <> class SerializationTypeName<RPCFoo> { 26 public: 27 static const char *getName() { return "RPCFoo"; } 28 }; 29 30 template <> 31 class SerializationTraits<QueueChannel, RPCFoo, RPCFoo> { 32 public: 33 static Error serialize(QueueChannel&, const RPCFoo&) { 34 return Error::success(); 35 } 36 37 static Error deserialize(QueueChannel&, RPCFoo&) { 38 return Error::success(); 39 } 40 }; 41 42 } // namespace shared 43 } // end namespace orc 44 } // end namespace llvm 45 46 class RPCBar {}; 47 48 class DummyError : public ErrorInfo<DummyError> { 49 public: 50 51 static char ID; 52 53 DummyError(uint32_t Val) : Val(Val) {} 54 55 std::error_code convertToErrorCode() const override { 56 // Use a nonsense error code - we want to verify that errors 57 // transmitted over the network are replaced with 58 // OrcErrorCode::UnknownErrorCodeFromRemote. 59 return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); 60 } 61 62 void log(raw_ostream &OS) const override { 63 OS << "Dummy error " << Val; 64 } 65 66 uint32_t getValue() const { return Val; } 67 68 public: 69 uint32_t Val; 70 }; 71 72 char DummyError::ID = 0; 73 74 template <typename ChannelT> 75 void registerDummyErrorSerialization() { 76 static bool AlreadyRegistered = false; 77 if (!AlreadyRegistered) { 78 SerializationTraits<ChannelT, Error>:: 79 template registerErrorType<DummyError>( 80 "DummyError", 81 [](ChannelT &C, const DummyError &DE) { 82 return serializeSeq(C, DE.getValue()); 83 }, 84 [](ChannelT &C, Error &Err) -> Error { 85 ErrorAsOutParameter EAO(&Err); 86 uint32_t Val; 87 if (auto Err = deserializeSeq(C, Val)) 88 return Err; 89 Err = make_error<DummyError>(Val); 90 return Error::success(); 91 }); 92 AlreadyRegistered = true; 93 } 94 } 95 96 namespace llvm { 97 namespace orc { 98 namespace shared { 99 100 template <> class SerializationTraits<QueueChannel, RPCFoo, RPCBar> { 101 public: 102 static Error serialize(QueueChannel &, const RPCBar &) { 103 return Error::success(); 104 } 105 106 static Error deserialize(QueueChannel &, RPCBar &) { 107 return Error::success(); 108 } 109 }; 110 111 } // end namespace shared 112 } // end namespace orc 113 } // end namespace llvm 114 115 namespace DummyRPCAPI { 116 117 class VoidBool : public RPCFunction<VoidBool, void(bool)> { 118 public: 119 static const char *getName() { return "VoidBool"; } 120 }; 121 122 class IntInt : public RPCFunction<IntInt, int32_t(int32_t)> { 123 public: 124 static const char *getName() { return "IntInt"; } 125 }; 126 127 class VoidString : public RPCFunction<VoidString, void(std::string)> { 128 public: 129 static const char *getName() { return "VoidString"; } 130 }; 131 132 class AllTheTypes 133 : public RPCFunction<AllTheTypes, 134 void(int8_t, uint8_t, int16_t, uint16_t, int32_t, 135 uint32_t, int64_t, uint64_t, bool, std::string, 136 std::vector<int>, std::set<int>, 137 std::map<int, bool>)> { 138 public: 139 static const char *getName() { return "AllTheTypes"; } 140 }; 141 142 class CustomType : public RPCFunction<CustomType, RPCFoo(RPCFoo)> { 143 public: 144 static const char *getName() { return "CustomType"; } 145 }; 146 147 class ErrorFunc : public RPCFunction<ErrorFunc, Error()> { 148 public: 149 static const char *getName() { return "ErrorFunc"; } 150 }; 151 152 class ExpectedFunc : public RPCFunction<ExpectedFunc, Expected<uint32_t>()> { 153 public: 154 static const char *getName() { return "ExpectedFunc"; } 155 }; 156 } 157 158 class DummyRPCEndpoint : public SingleThreadedRPCEndpoint<QueueChannel> { 159 public: 160 DummyRPCEndpoint(QueueChannel &C) 161 : SingleThreadedRPCEndpoint(C, true) {} 162 }; 163 164 165 void freeVoidBool(bool B) { 166 } 167 168 TEST(DummyRPC, TestFreeFunctionHandler) { 169 auto Channels = createPairedQueueChannels(); 170 DummyRPCEndpoint Server(*Channels.first); 171 Server.addHandler<DummyRPCAPI::VoidBool>(freeVoidBool); 172 } 173 174 TEST(DummyRPC, TestCallAsyncVoidBool) { 175 auto Channels = createPairedQueueChannels(); 176 DummyRPCEndpoint Client(*Channels.first); 177 DummyRPCEndpoint Server(*Channels.second); 178 179 std::thread ServerThread([&]() { 180 Server.addHandler<DummyRPCAPI::VoidBool>( 181 [](bool B) { 182 EXPECT_EQ(B, true) 183 << "Server void(bool) received unexpected result"; 184 }); 185 186 { 187 // Poke the server to handle the negotiate call. 188 auto Err = Server.handleOne(); 189 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 190 } 191 192 { 193 // Poke the server to handle the VoidBool call. 194 auto Err = Server.handleOne(); 195 EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; 196 } 197 }); 198 199 { 200 // Make an async call. 201 auto Err = Client.callAsync<DummyRPCAPI::VoidBool>( 202 [](Error Err) { 203 EXPECT_FALSE(!!Err) << "Async void(bool) response handler failed"; 204 return Error::success(); 205 }, true); 206 EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)"; 207 } 208 209 { 210 // Poke the client to process the result of the void(bool) call. 211 auto Err = Client.handleOne(); 212 EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; 213 } 214 215 ServerThread.join(); 216 217 // The client should have made two calls to send: One implicit call to 218 // negotiate the VoidBool function key, and a second to make the VoidBool 219 // call. 220 EXPECT_EQ(Channels.first->SendCalls, 2U) 221 << "Expected one send call to have been made by client"; 222 223 // The server should have made two calls to send: One to send the response to 224 // the negotiate call, and another to send the response to the VoidBool call. 225 EXPECT_EQ(Channels.second->SendCalls, 2U) 226 << "Expected two send calls to have been made by server"; 227 } 228 229 TEST(DummyRPC, TestCallAsyncIntInt) { 230 auto Channels = createPairedQueueChannels(); 231 DummyRPCEndpoint Client(*Channels.first); 232 DummyRPCEndpoint Server(*Channels.second); 233 234 std::thread ServerThread([&]() { 235 Server.addHandler<DummyRPCAPI::IntInt>( 236 [](int X) -> int { 237 EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result"; 238 return 2 * X; 239 }); 240 241 { 242 // Poke the server to handle the negotiate call. 243 auto Err = Server.handleOne(); 244 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 245 } 246 247 { 248 // Poke the server to handle the int(int) call. 249 auto Err = Server.handleOne(); 250 EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)"; 251 } 252 }); 253 254 { 255 auto Err = Client.callAsync<DummyRPCAPI::IntInt>( 256 [](Expected<int> Result) { 257 EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; 258 EXPECT_EQ(*Result, 42) 259 << "Async int(int) response handler received incorrect result"; 260 return Error::success(); 261 }, 21); 262 EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)"; 263 } 264 265 { 266 // Poke the client to process the result. 267 auto Err = Client.handleOne(); 268 EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; 269 } 270 271 ServerThread.join(); 272 } 273 274 TEST(DummyRPC, TestAsyncVoidBoolHandler) { 275 auto Channels = createPairedQueueChannels(); 276 DummyRPCEndpoint Client(*Channels.first); 277 DummyRPCEndpoint Server(*Channels.second); 278 279 std::thread ServerThread([&]() { 280 Server.addAsyncHandler<DummyRPCAPI::VoidBool>( 281 [](std::function<Error(Error)> SendResult, 282 bool B) { 283 EXPECT_EQ(B, true) << "Server void(bool) receieved unexpected result"; 284 cantFail(SendResult(Error::success())); 285 return Error::success(); 286 }); 287 288 { 289 // Poke the server to handle the negotiate call. 290 auto Err = Server.handleOne(); 291 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 292 } 293 294 { 295 // Poke the server to handle the VoidBool call. 296 auto Err = Server.handleOne(); 297 EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; 298 } 299 }); 300 301 { 302 auto Err = Client.callAsync<DummyRPCAPI::VoidBool>( 303 [](Error Result) { 304 EXPECT_FALSE(!!Result) << "Async void(bool) response handler failed"; 305 return Error::success(); 306 }, true); 307 EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)"; 308 } 309 310 { 311 // Poke the client to process the result. 312 auto Err = Client.handleOne(); 313 EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; 314 } 315 316 ServerThread.join(); 317 } 318 319 TEST(DummyRPC, TestAsyncIntIntHandler) { 320 auto Channels = createPairedQueueChannels(); 321 DummyRPCEndpoint Client(*Channels.first); 322 DummyRPCEndpoint Server(*Channels.second); 323 324 std::thread ServerThread([&]() { 325 Server.addAsyncHandler<DummyRPCAPI::IntInt>( 326 [](std::function<Error(Expected<int32_t>)> SendResult, 327 int32_t X) { 328 EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result"; 329 return SendResult(2 * X); 330 }); 331 332 { 333 // Poke the server to handle the negotiate call. 334 auto Err = Server.handleOne(); 335 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 336 } 337 338 { 339 // Poke the server to handle the VoidBool call. 340 auto Err = Server.handleOne(); 341 EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; 342 } 343 }); 344 345 { 346 auto Err = Client.callAsync<DummyRPCAPI::IntInt>( 347 [](Expected<int> Result) { 348 EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; 349 EXPECT_EQ(*Result, 42) 350 << "Async int(int) response handler received incorrect result"; 351 return Error::success(); 352 }, 21); 353 EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)"; 354 } 355 356 { 357 // Poke the client to process the result. 358 auto Err = Client.handleOne(); 359 EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; 360 } 361 362 ServerThread.join(); 363 } 364 365 TEST(DummyRPC, TestAsyncIntIntHandlerMethod) { 366 auto Channels = createPairedQueueChannels(); 367 DummyRPCEndpoint Client(*Channels.first); 368 DummyRPCEndpoint Server(*Channels.second); 369 370 class Dummy { 371 public: 372 Error handler(std::function<Error(Expected<int32_t>)> SendResult, 373 int32_t X) { 374 EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result"; 375 return SendResult(2 * X); 376 } 377 }; 378 379 std::thread ServerThread([&]() { 380 Dummy D; 381 Server.addAsyncHandler<DummyRPCAPI::IntInt>(D, &Dummy::handler); 382 383 { 384 // Poke the server to handle the negotiate call. 385 auto Err = Server.handleOne(); 386 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 387 } 388 389 { 390 // Poke the server to handle the VoidBool call. 391 auto Err = Server.handleOne(); 392 EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; 393 } 394 }); 395 396 { 397 auto Err = Client.callAsync<DummyRPCAPI::IntInt>( 398 [](Expected<int> Result) { 399 EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; 400 EXPECT_EQ(*Result, 42) 401 << "Async int(int) response handler received incorrect result"; 402 return Error::success(); 403 }, 21); 404 EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)"; 405 } 406 407 { 408 // Poke the client to process the result. 409 auto Err = Client.handleOne(); 410 EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; 411 } 412 413 ServerThread.join(); 414 } 415 416 TEST(DummyRPC, TestCallAsyncVoidString) { 417 auto Channels = createPairedQueueChannels(); 418 DummyRPCEndpoint Client(*Channels.first); 419 DummyRPCEndpoint Server(*Channels.second); 420 421 std::thread ServerThread([&]() { 422 Server.addHandler<DummyRPCAPI::VoidString>( 423 [](const std::string &S) { 424 EXPECT_EQ(S, "hello") 425 << "Server void(std::string) received unexpected result"; 426 }); 427 428 // Poke the server to handle the negotiate call. 429 for (int I = 0; I < 4; ++I) { 430 auto Err = Server.handleOne(); 431 EXPECT_FALSE(!!Err) << "Server failed to handle call"; 432 } 433 }); 434 435 { 436 // Make an call using a std::string. 437 auto Err = Client.callB<DummyRPCAPI::VoidString>(std::string("hello")); 438 EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)"; 439 } 440 441 { 442 // Make an call using a std::string. 443 auto Err = Client.callB<DummyRPCAPI::VoidString>(StringRef("hello")); 444 EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)"; 445 } 446 447 { 448 // Make an call using a std::string. 449 auto Err = Client.callB<DummyRPCAPI::VoidString>("hello"); 450 EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(string)"; 451 } 452 453 ServerThread.join(); 454 } 455 456 TEST(DummyRPC, TestSerialization) { 457 auto Channels = createPairedQueueChannels(); 458 DummyRPCEndpoint Client(*Channels.first); 459 DummyRPCEndpoint Server(*Channels.second); 460 461 std::thread ServerThread([&]() { 462 Server.addHandler<DummyRPCAPI::AllTheTypes>([&](int8_t S8, uint8_t U8, 463 int16_t S16, uint16_t U16, 464 int32_t S32, uint32_t U32, 465 int64_t S64, uint64_t U64, 466 bool B, std::string S, 467 std::vector<int> V, 468 std::set<int> S2, 469 std::map<int, bool> M) { 470 EXPECT_EQ(S8, -101) << "int8_t serialization broken"; 471 EXPECT_EQ(U8, 250) << "uint8_t serialization broken"; 472 EXPECT_EQ(S16, -10000) << "int16_t serialization broken"; 473 EXPECT_EQ(U16, 10000) << "uint16_t serialization broken"; 474 EXPECT_EQ(S32, -1000000000) << "int32_t serialization broken"; 475 EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization broken"; 476 EXPECT_EQ(S64, -10000000000) << "int64_t serialization broken"; 477 EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization broken"; 478 EXPECT_EQ(B, true) << "bool serialization broken"; 479 EXPECT_EQ(S, "foo") << "std::string serialization broken"; 480 EXPECT_EQ(V, std::vector<int>({42, 7})) 481 << "std::vector serialization broken"; 482 EXPECT_EQ(S2, std::set<int>({7, 42})) << "std::set serialization broken"; 483 EXPECT_EQ(M, (std::map<int, bool>({{7, false}, {42, true}}))) 484 << "std::map serialization broken"; 485 return Error::success(); 486 }); 487 488 { 489 // Poke the server to handle the negotiate call. 490 auto Err = Server.handleOne(); 491 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 492 } 493 494 { 495 // Poke the server to handle the AllTheTypes call. 496 auto Err = Server.handleOne(); 497 EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; 498 } 499 }); 500 501 { 502 // Make an async call. 503 std::vector<int> V({42, 7}); 504 std::set<int> S({7, 42}); 505 std::map<int, bool> M({{7, false}, {42, true}}); 506 auto Err = Client.callAsync<DummyRPCAPI::AllTheTypes>( 507 [](Error Err) { 508 EXPECT_FALSE(!!Err) << "Async AllTheTypes response handler failed"; 509 return Error::success(); 510 }, 511 static_cast<int8_t>(-101), static_cast<uint8_t>(250), 512 static_cast<int16_t>(-10000), static_cast<uint16_t>(10000), 513 static_cast<int32_t>(-1000000000), static_cast<uint32_t>(1000000000), 514 static_cast<int64_t>(-10000000000), static_cast<uint64_t>(10000000000), 515 true, std::string("foo"), V, S, M); 516 EXPECT_FALSE(!!Err) << "Client.callAsync failed for AllTheTypes"; 517 } 518 519 { 520 // Poke the client to process the result of the AllTheTypes call. 521 auto Err = Client.handleOne(); 522 EXPECT_FALSE(!!Err) << "Client failed to handle response from AllTheTypes"; 523 } 524 525 ServerThread.join(); 526 } 527 528 TEST(DummyRPC, TestCustomType) { 529 auto Channels = createPairedQueueChannels(); 530 DummyRPCEndpoint Client(*Channels.first); 531 DummyRPCEndpoint Server(*Channels.second); 532 533 std::thread ServerThread([&]() { 534 Server.addHandler<DummyRPCAPI::CustomType>( 535 [](RPCFoo F) {}); 536 537 { 538 // Poke the server to handle the negotiate call. 539 auto Err = Server.handleOne(); 540 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 541 } 542 543 { 544 // Poke the server to handle the CustomType call. 545 auto Err = Server.handleOne(); 546 EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)"; 547 } 548 }); 549 550 { 551 // Make an async call. 552 auto Err = Client.callAsync<DummyRPCAPI::CustomType>( 553 [](Expected<RPCFoo> FOrErr) { 554 EXPECT_TRUE(!!FOrErr) 555 << "Async RPCFoo(RPCFoo) response handler failed"; 556 return Error::success(); 557 }, RPCFoo()); 558 EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)"; 559 } 560 561 { 562 // Poke the client to process the result of the RPCFoo() call. 563 auto Err = Client.handleOne(); 564 EXPECT_FALSE(!!Err) 565 << "Client failed to handle response from RPCFoo(RPCFoo)"; 566 } 567 568 ServerThread.join(); 569 } 570 571 TEST(DummyRPC, TestWithAltCustomType) { 572 auto Channels = createPairedQueueChannels(); 573 DummyRPCEndpoint Client(*Channels.first); 574 DummyRPCEndpoint Server(*Channels.second); 575 576 std::thread ServerThread([&]() { 577 Server.addHandler<DummyRPCAPI::CustomType>( 578 [](RPCBar F) {}); 579 580 { 581 // Poke the server to handle the negotiate call. 582 auto Err = Server.handleOne(); 583 EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; 584 } 585 586 { 587 // Poke the server to handle the CustomType call. 588 auto Err = Server.handleOne(); 589 EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)"; 590 } 591 }); 592 593 { 594 // Make an async call. 595 auto Err = Client.callAsync<DummyRPCAPI::CustomType>( 596 [](Expected<RPCBar> FOrErr) { 597 EXPECT_TRUE(!!FOrErr) 598 << "Async RPCFoo(RPCFoo) response handler failed"; 599 return Error::success(); 600 }, RPCBar()); 601 EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)"; 602 } 603 604 { 605 // Poke the client to process the result of the RPCFoo() call. 606 auto Err = Client.handleOne(); 607 EXPECT_FALSE(!!Err) 608 << "Client failed to handle response from RPCFoo(RPCFoo)"; 609 } 610 611 ServerThread.join(); 612 } 613 614 TEST(DummyRPC, ReturnErrorSuccess) { 615 registerDummyErrorSerialization<QueueChannel>(); 616 617 auto Channels = createPairedQueueChannels(); 618 DummyRPCEndpoint Client(*Channels.first); 619 DummyRPCEndpoint Server(*Channels.second); 620 621 std::thread ServerThread([&]() { 622 Server.addHandler<DummyRPCAPI::ErrorFunc>( 623 []() { 624 return Error::success(); 625 }); 626 627 // Handle the negotiate plus one call. 628 for (unsigned I = 0; I != 2; ++I) 629 cantFail(Server.handleOne()); 630 }); 631 632 cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>( 633 [&](Error Err) { 634 EXPECT_FALSE(!!Err) << "Expected success value"; 635 return Error::success(); 636 })); 637 638 cantFail(Client.handleOne()); 639 640 ServerThread.join(); 641 } 642 643 TEST(DummyRPC, ReturnErrorFailure) { 644 registerDummyErrorSerialization<QueueChannel>(); 645 646 auto Channels = createPairedQueueChannels(); 647 DummyRPCEndpoint Client(*Channels.first); 648 DummyRPCEndpoint Server(*Channels.second); 649 650 std::thread ServerThread([&]() { 651 Server.addHandler<DummyRPCAPI::ErrorFunc>( 652 []() { 653 return make_error<DummyError>(42); 654 }); 655 656 // Handle the negotiate plus one call. 657 for (unsigned I = 0; I != 2; ++I) 658 cantFail(Server.handleOne()); 659 }); 660 661 cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>( 662 [&](Error Err) { 663 EXPECT_TRUE(Err.isA<DummyError>()) 664 << "Incorrect error type"; 665 return handleErrors( 666 std::move(Err), 667 [](const DummyError &DE) { 668 EXPECT_EQ(DE.getValue(), 42ULL) 669 << "Incorrect DummyError serialization"; 670 }); 671 })); 672 673 cantFail(Client.handleOne()); 674 675 ServerThread.join(); 676 } 677 678 TEST(DummyRPC, ReturnExpectedSuccess) { 679 registerDummyErrorSerialization<QueueChannel>(); 680 681 auto Channels = createPairedQueueChannels(); 682 DummyRPCEndpoint Client(*Channels.first); 683 DummyRPCEndpoint Server(*Channels.second); 684 685 std::thread ServerThread([&]() { 686 Server.addHandler<DummyRPCAPI::ExpectedFunc>( 687 []() -> uint32_t { 688 return 42; 689 }); 690 691 // Handle the negotiate plus one call. 692 for (unsigned I = 0; I != 2; ++I) 693 cantFail(Server.handleOne()); 694 }); 695 696 cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>( 697 [&](Expected<uint32_t> ValOrErr) { 698 EXPECT_TRUE(!!ValOrErr) 699 << "Expected success value"; 700 EXPECT_EQ(*ValOrErr, 42ULL) 701 << "Incorrect Expected<uint32_t> deserialization"; 702 return Error::success(); 703 })); 704 705 cantFail(Client.handleOne()); 706 707 ServerThread.join(); 708 } 709 710 TEST(DummyRPC, ReturnExpectedFailure) { 711 registerDummyErrorSerialization<QueueChannel>(); 712 713 auto Channels = createPairedQueueChannels(); 714 DummyRPCEndpoint Client(*Channels.first); 715 DummyRPCEndpoint Server(*Channels.second); 716 717 std::thread ServerThread([&]() { 718 Server.addHandler<DummyRPCAPI::ExpectedFunc>( 719 []() -> Expected<uint32_t> { 720 return make_error<DummyError>(7); 721 }); 722 723 // Handle the negotiate plus one call. 724 for (unsigned I = 0; I != 2; ++I) 725 cantFail(Server.handleOne()); 726 }); 727 728 cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>( 729 [&](Expected<uint32_t> ValOrErr) { 730 EXPECT_FALSE(!!ValOrErr) 731 << "Expected failure value"; 732 auto Err = ValOrErr.takeError(); 733 EXPECT_TRUE(Err.isA<DummyError>()) 734 << "Incorrect error type"; 735 return handleErrors( 736 std::move(Err), 737 [](const DummyError &DE) { 738 EXPECT_EQ(DE.getValue(), 7ULL) 739 << "Incorrect DummyError serialization"; 740 }); 741 })); 742 743 cantFail(Client.handleOne()); 744 745 ServerThread.join(); 746 } 747 748 TEST(DummyRPC, TestParallelCallGroup) { 749 auto Channels = createPairedQueueChannels(); 750 DummyRPCEndpoint Client(*Channels.first); 751 DummyRPCEndpoint Server(*Channels.second); 752 753 std::thread ServerThread([&]() { 754 Server.addHandler<DummyRPCAPI::IntInt>( 755 [](int X) -> int { 756 return 2 * X; 757 }); 758 759 // Handle the negotiate, plus three calls. 760 for (unsigned I = 0; I != 4; ++I) { 761 auto Err = Server.handleOne(); 762 EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)"; 763 } 764 }); 765 766 { 767 int A, B, C; 768 ParallelCallGroup PCG; 769 770 { 771 auto Err = PCG.call( 772 rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client), 773 [&A](Expected<int> Result) { 774 EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; 775 A = *Result; 776 return Error::success(); 777 }, 1); 778 EXPECT_FALSE(!!Err) << "First parallel call failed for int(int)"; 779 } 780 781 { 782 auto Err = PCG.call( 783 rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client), 784 [&B](Expected<int> Result) { 785 EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; 786 B = *Result; 787 return Error::success(); 788 }, 2); 789 EXPECT_FALSE(!!Err) << "Second parallel call failed for int(int)"; 790 } 791 792 { 793 auto Err = PCG.call( 794 rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client), 795 [&C](Expected<int> Result) { 796 EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; 797 C = *Result; 798 return Error::success(); 799 }, 3); 800 EXPECT_FALSE(!!Err) << "Third parallel call failed for int(int)"; 801 } 802 803 // Handle the three int(int) results. 804 for (unsigned I = 0; I != 3; ++I) { 805 auto Err = Client.handleOne(); 806 EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; 807 } 808 809 PCG.wait(); 810 811 EXPECT_EQ(A, 2) << "First parallel call returned bogus result"; 812 EXPECT_EQ(B, 4) << "Second parallel call returned bogus result"; 813 EXPECT_EQ(C, 6) << "Third parallel call returned bogus result"; 814 } 815 816 ServerThread.join(); 817 } 818 819 TEST(DummyRPC, TestAPICalls) { 820 821 using DummyCalls1 = APICalls<DummyRPCAPI::VoidBool, DummyRPCAPI::IntInt>; 822 using DummyCalls2 = APICalls<DummyRPCAPI::AllTheTypes>; 823 using DummyCalls3 = APICalls<DummyCalls1, DummyRPCAPI::CustomType>; 824 using DummyCallsAll = APICalls<DummyCalls1, DummyCalls2, DummyRPCAPI::CustomType>; 825 826 static_assert(DummyCalls1::Contains<DummyRPCAPI::VoidBool>::value, 827 "Contains<Func> template should return true here"); 828 static_assert(!DummyCalls1::Contains<DummyRPCAPI::CustomType>::value, 829 "Contains<Func> template should return false here"); 830 831 auto Channels = createPairedQueueChannels(); 832 DummyRPCEndpoint Client(*Channels.first); 833 DummyRPCEndpoint Server(*Channels.second); 834 835 std::thread ServerThread( 836 [&]() { 837 Server.addHandler<DummyRPCAPI::VoidBool>([](bool b) { }); 838 Server.addHandler<DummyRPCAPI::IntInt>([](int x) { return x; }); 839 Server.addHandler<DummyRPCAPI::CustomType>([](RPCFoo F) {}); 840 841 for (unsigned I = 0; I < 4; ++I) { 842 auto Err = Server.handleOne(); 843 (void)!!Err; 844 } 845 }); 846 847 { 848 auto Err = DummyCalls1::negotiate(Client); 849 EXPECT_FALSE(!!Err) << "DummyCalls1::negotiate failed"; 850 } 851 852 { 853 auto Err = DummyCalls3::negotiate(Client); 854 EXPECT_FALSE(!!Err) << "DummyCalls3::negotiate failed"; 855 } 856 857 { 858 auto Err = DummyCallsAll::negotiate(Client); 859 EXPECT_TRUE(Err.isA<CouldNotNegotiate>()) 860 << "Expected CouldNotNegotiate error for attempted negotiate of " 861 "unsupported function"; 862 consumeError(std::move(Err)); 863 } 864 865 ServerThread.join(); 866 } 867 868 TEST(DummyRPC, TestRemoveHandler) { 869 auto Channels = createPairedQueueChannels(); 870 DummyRPCEndpoint Server(*Channels.second); 871 872 Server.addHandler<DummyRPCAPI::VoidBool>( 873 [](bool B) { 874 llvm_unreachable("Server void(bool) received unexpected result"); 875 }); 876 877 Server.removeHandler<DummyRPCAPI::VoidBool>(); 878 } 879 880 TEST(DummyRPC, TestClearHandlers) { 881 auto Channels = createPairedQueueChannels(); 882 DummyRPCEndpoint Server(*Channels.second); 883 884 Server.addHandler<DummyRPCAPI::VoidBool>( 885 [](bool B) { 886 llvm_unreachable("Server void(bool) received unexpected result"); 887 }); 888 889 Server.clearHandlers(); 890 } 891