xref: /aosp_15_r20/external/flatbuffers/grpc/tests/grpctest.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
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