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:
getName()27 static const char *getName() { return "RPCFoo"; }
28 };
29
30 template <>
31 class SerializationTraits<QueueChannel, RPCFoo, RPCFoo> {
32 public:
serialize(QueueChannel &,const RPCFoo &)33 static Error serialize(QueueChannel&, const RPCFoo&) {
34 return Error::success();
35 }
36
deserialize(QueueChannel &,RPCFoo &)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
DummyError(uint32_t Val)53 DummyError(uint32_t Val) : Val(Val) {}
54
convertToErrorCode() const55 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
log(raw_ostream & OS) const62 void log(raw_ostream &OS) const override {
63 OS << "Dummy error " << Val;
64 }
65
getValue() const66 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>
registerDummyErrorSerialization()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:
serialize(QueueChannel &,const RPCBar &)102 static Error serialize(QueueChannel &, const RPCBar &) {
103 return Error::success();
104 }
105
deserialize(QueueChannel &,RPCBar &)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:
getName()119 static const char *getName() { return "VoidBool"; }
120 };
121
122 class IntInt : public RPCFunction<IntInt, int32_t(int32_t)> {
123 public:
getName()124 static const char *getName() { return "IntInt"; }
125 };
126
127 class VoidString : public RPCFunction<VoidString, void(std::string)> {
128 public:
getName()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:
getName()139 static const char *getName() { return "AllTheTypes"; }
140 };
141
142 class CustomType : public RPCFunction<CustomType, RPCFoo(RPCFoo)> {
143 public:
getName()144 static const char *getName() { return "CustomType"; }
145 };
146
147 class ErrorFunc : public RPCFunction<ErrorFunc, Error()> {
148 public:
getName()149 static const char *getName() { return "ErrorFunc"; }
150 };
151
152 class ExpectedFunc : public RPCFunction<ExpectedFunc, Expected<uint32_t>()> {
153 public:
getName()154 static const char *getName() { return "ExpectedFunc"; }
155 };
156 }
157
158 class DummyRPCEndpoint : public SingleThreadedRPCEndpoint<QueueChannel> {
159 public:
DummyRPCEndpoint(QueueChannel & C)160 DummyRPCEndpoint(QueueChannel &C)
161 : SingleThreadedRPCEndpoint(C, true) {}
162 };
163
164
freeVoidBool(bool B)165 void freeVoidBool(bool B) {
166 }
167
TEST(DummyRPC,TestFreeFunctionHandler)168 TEST(DummyRPC, TestFreeFunctionHandler) {
169 auto Channels = createPairedQueueChannels();
170 DummyRPCEndpoint Server(*Channels.first);
171 Server.addHandler<DummyRPCAPI::VoidBool>(freeVoidBool);
172 }
173
TEST(DummyRPC,TestCallAsyncVoidBool)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
TEST(DummyRPC,TestCallAsyncIntInt)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
TEST(DummyRPC,TestAsyncVoidBoolHandler)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
TEST(DummyRPC,TestAsyncIntIntHandler)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
TEST(DummyRPC,TestAsyncIntIntHandlerMethod)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
TEST(DummyRPC,TestCallAsyncVoidString)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
TEST(DummyRPC,TestSerialization)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
TEST(DummyRPC,TestCustomType)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
TEST(DummyRPC,TestWithAltCustomType)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
TEST(DummyRPC,ReturnErrorSuccess)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
TEST(DummyRPC,ReturnErrorFailure)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
TEST(DummyRPC,ReturnExpectedSuccess)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
TEST(DummyRPC,ReturnExpectedFailure)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
TEST(DummyRPC,TestParallelCallGroup)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
TEST(DummyRPC,TestAPICalls)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
TEST(DummyRPC,TestRemoveHandler)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
TEST(DummyRPC,TestClearHandlers)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