893 lines
27 KiB
C++
893 lines
27 KiB
C++
//===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
|
|
#include "QueueChannel.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <queue>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::orc;
|
|
using namespace llvm::orc::shared;
|
|
|
|
class RPCFoo {};
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
namespace shared {
|
|
|
|
template <> class SerializationTypeName<RPCFoo> {
|
|
public:
|
|
static const char *getName() { return "RPCFoo"; }
|
|
};
|
|
|
|
template <>
|
|
class SerializationTraits<QueueChannel, RPCFoo, RPCFoo> {
|
|
public:
|
|
static Error serialize(QueueChannel&, const RPCFoo&) {
|
|
return Error::success();
|
|
}
|
|
|
|
static Error deserialize(QueueChannel&, RPCFoo&) {
|
|
return Error::success();
|
|
}
|
|
};
|
|
|
|
} // namespace shared
|
|
} // end namespace orc
|
|
} // end namespace llvm
|
|
|
|
class RPCBar {};
|
|
|
|
class DummyError : public ErrorInfo<DummyError> {
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
DummyError(uint32_t Val) : Val(Val) {}
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
// Use a nonsense error code - we want to verify that errors
|
|
// transmitted over the network are replaced with
|
|
// OrcErrorCode::UnknownErrorCodeFromRemote.
|
|
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
|
|
}
|
|
|
|
void log(raw_ostream &OS) const override {
|
|
OS << "Dummy error " << Val;
|
|
}
|
|
|
|
uint32_t getValue() const { return Val; }
|
|
|
|
public:
|
|
uint32_t Val;
|
|
};
|
|
|
|
char DummyError::ID = 0;
|
|
|
|
template <typename ChannelT>
|
|
void registerDummyErrorSerialization() {
|
|
static bool AlreadyRegistered = false;
|
|
if (!AlreadyRegistered) {
|
|
SerializationTraits<ChannelT, Error>::
|
|
template registerErrorType<DummyError>(
|
|
"DummyError",
|
|
[](ChannelT &C, const DummyError &DE) {
|
|
return serializeSeq(C, DE.getValue());
|
|
},
|
|
[](ChannelT &C, Error &Err) -> Error {
|
|
ErrorAsOutParameter EAO(&Err);
|
|
uint32_t Val;
|
|
if (auto Err = deserializeSeq(C, Val))
|
|
return Err;
|
|
Err = make_error<DummyError>(Val);
|
|
return Error::success();
|
|
});
|
|
AlreadyRegistered = true;
|
|
}
|
|
}
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
namespace shared {
|
|
|
|
template <> class SerializationTraits<QueueChannel, RPCFoo, RPCBar> {
|
|
public:
|
|
static Error serialize(QueueChannel &, const RPCBar &) {
|
|
return Error::success();
|
|
}
|
|
|
|
static Error deserialize(QueueChannel &, RPCBar &) {
|
|
return Error::success();
|
|
}
|
|
};
|
|
|
|
} // end namespace shared
|
|
} // end namespace orc
|
|
} // end namespace llvm
|
|
|
|
namespace DummyRPCAPI {
|
|
|
|
class VoidBool : public RPCFunction<VoidBool, void(bool)> {
|
|
public:
|
|
static const char *getName() { return "VoidBool"; }
|
|
};
|
|
|
|
class IntInt : public RPCFunction<IntInt, int32_t(int32_t)> {
|
|
public:
|
|
static const char *getName() { return "IntInt"; }
|
|
};
|
|
|
|
class VoidString : public RPCFunction<VoidString, void(std::string)> {
|
|
public:
|
|
static const char *getName() { return "VoidString"; }
|
|
};
|
|
|
|
class AllTheTypes
|
|
: public RPCFunction<AllTheTypes,
|
|
void(int8_t, uint8_t, int16_t, uint16_t, int32_t,
|
|
uint32_t, int64_t, uint64_t, bool, std::string,
|
|
std::vector<int>, std::set<int>,
|
|
std::map<int, bool>)> {
|
|
public:
|
|
static const char *getName() { return "AllTheTypes"; }
|
|
};
|
|
|
|
class CustomType : public RPCFunction<CustomType, RPCFoo(RPCFoo)> {
|
|
public:
|
|
static const char *getName() { return "CustomType"; }
|
|
};
|
|
|
|
class ErrorFunc : public RPCFunction<ErrorFunc, Error()> {
|
|
public:
|
|
static const char *getName() { return "ErrorFunc"; }
|
|
};
|
|
|
|
class ExpectedFunc : public RPCFunction<ExpectedFunc, Expected<uint32_t>()> {
|
|
public:
|
|
static const char *getName() { return "ExpectedFunc"; }
|
|
};
|
|
}
|
|
|
|
class DummyRPCEndpoint : public SingleThreadedRPCEndpoint<QueueChannel> {
|
|
public:
|
|
DummyRPCEndpoint(QueueChannel &C)
|
|
: SingleThreadedRPCEndpoint(C, true) {}
|
|
};
|
|
|
|
|
|
void freeVoidBool(bool B) {
|
|
}
|
|
|
|
TEST(DummyRPC, TestFreeFunctionHandler) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Server(*Channels.first);
|
|
Server.addHandler<DummyRPCAPI::VoidBool>(freeVoidBool);
|
|
}
|
|
|
|
TEST(DummyRPC, TestCallAsyncVoidBool) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::VoidBool>(
|
|
[](bool B) {
|
|
EXPECT_EQ(B, true)
|
|
<< "Server void(bool) received unexpected result";
|
|
});
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the VoidBool call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
|
}
|
|
});
|
|
|
|
{
|
|
// Make an async call.
|
|
auto Err = Client.callAsync<DummyRPCAPI::VoidBool>(
|
|
[](Error Err) {
|
|
EXPECT_FALSE(!!Err) << "Async void(bool) response handler failed";
|
|
return Error::success();
|
|
}, true);
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result of the void(bool) call.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
|
|
// The client should have made two calls to send: One implicit call to
|
|
// negotiate the VoidBool function key, and a second to make the VoidBool
|
|
// call.
|
|
EXPECT_EQ(Channels.first->SendCalls, 2U)
|
|
<< "Expected one send call to have been made by client";
|
|
|
|
// The server should have made two calls to send: One to send the response to
|
|
// the negotiate call, and another to send the response to the VoidBool call.
|
|
EXPECT_EQ(Channels.second->SendCalls, 2U)
|
|
<< "Expected two send calls to have been made by server";
|
|
}
|
|
|
|
TEST(DummyRPC, TestCallAsyncIntInt) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::IntInt>(
|
|
[](int X) -> int {
|
|
EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
|
|
return 2 * X;
|
|
});
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the int(int) call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)";
|
|
}
|
|
});
|
|
|
|
{
|
|
auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
|
|
[](Expected<int> Result) {
|
|
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
|
EXPECT_EQ(*Result, 42)
|
|
<< "Async int(int) response handler received incorrect result";
|
|
return Error::success();
|
|
}, 21);
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestAsyncVoidBoolHandler) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addAsyncHandler<DummyRPCAPI::VoidBool>(
|
|
[](std::function<Error(Error)> SendResult,
|
|
bool B) {
|
|
EXPECT_EQ(B, true) << "Server void(bool) receieved unexpected result";
|
|
cantFail(SendResult(Error::success()));
|
|
return Error::success();
|
|
});
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the VoidBool call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
|
}
|
|
});
|
|
|
|
{
|
|
auto Err = Client.callAsync<DummyRPCAPI::VoidBool>(
|
|
[](Error Result) {
|
|
EXPECT_FALSE(!!Result) << "Async void(bool) response handler failed";
|
|
return Error::success();
|
|
}, true);
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestAsyncIntIntHandler) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addAsyncHandler<DummyRPCAPI::IntInt>(
|
|
[](std::function<Error(Expected<int32_t>)> SendResult,
|
|
int32_t X) {
|
|
EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
|
|
return SendResult(2 * X);
|
|
});
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the VoidBool call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
|
}
|
|
});
|
|
|
|
{
|
|
auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
|
|
[](Expected<int> Result) {
|
|
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
|
EXPECT_EQ(*Result, 42)
|
|
<< "Async int(int) response handler received incorrect result";
|
|
return Error::success();
|
|
}, 21);
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestAsyncIntIntHandlerMethod) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
class Dummy {
|
|
public:
|
|
Error handler(std::function<Error(Expected<int32_t>)> SendResult,
|
|
int32_t X) {
|
|
EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
|
|
return SendResult(2 * X);
|
|
}
|
|
};
|
|
|
|
std::thread ServerThread([&]() {
|
|
Dummy D;
|
|
Server.addAsyncHandler<DummyRPCAPI::IntInt>(D, &Dummy::handler);
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the VoidBool call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
|
}
|
|
});
|
|
|
|
{
|
|
auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
|
|
[](Expected<int> Result) {
|
|
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
|
EXPECT_EQ(*Result, 42)
|
|
<< "Async int(int) response handler received incorrect result";
|
|
return Error::success();
|
|
}, 21);
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestCallAsyncVoidString) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::VoidString>(
|
|
[](const std::string &S) {
|
|
EXPECT_EQ(S, "hello")
|
|
<< "Server void(std::string) received unexpected result";
|
|
});
|
|
|
|
// Poke the server to handle the negotiate call.
|
|
for (int I = 0; I < 4; ++I) {
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call";
|
|
}
|
|
});
|
|
|
|
{
|
|
// Make an call using a std::string.
|
|
auto Err = Client.callB<DummyRPCAPI::VoidString>(std::string("hello"));
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)";
|
|
}
|
|
|
|
{
|
|
// Make an call using a std::string.
|
|
auto Err = Client.callB<DummyRPCAPI::VoidString>(StringRef("hello"));
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)";
|
|
}
|
|
|
|
{
|
|
// Make an call using a std::string.
|
|
auto Err = Client.callB<DummyRPCAPI::VoidString>("hello");
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(string)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestSerialization) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::AllTheTypes>([&](int8_t S8, uint8_t U8,
|
|
int16_t S16, uint16_t U16,
|
|
int32_t S32, uint32_t U32,
|
|
int64_t S64, uint64_t U64,
|
|
bool B, std::string S,
|
|
std::vector<int> V,
|
|
std::set<int> S2,
|
|
std::map<int, bool> M) {
|
|
EXPECT_EQ(S8, -101) << "int8_t serialization broken";
|
|
EXPECT_EQ(U8, 250) << "uint8_t serialization broken";
|
|
EXPECT_EQ(S16, -10000) << "int16_t serialization broken";
|
|
EXPECT_EQ(U16, 10000) << "uint16_t serialization broken";
|
|
EXPECT_EQ(S32, -1000000000) << "int32_t serialization broken";
|
|
EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization broken";
|
|
EXPECT_EQ(S64, -10000000000) << "int64_t serialization broken";
|
|
EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization broken";
|
|
EXPECT_EQ(B, true) << "bool serialization broken";
|
|
EXPECT_EQ(S, "foo") << "std::string serialization broken";
|
|
EXPECT_EQ(V, std::vector<int>({42, 7}))
|
|
<< "std::vector serialization broken";
|
|
EXPECT_EQ(S2, std::set<int>({7, 42})) << "std::set serialization broken";
|
|
EXPECT_EQ(M, (std::map<int, bool>({{7, false}, {42, true}})))
|
|
<< "std::map serialization broken";
|
|
return Error::success();
|
|
});
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the AllTheTypes call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
|
}
|
|
});
|
|
|
|
{
|
|
// Make an async call.
|
|
std::vector<int> V({42, 7});
|
|
std::set<int> S({7, 42});
|
|
std::map<int, bool> M({{7, false}, {42, true}});
|
|
auto Err = Client.callAsync<DummyRPCAPI::AllTheTypes>(
|
|
[](Error Err) {
|
|
EXPECT_FALSE(!!Err) << "Async AllTheTypes response handler failed";
|
|
return Error::success();
|
|
},
|
|
static_cast<int8_t>(-101), static_cast<uint8_t>(250),
|
|
static_cast<int16_t>(-10000), static_cast<uint16_t>(10000),
|
|
static_cast<int32_t>(-1000000000), static_cast<uint32_t>(1000000000),
|
|
static_cast<int64_t>(-10000000000), static_cast<uint64_t>(10000000000),
|
|
true, std::string("foo"), V, S, M);
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for AllTheTypes";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result of the AllTheTypes call.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Client failed to handle response from AllTheTypes";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestCustomType) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::CustomType>(
|
|
[](RPCFoo F) {});
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the CustomType call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)";
|
|
}
|
|
});
|
|
|
|
{
|
|
// Make an async call.
|
|
auto Err = Client.callAsync<DummyRPCAPI::CustomType>(
|
|
[](Expected<RPCFoo> FOrErr) {
|
|
EXPECT_TRUE(!!FOrErr)
|
|
<< "Async RPCFoo(RPCFoo) response handler failed";
|
|
return Error::success();
|
|
}, RPCFoo());
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result of the RPCFoo() call.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err)
|
|
<< "Client failed to handle response from RPCFoo(RPCFoo)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestWithAltCustomType) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::CustomType>(
|
|
[](RPCBar F) {});
|
|
|
|
{
|
|
// Poke the server to handle the negotiate call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
|
}
|
|
|
|
{
|
|
// Poke the server to handle the CustomType call.
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)";
|
|
}
|
|
});
|
|
|
|
{
|
|
// Make an async call.
|
|
auto Err = Client.callAsync<DummyRPCAPI::CustomType>(
|
|
[](Expected<RPCBar> FOrErr) {
|
|
EXPECT_TRUE(!!FOrErr)
|
|
<< "Async RPCFoo(RPCFoo) response handler failed";
|
|
return Error::success();
|
|
}, RPCBar());
|
|
EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)";
|
|
}
|
|
|
|
{
|
|
// Poke the client to process the result of the RPCFoo() call.
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err)
|
|
<< "Client failed to handle response from RPCFoo(RPCFoo)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, ReturnErrorSuccess) {
|
|
registerDummyErrorSerialization<QueueChannel>();
|
|
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::ErrorFunc>(
|
|
[]() {
|
|
return Error::success();
|
|
});
|
|
|
|
// Handle the negotiate plus one call.
|
|
for (unsigned I = 0; I != 2; ++I)
|
|
cantFail(Server.handleOne());
|
|
});
|
|
|
|
cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>(
|
|
[&](Error Err) {
|
|
EXPECT_FALSE(!!Err) << "Expected success value";
|
|
return Error::success();
|
|
}));
|
|
|
|
cantFail(Client.handleOne());
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, ReturnErrorFailure) {
|
|
registerDummyErrorSerialization<QueueChannel>();
|
|
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::ErrorFunc>(
|
|
[]() {
|
|
return make_error<DummyError>(42);
|
|
});
|
|
|
|
// Handle the negotiate plus one call.
|
|
for (unsigned I = 0; I != 2; ++I)
|
|
cantFail(Server.handleOne());
|
|
});
|
|
|
|
cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>(
|
|
[&](Error Err) {
|
|
EXPECT_TRUE(Err.isA<DummyError>())
|
|
<< "Incorrect error type";
|
|
return handleErrors(
|
|
std::move(Err),
|
|
[](const DummyError &DE) {
|
|
EXPECT_EQ(DE.getValue(), 42ULL)
|
|
<< "Incorrect DummyError serialization";
|
|
});
|
|
}));
|
|
|
|
cantFail(Client.handleOne());
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, ReturnExpectedSuccess) {
|
|
registerDummyErrorSerialization<QueueChannel>();
|
|
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::ExpectedFunc>(
|
|
[]() -> uint32_t {
|
|
return 42;
|
|
});
|
|
|
|
// Handle the negotiate plus one call.
|
|
for (unsigned I = 0; I != 2; ++I)
|
|
cantFail(Server.handleOne());
|
|
});
|
|
|
|
cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>(
|
|
[&](Expected<uint32_t> ValOrErr) {
|
|
EXPECT_TRUE(!!ValOrErr)
|
|
<< "Expected success value";
|
|
EXPECT_EQ(*ValOrErr, 42ULL)
|
|
<< "Incorrect Expected<uint32_t> deserialization";
|
|
return Error::success();
|
|
}));
|
|
|
|
cantFail(Client.handleOne());
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, ReturnExpectedFailure) {
|
|
registerDummyErrorSerialization<QueueChannel>();
|
|
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::ExpectedFunc>(
|
|
[]() -> Expected<uint32_t> {
|
|
return make_error<DummyError>(7);
|
|
});
|
|
|
|
// Handle the negotiate plus one call.
|
|
for (unsigned I = 0; I != 2; ++I)
|
|
cantFail(Server.handleOne());
|
|
});
|
|
|
|
cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>(
|
|
[&](Expected<uint32_t> ValOrErr) {
|
|
EXPECT_FALSE(!!ValOrErr)
|
|
<< "Expected failure value";
|
|
auto Err = ValOrErr.takeError();
|
|
EXPECT_TRUE(Err.isA<DummyError>())
|
|
<< "Incorrect error type";
|
|
return handleErrors(
|
|
std::move(Err),
|
|
[](const DummyError &DE) {
|
|
EXPECT_EQ(DE.getValue(), 7ULL)
|
|
<< "Incorrect DummyError serialization";
|
|
});
|
|
}));
|
|
|
|
cantFail(Client.handleOne());
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestParallelCallGroup) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread([&]() {
|
|
Server.addHandler<DummyRPCAPI::IntInt>(
|
|
[](int X) -> int {
|
|
return 2 * X;
|
|
});
|
|
|
|
// Handle the negotiate, plus three calls.
|
|
for (unsigned I = 0; I != 4; ++I) {
|
|
auto Err = Server.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)";
|
|
}
|
|
});
|
|
|
|
{
|
|
int A, B, C;
|
|
ParallelCallGroup PCG;
|
|
|
|
{
|
|
auto Err = PCG.call(
|
|
rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
|
|
[&A](Expected<int> Result) {
|
|
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
|
A = *Result;
|
|
return Error::success();
|
|
}, 1);
|
|
EXPECT_FALSE(!!Err) << "First parallel call failed for int(int)";
|
|
}
|
|
|
|
{
|
|
auto Err = PCG.call(
|
|
rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
|
|
[&B](Expected<int> Result) {
|
|
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
|
B = *Result;
|
|
return Error::success();
|
|
}, 2);
|
|
EXPECT_FALSE(!!Err) << "Second parallel call failed for int(int)";
|
|
}
|
|
|
|
{
|
|
auto Err = PCG.call(
|
|
rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
|
|
[&C](Expected<int> Result) {
|
|
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
|
C = *Result;
|
|
return Error::success();
|
|
}, 3);
|
|
EXPECT_FALSE(!!Err) << "Third parallel call failed for int(int)";
|
|
}
|
|
|
|
// Handle the three int(int) results.
|
|
for (unsigned I = 0; I != 3; ++I) {
|
|
auto Err = Client.handleOne();
|
|
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
|
}
|
|
|
|
PCG.wait();
|
|
|
|
EXPECT_EQ(A, 2) << "First parallel call returned bogus result";
|
|
EXPECT_EQ(B, 4) << "Second parallel call returned bogus result";
|
|
EXPECT_EQ(C, 6) << "Third parallel call returned bogus result";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestAPICalls) {
|
|
|
|
using DummyCalls1 = APICalls<DummyRPCAPI::VoidBool, DummyRPCAPI::IntInt>;
|
|
using DummyCalls2 = APICalls<DummyRPCAPI::AllTheTypes>;
|
|
using DummyCalls3 = APICalls<DummyCalls1, DummyRPCAPI::CustomType>;
|
|
using DummyCallsAll = APICalls<DummyCalls1, DummyCalls2, DummyRPCAPI::CustomType>;
|
|
|
|
static_assert(DummyCalls1::Contains<DummyRPCAPI::VoidBool>::value,
|
|
"Contains<Func> template should return true here");
|
|
static_assert(!DummyCalls1::Contains<DummyRPCAPI::CustomType>::value,
|
|
"Contains<Func> template should return false here");
|
|
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Client(*Channels.first);
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
std::thread ServerThread(
|
|
[&]() {
|
|
Server.addHandler<DummyRPCAPI::VoidBool>([](bool b) { });
|
|
Server.addHandler<DummyRPCAPI::IntInt>([](int x) { return x; });
|
|
Server.addHandler<DummyRPCAPI::CustomType>([](RPCFoo F) {});
|
|
|
|
for (unsigned I = 0; I < 4; ++I) {
|
|
auto Err = Server.handleOne();
|
|
(void)!!Err;
|
|
}
|
|
});
|
|
|
|
{
|
|
auto Err = DummyCalls1::negotiate(Client);
|
|
EXPECT_FALSE(!!Err) << "DummyCalls1::negotiate failed";
|
|
}
|
|
|
|
{
|
|
auto Err = DummyCalls3::negotiate(Client);
|
|
EXPECT_FALSE(!!Err) << "DummyCalls3::negotiate failed";
|
|
}
|
|
|
|
{
|
|
auto Err = DummyCallsAll::negotiate(Client);
|
|
EXPECT_TRUE(Err.isA<CouldNotNegotiate>())
|
|
<< "Expected CouldNotNegotiate error for attempted negotiate of "
|
|
"unsupported function";
|
|
consumeError(std::move(Err));
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestRemoveHandler) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
Server.addHandler<DummyRPCAPI::VoidBool>(
|
|
[](bool B) {
|
|
EXPECT_EQ(B, true)
|
|
<< "Server void(bool) received unexpected result";
|
|
});
|
|
|
|
Server.removeHandler<DummyRPCAPI::VoidBool>();
|
|
}
|
|
|
|
TEST(DummyRPC, TestClearHandlers) {
|
|
auto Channels = createPairedQueueChannels();
|
|
DummyRPCEndpoint Server(*Channels.second);
|
|
|
|
Server.addHandler<DummyRPCAPI::VoidBool>(
|
|
[](bool B) {
|
|
EXPECT_EQ(B, true)
|
|
<< "Server void(bool) received unexpected result";
|
|
});
|
|
|
|
Server.clearHandlers();
|
|
}
|