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