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