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