#include <grpcpp/grpcpp.h>
#include <condition_variable>
#include <thread>
#include "monster_test.grpc.fb.h"
#include "monster_test_generated.h"
#include "test_assert.h"
using namespace MyGame::Example;
using flatbuffers::FlatBufferBuilder;
using flatbuffers::grpc::MessageBuilder;
void message_builder_tests();
class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
virtual ::grpc::Status Store(
::grpc::ServerContext *context,
const flatbuffers::grpc::Message<Monster> *request,
flatbuffers::grpc::Message<Stat> *response) override {
fbb_.Clear();
auto stat_offset = CreateStat(
fbb_, fbb_.CreateString("Hello, " + request->GetRoot()->name()->str()));
fbb_.Finish(stat_offset);
*response = fbb_.ReleaseMessage<Stat>();
return grpc::Status::OK;
}
virtual ::grpc::Status Retrieve(
::grpc::ServerContext *context,
const flatbuffers::grpc::Message<Stat> *request,
::grpc::ServerWriter<flatbuffers::grpc::Message<Monster>> *writer)
override {
for (int i = 0; i < 5; i++) {
fbb_.Clear();
auto monster_offset =
CreateMonster(fbb_, 0, 0, 0,
fbb_.CreateString(request->GetRoot()->id()->str() +
" No." + std::to_string(i)));
fbb_.Finish(monster_offset);
flatbuffers::grpc::Message<Monster> monster =
fbb_.ReleaseMessage<Monster>();
writer->Write(monster);
}
return grpc::Status::OK;
}
private:
flatbuffers::grpc::MessageBuilder fbb_;
};
grpc::Server *server_instance = nullptr;
std::mutex wait_for_server;
std::condition_variable server_instance_cv;
void RunServer() {
auto server_address = "0.0.0.0:50051";
ServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
wait_for_server.lock();
server_instance = builder.BuildAndStart().release();
wait_for_server.unlock();
server_instance_cv.notify_one();
std::cout << "Server listening on " << server_address << std::endl;
server_instance->Wait();
}
template<class Builder> void StoreRPC(MonsterStorage::Stub *stub) {
Builder fbb;
grpc::ClientContext context;
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
MessageBuilder mb(std::move(fbb));
mb.Finish(monster_offset);
auto request = mb.ReleaseMessage<Monster>();
flatbuffers::grpc::Message<Stat> response;
auto status = stub->Store(&context, request, &response);
if (status.ok()) {
auto resp = response.GetRoot()->id();
std::cout << "RPC response: " << resp->str() << std::endl;
} else {
std::cout << "RPC failed" << std::endl;
}
}
template<class Builder> void RetrieveRPC(MonsterStorage::Stub *stub) {
Builder fbb;
grpc::ClientContext context;
fbb.Clear();
auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
fbb.Finish(stat_offset);
auto request = MessageBuilder(std::move(fbb)).ReleaseMessage<Stat>();
flatbuffers::grpc::Message<Monster> response;
auto stream = stub->Retrieve(&context, request);
while (stream->Read(&response)) {
auto resp = response.GetRoot()->name();
std::cout << "RPC Streaming response: " << resp->str() << std::endl;
}
}
int grpc_server_test() {
std::thread server_thread(RunServer);
std::unique_lock<std::mutex> lock(wait_for_server);
while (!server_instance) server_instance_cv.wait(lock);
auto channel = grpc::CreateChannel("localhost:50051",
grpc::InsecureChannelCredentials());
auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
StoreRPC<MessageBuilder>(stub.get());
StoreRPC<FlatBufferBuilder>(stub.get());
RetrieveRPC<MessageBuilder>(stub.get());
RetrieveRPC<FlatBufferBuilder>(stub.get());
#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
{
grpc::ClientContext context;
flatbuffers::grpc::Message<Monster> request; flatbuffers::grpc::Message<Stat> response;
auto status = stub->Store(&context, request, &response);
assert(!status.ok());
assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
assert(strcmp(status.error_message().c_str(),
"Message verification failed") == 0);
}
#endif
server_instance->Shutdown();
server_thread.join();
delete server_instance;
return 0;
}
int main(int , const char * []) {
message_builder_tests();
grpc_server_test();
if (!testing_fails) {
TEST_OUTPUT_LINE("ALL TESTS PASSED");
return 0;
} else {
TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
return 1;
}
}