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