1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include <climits>
20 #include <iostream>
21
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24
25 #include "absl/types/optional.h"
26
27 #include <grpc/grpc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/time.h>
30 #include <grpcpp/channel.h>
31 #include <grpcpp/client_context.h>
32 #include <grpcpp/create_channel.h>
33 #include <grpcpp/server.h>
34 #include <grpcpp/server_builder.h>
35 #include <grpcpp/server_context.h>
36 #include <grpcpp/test/default_reactor_test_peer.h>
37 #include <grpcpp/test/mock_stream.h>
38
39 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
40 #include "src/proto/grpc/testing/echo.grpc.pb.h"
41 #include "src/proto/grpc/testing/echo_mock.grpc.pb.h"
42 #include "test/core/util/port.h"
43 #include "test/core/util/test_config.h"
44
45 using grpc::testing::DefaultReactorTestPeer;
46 using grpc::testing::EchoRequest;
47 using grpc::testing::EchoResponse;
48 using grpc::testing::EchoTestService;
49 using grpc::testing::MockClientReaderWriter;
50 using std::vector;
51 using ::testing::_;
52 using ::testing::AtLeast;
53 using ::testing::DoAll;
54 using ::testing::Return;
55 using ::testing::SaveArg;
56 using ::testing::SetArgPointee;
57 using ::testing::WithArg;
58
59 namespace grpc {
60 namespace testing {
61
62 namespace {
63 class FakeClient {
64 public:
FakeClient(EchoTestService::StubInterface * stub)65 explicit FakeClient(EchoTestService::StubInterface* stub) : stub_(stub) {}
66
DoEcho()67 void DoEcho() {
68 ClientContext context;
69 EchoRequest request;
70 EchoResponse response;
71 request.set_message("hello world");
72 Status s = stub_->Echo(&context, request, &response);
73 EXPECT_EQ(request.message(), response.message());
74 EXPECT_TRUE(s.ok());
75 }
76
DoRequestStream()77 void DoRequestStream() {
78 EchoRequest request;
79 EchoResponse response;
80
81 ClientContext context;
82 std::string msg("hello");
83 std::string exp(msg);
84
85 std::unique_ptr<ClientWriterInterface<EchoRequest>> cstream =
86 stub_->RequestStream(&context, &response);
87
88 request.set_message(msg);
89 EXPECT_TRUE(cstream->Write(request));
90
91 msg = ", world";
92 request.set_message(msg);
93 exp.append(msg);
94 EXPECT_TRUE(cstream->Write(request));
95
96 cstream->WritesDone();
97 Status s = cstream->Finish();
98
99 EXPECT_EQ(exp, response.message());
100 EXPECT_TRUE(s.ok());
101 }
102
DoResponseStream()103 void DoResponseStream() {
104 EchoRequest request;
105 EchoResponse response;
106 request.set_message("hello world");
107
108 ClientContext context;
109 std::unique_ptr<ClientReaderInterface<EchoResponse>> cstream =
110 stub_->ResponseStream(&context, request);
111
112 std::string exp = "";
113 EXPECT_TRUE(cstream->Read(&response));
114 exp.append(response.message() + " ");
115
116 EXPECT_TRUE(cstream->Read(&response));
117 exp.append(response.message());
118
119 EXPECT_FALSE(cstream->Read(&response));
120 EXPECT_EQ(request.message(), exp);
121
122 Status s = cstream->Finish();
123 EXPECT_TRUE(s.ok());
124 }
125
DoBidiStream()126 void DoBidiStream() {
127 EchoRequest request;
128 EchoResponse response;
129 ClientContext context;
130 std::string msg("hello");
131
132 std::unique_ptr<ClientReaderWriterInterface<EchoRequest, EchoResponse>>
133 stream = stub_->BidiStream(&context);
134
135 request.set_message(msg + "0");
136 EXPECT_TRUE(stream->Write(request));
137 EXPECT_TRUE(stream->Read(&response));
138 EXPECT_EQ(response.message(), request.message());
139
140 request.set_message(msg + "1");
141 EXPECT_TRUE(stream->Write(request));
142 EXPECT_TRUE(stream->Read(&response));
143 EXPECT_EQ(response.message(), request.message());
144
145 request.set_message(msg + "2");
146 EXPECT_TRUE(stream->Write(request));
147 EXPECT_TRUE(stream->Read(&response));
148 EXPECT_EQ(response.message(), request.message());
149
150 stream->WritesDone();
151 EXPECT_FALSE(stream->Read(&response));
152
153 Status s = stream->Finish();
154 EXPECT_TRUE(s.ok());
155 }
156
ResetStub(EchoTestService::StubInterface * stub)157 void ResetStub(EchoTestService::StubInterface* stub) { stub_ = stub; }
158
159 private:
160 EchoTestService::StubInterface* stub_;
161 };
162
163 class CallbackTestServiceImpl : public EchoTestService::CallbackService {
164 public:
Echo(CallbackServerContext * context,const EchoRequest * request,EchoResponse * response)165 ServerUnaryReactor* Echo(CallbackServerContext* context,
166 const EchoRequest* request,
167 EchoResponse* response) override {
168 // Make the mock service explicitly treat empty input messages as invalid
169 // arguments so that we can test various results of status. In general, a
170 // mocked service should just use the original service methods, but we are
171 // adding this variance in Status return value just to improve coverage in
172 // this test.
173 auto* reactor = context->DefaultReactor();
174 if (request->message().length() > 0) {
175 response->set_message(request->message());
176 reactor->Finish(Status::OK);
177 } else {
178 reactor->Finish(Status(StatusCode::INVALID_ARGUMENT, "Invalid request"));
179 }
180 return reactor;
181 }
182 };
183
184 class MockCallbackTest : public ::testing::Test {
185 protected:
186 CallbackTestServiceImpl service_;
187 ServerContext context_;
188 };
189
TEST_F(MockCallbackTest,MockedCallSucceedsWithWait)190 TEST_F(MockCallbackTest, MockedCallSucceedsWithWait) {
191 CallbackServerContext ctx;
192 EchoRequest req;
193 EchoResponse resp;
194 struct {
195 grpc::internal::Mutex mu;
196 grpc::internal::CondVar cv;
197 absl::optional<grpc::Status> ABSL_GUARDED_BY(mu) status;
198 } status;
199 DefaultReactorTestPeer peer(&ctx, [&](::grpc::Status s) {
200 grpc::internal::MutexLock l(&status.mu);
201 status.status = std::move(s);
202 status.cv.Signal();
203 });
204
205 req.set_message("mock 1");
206 auto* reactor = service_.Echo(&ctx, &req, &resp);
207
208 grpc::internal::MutexLock l(&status.mu);
209 while (!status.status.has_value()) {
210 status.cv.Wait(&status.mu);
211 }
212
213 EXPECT_EQ(reactor, peer.reactor());
214 EXPECT_TRUE(peer.test_status_set());
215 EXPECT_TRUE(peer.test_status().ok());
216 EXPECT_TRUE(status.status.has_value());
217 EXPECT_TRUE(status.status.value().ok());
218 EXPECT_EQ(req.message(), resp.message());
219 }
220
TEST_F(MockCallbackTest,MockedCallSucceeds)221 TEST_F(MockCallbackTest, MockedCallSucceeds) {
222 CallbackServerContext ctx;
223 EchoRequest req;
224 EchoResponse resp;
225 DefaultReactorTestPeer peer(&ctx);
226
227 req.set_message("ha ha, consider yourself mocked.");
228 auto* reactor = service_.Echo(&ctx, &req, &resp);
229 EXPECT_EQ(reactor, peer.reactor());
230 EXPECT_TRUE(peer.test_status_set());
231 EXPECT_TRUE(peer.test_status().ok());
232 }
233
TEST_F(MockCallbackTest,MockedCallFails)234 TEST_F(MockCallbackTest, MockedCallFails) {
235 CallbackServerContext ctx;
236 EchoRequest req;
237 EchoResponse resp;
238 DefaultReactorTestPeer peer(&ctx);
239
240 auto* reactor = service_.Echo(&ctx, &req, &resp);
241 EXPECT_EQ(reactor, peer.reactor());
242 EXPECT_TRUE(peer.test_status_set());
243 EXPECT_EQ(peer.test_status().error_code(), StatusCode::INVALID_ARGUMENT);
244 }
245
246 class TestServiceImpl : public EchoTestService::Service {
247 public:
Echo(ServerContext *,const EchoRequest * request,EchoResponse * response)248 Status Echo(ServerContext* /*context*/, const EchoRequest* request,
249 EchoResponse* response) override {
250 response->set_message(request->message());
251 return Status::OK;
252 }
253
RequestStream(ServerContext *,ServerReader<EchoRequest> * reader,EchoResponse * response)254 Status RequestStream(ServerContext* /*context*/,
255 ServerReader<EchoRequest>* reader,
256 EchoResponse* response) override {
257 EchoRequest request;
258 std::string resp("");
259 while (reader->Read(&request)) {
260 gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
261 resp.append(request.message());
262 }
263 response->set_message(resp);
264 return Status::OK;
265 }
266
ResponseStream(ServerContext *,const EchoRequest * request,ServerWriter<EchoResponse> * writer)267 Status ResponseStream(ServerContext* /*context*/, const EchoRequest* request,
268 ServerWriter<EchoResponse>* writer) override {
269 EchoResponse response;
270 vector<std::string> tokens = split(request->message());
271 for (const std::string& token : tokens) {
272 response.set_message(token);
273 writer->Write(response);
274 }
275 return Status::OK;
276 }
277
BidiStream(ServerContext *,ServerReaderWriter<EchoResponse,EchoRequest> * stream)278 Status BidiStream(
279 ServerContext* /*context*/,
280 ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
281 EchoRequest request;
282 EchoResponse response;
283 while (stream->Read(&request)) {
284 gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
285 response.set_message(request.message());
286 stream->Write(response);
287 }
288 return Status::OK;
289 }
290
291 private:
split(const std::string & input)292 vector<std::string> split(const std::string& input) {
293 std::string buff("");
294 vector<std::string> result;
295
296 for (auto n : input) {
297 if (n != ' ') {
298 buff += n;
299 continue;
300 }
301 if (buff.empty()) continue;
302 result.push_back(buff);
303 buff = "";
304 }
305 if (!buff.empty()) result.push_back(buff);
306
307 return result;
308 }
309 };
310
311 class MockTest : public ::testing::Test {
312 protected:
MockTest()313 MockTest() {}
314
SetUp()315 void SetUp() override {
316 int port = grpc_pick_unused_port_or_die();
317 server_address_ << "localhost:" << port;
318 // Setup server
319 ServerBuilder builder;
320 builder.AddListeningPort(server_address_.str(),
321 InsecureServerCredentials());
322 builder.RegisterService(&service_);
323 server_ = builder.BuildAndStart();
324 }
325
TearDown()326 void TearDown() override { server_->Shutdown(); }
327
ResetStub()328 void ResetStub() {
329 std::shared_ptr<Channel> channel = grpc::CreateChannel(
330 server_address_.str(), InsecureChannelCredentials());
331 stub_ = grpc::testing::EchoTestService::NewStub(channel);
332 }
333
334 std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
335 std::unique_ptr<Server> server_;
336 std::ostringstream server_address_;
337 TestServiceImpl service_;
338 };
339
340 // Do one real rpc and one mocked one
TEST_F(MockTest,SimpleRpc)341 TEST_F(MockTest, SimpleRpc) {
342 ResetStub();
343 FakeClient client(stub_.get());
344 client.DoEcho();
345 MockEchoTestServiceStub stub;
346 EchoResponse resp;
347 resp.set_message("hello world");
348 EXPECT_CALL(stub, Echo(_, _, _))
349 .Times(AtLeast(1))
350 .WillOnce(DoAll(SetArgPointee<2>(resp), Return(Status::OK)));
351 client.ResetStub(&stub);
352 client.DoEcho();
353 }
354
TEST_F(MockTest,ClientStream)355 TEST_F(MockTest, ClientStream) {
356 ResetStub();
357 FakeClient client(stub_.get());
358 client.DoRequestStream();
359
360 MockEchoTestServiceStub stub;
361 auto w = new MockClientWriter<EchoRequest>();
362 EchoResponse resp;
363 resp.set_message("hello, world");
364
365 EXPECT_CALL(*w, Write(_, _)).Times(2).WillRepeatedly(Return(true));
366 EXPECT_CALL(*w, WritesDone());
367 EXPECT_CALL(*w, Finish()).WillOnce(Return(Status::OK));
368
369 EXPECT_CALL(stub, RequestStreamRaw(_, _))
370 .WillOnce(DoAll(SetArgPointee<1>(resp), Return(w)));
371 client.ResetStub(&stub);
372 client.DoRequestStream();
373 }
374
TEST_F(MockTest,ServerStream)375 TEST_F(MockTest, ServerStream) {
376 ResetStub();
377 FakeClient client(stub_.get());
378 client.DoResponseStream();
379
380 MockEchoTestServiceStub stub;
381 auto r = new MockClientReader<EchoResponse>();
382 EchoResponse resp1;
383 resp1.set_message("hello");
384 EchoResponse resp2;
385 resp2.set_message("world");
386
387 EXPECT_CALL(*r, Read(_))
388 .WillOnce(DoAll(SetArgPointee<0>(resp1), Return(true)))
389 .WillOnce(DoAll(SetArgPointee<0>(resp2), Return(true)))
390 .WillOnce(Return(false));
391 EXPECT_CALL(*r, Finish()).WillOnce(Return(Status::OK));
392
393 EXPECT_CALL(stub, ResponseStreamRaw(_, _)).WillOnce(Return(r));
394
395 client.ResetStub(&stub);
396 client.DoResponseStream();
397 }
398
ACTION_P(copy,msg)399 ACTION_P(copy, msg) { arg0->set_message(msg->message()); }
400
TEST_F(MockTest,BidiStream)401 TEST_F(MockTest, BidiStream) {
402 ResetStub();
403 FakeClient client(stub_.get());
404 client.DoBidiStream();
405 MockEchoTestServiceStub stub;
406 auto rw = new MockClientReaderWriter<EchoRequest, EchoResponse>();
407 EchoRequest msg;
408
409 EXPECT_CALL(*rw, Write(_, _))
410 .Times(3)
411 .WillRepeatedly(DoAll(SaveArg<0>(&msg), Return(true)));
412 EXPECT_CALL(*rw, Read(_))
413 .WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
414 .WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
415 .WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
416 .WillOnce(Return(false));
417 EXPECT_CALL(*rw, WritesDone());
418 EXPECT_CALL(*rw, Finish()).WillOnce(Return(Status::OK));
419
420 EXPECT_CALL(stub, BidiStreamRaw(_)).WillOnce(Return(rw));
421 client.ResetStub(&stub);
422 client.DoBidiStream();
423 }
424
425 } // namespace
426 } // namespace testing
427 } // namespace grpc
428
main(int argc,char ** argv)429 int main(int argc, char** argv) {
430 grpc::testing::TestEnvironment env(argc, argv);
431 ::testing::InitGoogleTest(&argc, argv);
432 return RUN_ALL_TESTS();
433 }
434