1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker * Copyright 2014 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker *
4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker *
8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker *
10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker */
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker #include <grpcpp/grpcpp.h>
18*890232f2SAndroid Build Coastguard Worker
19*890232f2SAndroid Build Coastguard Worker #include <condition_variable>
20*890232f2SAndroid Build Coastguard Worker #include <thread>
21*890232f2SAndroid Build Coastguard Worker
22*890232f2SAndroid Build Coastguard Worker #include "monster_test.grpc.fb.h"
23*890232f2SAndroid Build Coastguard Worker #include "monster_test_generated.h"
24*890232f2SAndroid Build Coastguard Worker #include "test_assert.h"
25*890232f2SAndroid Build Coastguard Worker
26*890232f2SAndroid Build Coastguard Worker using namespace MyGame::Example;
27*890232f2SAndroid Build Coastguard Worker using flatbuffers::FlatBufferBuilder;
28*890232f2SAndroid Build Coastguard Worker using flatbuffers::grpc::MessageBuilder;
29*890232f2SAndroid Build Coastguard Worker
30*890232f2SAndroid Build Coastguard Worker void message_builder_tests();
31*890232f2SAndroid Build Coastguard Worker
32*890232f2SAndroid Build Coastguard Worker // The callback implementation of our server, that derives from the generated
33*890232f2SAndroid Build Coastguard Worker // code. It implements all rpcs specified in the FlatBuffers schema.
34*890232f2SAndroid Build Coastguard Worker class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
Store(::grpc::ServerContext * context,const flatbuffers::grpc::Message<Monster> * request,flatbuffers::grpc::Message<Stat> * response)35*890232f2SAndroid Build Coastguard Worker virtual ::grpc::Status Store(
36*890232f2SAndroid Build Coastguard Worker ::grpc::ServerContext *context,
37*890232f2SAndroid Build Coastguard Worker const flatbuffers::grpc::Message<Monster> *request,
38*890232f2SAndroid Build Coastguard Worker flatbuffers::grpc::Message<Stat> *response) override {
39*890232f2SAndroid Build Coastguard Worker // Create a response from the incoming request name.
40*890232f2SAndroid Build Coastguard Worker fbb_.Clear();
41*890232f2SAndroid Build Coastguard Worker auto stat_offset = CreateStat(
42*890232f2SAndroid Build Coastguard Worker fbb_, fbb_.CreateString("Hello, " + request->GetRoot()->name()->str()));
43*890232f2SAndroid Build Coastguard Worker fbb_.Finish(stat_offset);
44*890232f2SAndroid Build Coastguard Worker // Transfer ownership of the message to gRPC
45*890232f2SAndroid Build Coastguard Worker *response = fbb_.ReleaseMessage<Stat>();
46*890232f2SAndroid Build Coastguard Worker return grpc::Status::OK;
47*890232f2SAndroid Build Coastguard Worker }
Retrieve(::grpc::ServerContext * context,const flatbuffers::grpc::Message<Stat> * request,::grpc::ServerWriter<flatbuffers::grpc::Message<Monster>> * writer)48*890232f2SAndroid Build Coastguard Worker virtual ::grpc::Status Retrieve(
49*890232f2SAndroid Build Coastguard Worker ::grpc::ServerContext *context,
50*890232f2SAndroid Build Coastguard Worker const flatbuffers::grpc::Message<Stat> *request,
51*890232f2SAndroid Build Coastguard Worker ::grpc::ServerWriter<flatbuffers::grpc::Message<Monster>> *writer)
52*890232f2SAndroid Build Coastguard Worker override {
53*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < 5; i++) {
54*890232f2SAndroid Build Coastguard Worker fbb_.Clear();
55*890232f2SAndroid Build Coastguard Worker // Create 5 monsters for resposne.
56*890232f2SAndroid Build Coastguard Worker auto monster_offset =
57*890232f2SAndroid Build Coastguard Worker CreateMonster(fbb_, 0, 0, 0,
58*890232f2SAndroid Build Coastguard Worker fbb_.CreateString(request->GetRoot()->id()->str() +
59*890232f2SAndroid Build Coastguard Worker " No." + std::to_string(i)));
60*890232f2SAndroid Build Coastguard Worker fbb_.Finish(monster_offset);
61*890232f2SAndroid Build Coastguard Worker
62*890232f2SAndroid Build Coastguard Worker flatbuffers::grpc::Message<Monster> monster =
63*890232f2SAndroid Build Coastguard Worker fbb_.ReleaseMessage<Monster>();
64*890232f2SAndroid Build Coastguard Worker
65*890232f2SAndroid Build Coastguard Worker // Send monster to client using streaming.
66*890232f2SAndroid Build Coastguard Worker writer->Write(monster);
67*890232f2SAndroid Build Coastguard Worker }
68*890232f2SAndroid Build Coastguard Worker return grpc::Status::OK;
69*890232f2SAndroid Build Coastguard Worker }
70*890232f2SAndroid Build Coastguard Worker
71*890232f2SAndroid Build Coastguard Worker private:
72*890232f2SAndroid Build Coastguard Worker flatbuffers::grpc::MessageBuilder fbb_;
73*890232f2SAndroid Build Coastguard Worker };
74*890232f2SAndroid Build Coastguard Worker
75*890232f2SAndroid Build Coastguard Worker // Track the server instance, so we can terminate it later.
76*890232f2SAndroid Build Coastguard Worker grpc::Server *server_instance = nullptr;
77*890232f2SAndroid Build Coastguard Worker // Mutex to protec this variable.
78*890232f2SAndroid Build Coastguard Worker std::mutex wait_for_server;
79*890232f2SAndroid Build Coastguard Worker std::condition_variable server_instance_cv;
80*890232f2SAndroid Build Coastguard Worker
81*890232f2SAndroid Build Coastguard Worker // This function implements the server thread.
RunServer()82*890232f2SAndroid Build Coastguard Worker void RunServer() {
83*890232f2SAndroid Build Coastguard Worker auto server_address = "0.0.0.0:50051";
84*890232f2SAndroid Build Coastguard Worker // Callback interface we implemented above.
85*890232f2SAndroid Build Coastguard Worker ServiceImpl service;
86*890232f2SAndroid Build Coastguard Worker grpc::ServerBuilder builder;
87*890232f2SAndroid Build Coastguard Worker builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
88*890232f2SAndroid Build Coastguard Worker builder.RegisterService(&service);
89*890232f2SAndroid Build Coastguard Worker
90*890232f2SAndroid Build Coastguard Worker // Start the server. Lock to change the variable we're changing.
91*890232f2SAndroid Build Coastguard Worker wait_for_server.lock();
92*890232f2SAndroid Build Coastguard Worker server_instance = builder.BuildAndStart().release();
93*890232f2SAndroid Build Coastguard Worker wait_for_server.unlock();
94*890232f2SAndroid Build Coastguard Worker server_instance_cv.notify_one();
95*890232f2SAndroid Build Coastguard Worker
96*890232f2SAndroid Build Coastguard Worker std::cout << "Server listening on " << server_address << std::endl;
97*890232f2SAndroid Build Coastguard Worker // This will block the thread and serve requests.
98*890232f2SAndroid Build Coastguard Worker server_instance->Wait();
99*890232f2SAndroid Build Coastguard Worker }
100*890232f2SAndroid Build Coastguard Worker
StoreRPC(MonsterStorage::Stub * stub)101*890232f2SAndroid Build Coastguard Worker template<class Builder> void StoreRPC(MonsterStorage::Stub *stub) {
102*890232f2SAndroid Build Coastguard Worker Builder fbb;
103*890232f2SAndroid Build Coastguard Worker grpc::ClientContext context;
104*890232f2SAndroid Build Coastguard Worker // Build a request with the name set.
105*890232f2SAndroid Build Coastguard Worker auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
106*890232f2SAndroid Build Coastguard Worker MessageBuilder mb(std::move(fbb));
107*890232f2SAndroid Build Coastguard Worker mb.Finish(monster_offset);
108*890232f2SAndroid Build Coastguard Worker auto request = mb.ReleaseMessage<Monster>();
109*890232f2SAndroid Build Coastguard Worker flatbuffers::grpc::Message<Stat> response;
110*890232f2SAndroid Build Coastguard Worker
111*890232f2SAndroid Build Coastguard Worker // The actual RPC.
112*890232f2SAndroid Build Coastguard Worker auto status = stub->Store(&context, request, &response);
113*890232f2SAndroid Build Coastguard Worker
114*890232f2SAndroid Build Coastguard Worker if (status.ok()) {
115*890232f2SAndroid Build Coastguard Worker auto resp = response.GetRoot()->id();
116*890232f2SAndroid Build Coastguard Worker std::cout << "RPC response: " << resp->str() << std::endl;
117*890232f2SAndroid Build Coastguard Worker } else {
118*890232f2SAndroid Build Coastguard Worker std::cout << "RPC failed" << std::endl;
119*890232f2SAndroid Build Coastguard Worker }
120*890232f2SAndroid Build Coastguard Worker }
121*890232f2SAndroid Build Coastguard Worker
RetrieveRPC(MonsterStorage::Stub * stub)122*890232f2SAndroid Build Coastguard Worker template<class Builder> void RetrieveRPC(MonsterStorage::Stub *stub) {
123*890232f2SAndroid Build Coastguard Worker Builder fbb;
124*890232f2SAndroid Build Coastguard Worker grpc::ClientContext context;
125*890232f2SAndroid Build Coastguard Worker fbb.Clear();
126*890232f2SAndroid Build Coastguard Worker auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
127*890232f2SAndroid Build Coastguard Worker fbb.Finish(stat_offset);
128*890232f2SAndroid Build Coastguard Worker auto request = MessageBuilder(std::move(fbb)).ReleaseMessage<Stat>();
129*890232f2SAndroid Build Coastguard Worker
130*890232f2SAndroid Build Coastguard Worker flatbuffers::grpc::Message<Monster> response;
131*890232f2SAndroid Build Coastguard Worker auto stream = stub->Retrieve(&context, request);
132*890232f2SAndroid Build Coastguard Worker while (stream->Read(&response)) {
133*890232f2SAndroid Build Coastguard Worker auto resp = response.GetRoot()->name();
134*890232f2SAndroid Build Coastguard Worker std::cout << "RPC Streaming response: " << resp->str() << std::endl;
135*890232f2SAndroid Build Coastguard Worker }
136*890232f2SAndroid Build Coastguard Worker }
137*890232f2SAndroid Build Coastguard Worker
grpc_server_test()138*890232f2SAndroid Build Coastguard Worker int grpc_server_test() {
139*890232f2SAndroid Build Coastguard Worker // Launch server.
140*890232f2SAndroid Build Coastguard Worker std::thread server_thread(RunServer);
141*890232f2SAndroid Build Coastguard Worker
142*890232f2SAndroid Build Coastguard Worker // wait for server to spin up.
143*890232f2SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(wait_for_server);
144*890232f2SAndroid Build Coastguard Worker while (!server_instance) server_instance_cv.wait(lock);
145*890232f2SAndroid Build Coastguard Worker
146*890232f2SAndroid Build Coastguard Worker // Now connect the client.
147*890232f2SAndroid Build Coastguard Worker auto channel = grpc::CreateChannel("localhost:50051",
148*890232f2SAndroid Build Coastguard Worker grpc::InsecureChannelCredentials());
149*890232f2SAndroid Build Coastguard Worker auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
150*890232f2SAndroid Build Coastguard Worker
151*890232f2SAndroid Build Coastguard Worker StoreRPC<MessageBuilder>(stub.get());
152*890232f2SAndroid Build Coastguard Worker StoreRPC<FlatBufferBuilder>(stub.get());
153*890232f2SAndroid Build Coastguard Worker
154*890232f2SAndroid Build Coastguard Worker RetrieveRPC<MessageBuilder>(stub.get());
155*890232f2SAndroid Build Coastguard Worker RetrieveRPC<FlatBufferBuilder>(stub.get());
156*890232f2SAndroid Build Coastguard Worker
157*890232f2SAndroid Build Coastguard Worker #if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
158*890232f2SAndroid Build Coastguard Worker {
159*890232f2SAndroid Build Coastguard Worker // Test that an invalid request errors out correctly
160*890232f2SAndroid Build Coastguard Worker grpc::ClientContext context;
161*890232f2SAndroid Build Coastguard Worker flatbuffers::grpc::Message<Monster> request; // simulate invalid message
162*890232f2SAndroid Build Coastguard Worker flatbuffers::grpc::Message<Stat> response;
163*890232f2SAndroid Build Coastguard Worker auto status = stub->Store(&context, request, &response);
164*890232f2SAndroid Build Coastguard Worker // The rpc status should be INTERNAL to indicate a verification error. This
165*890232f2SAndroid Build Coastguard Worker // matches the protobuf gRPC status code for an unparseable message.
166*890232f2SAndroid Build Coastguard Worker assert(!status.ok());
167*890232f2SAndroid Build Coastguard Worker assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
168*890232f2SAndroid Build Coastguard Worker assert(strcmp(status.error_message().c_str(),
169*890232f2SAndroid Build Coastguard Worker "Message verification failed") == 0);
170*890232f2SAndroid Build Coastguard Worker }
171*890232f2SAndroid Build Coastguard Worker #endif
172*890232f2SAndroid Build Coastguard Worker
173*890232f2SAndroid Build Coastguard Worker server_instance->Shutdown();
174*890232f2SAndroid Build Coastguard Worker
175*890232f2SAndroid Build Coastguard Worker server_thread.join();
176*890232f2SAndroid Build Coastguard Worker
177*890232f2SAndroid Build Coastguard Worker delete server_instance;
178*890232f2SAndroid Build Coastguard Worker
179*890232f2SAndroid Build Coastguard Worker return 0;
180*890232f2SAndroid Build Coastguard Worker }
181*890232f2SAndroid Build Coastguard Worker
main(int,const char * [])182*890232f2SAndroid Build Coastguard Worker int main(int /*argc*/, const char * /*argv*/[]) {
183*890232f2SAndroid Build Coastguard Worker message_builder_tests();
184*890232f2SAndroid Build Coastguard Worker grpc_server_test();
185*890232f2SAndroid Build Coastguard Worker
186*890232f2SAndroid Build Coastguard Worker if (!testing_fails) {
187*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("ALL TESTS PASSED");
188*890232f2SAndroid Build Coastguard Worker return 0;
189*890232f2SAndroid Build Coastguard Worker } else {
190*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
191*890232f2SAndroid Build Coastguard Worker return 1;
192*890232f2SAndroid Build Coastguard Worker }
193*890232f2SAndroid Build Coastguard Worker }
194