1 /*
2 *
3 * Copyright 2016 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 "test/cpp/util/grpc_tool.h"
20
21 #include <sstream>
22
23 #include <gflags/gflags.h>
24 #include <grpc/grpc.h>
25 #include <grpc/support/alloc.h>
26 #include <grpcpp/channel.h>
27 #include <grpcpp/client_context.h>
28 #include <grpcpp/create_channel.h>
29 #include <grpcpp/ext/proto_server_reflection_plugin.h>
30 #include <grpcpp/server.h>
31 #include <grpcpp/server_builder.h>
32 #include <grpcpp/server_context.h>
33 #include <gtest/gtest.h>
34
35 #include "src/core/lib/gpr/env.h"
36 #include "src/proto/grpc/testing/echo.grpc.pb.h"
37 #include "src/proto/grpc/testing/echo.pb.h"
38 #include "test/core/end2end/data/ssl_test_data.h"
39 #include "test/core/util/port.h"
40 #include "test/core/util/test_config.h"
41 #include "test/cpp/util/cli_credentials.h"
42 #include "test/cpp/util/string_ref_helper.h"
43
44 using grpc::testing::EchoRequest;
45 using grpc::testing::EchoResponse;
46
47 #define USAGE_REGEX "( grpc_cli .+\n){2,10}"
48
49 #define ECHO_TEST_SERVICE_SUMMARY \
50 "Echo\n" \
51 "RequestStream\n" \
52 "ResponseStream\n" \
53 "BidiStream\n" \
54 "Unimplemented\n"
55
56 #define ECHO_TEST_SERVICE_DESCRIPTION \
57 "filename: src/proto/grpc/testing/echo.proto\n" \
58 "package: grpc.testing;\n" \
59 "service EchoTestService {\n" \
60 " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
61 "{}\n" \
62 " rpc RequestStream(stream grpc.testing.EchoRequest) returns " \
63 "(grpc.testing.EchoResponse) {}\n" \
64 " rpc ResponseStream(grpc.testing.EchoRequest) returns (stream " \
65 "grpc.testing.EchoResponse) {}\n" \
66 " rpc BidiStream(stream grpc.testing.EchoRequest) returns (stream " \
67 "grpc.testing.EchoResponse) {}\n" \
68 " rpc Unimplemented(grpc.testing.EchoRequest) returns " \
69 "(grpc.testing.EchoResponse) {}\n" \
70 "}\n" \
71 "\n"
72
73 #define ECHO_METHOD_DESCRIPTION \
74 " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
75 "{}\n"
76
77 #define ECHO_RESPONSE_MESSAGE \
78 "message: \"echo\"\n" \
79 "param {\n" \
80 " host: \"localhost\"\n" \
81 " peer: \"peer\"\n" \
82 "}\n\n"
83
84 DECLARE_string(channel_creds_type);
85 DECLARE_string(ssl_target);
86
87 namespace grpc {
88 namespace testing {
89
90 DECLARE_bool(binary_input);
91 DECLARE_bool(binary_output);
92 DECLARE_bool(l);
93 DECLARE_bool(batch);
94 DECLARE_string(metadata);
95 DECLARE_string(protofiles);
96 DECLARE_string(proto_path);
97
98 namespace {
99
100 const int kServerDefaultResponseStreamsToSend = 3;
101
102 class TestCliCredentials final : public grpc::testing::CliCredentials {
103 public:
TestCliCredentials(bool secure=false)104 TestCliCredentials(bool secure = false) : secure_(secure) {}
GetChannelCredentials() const105 std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials()
106 const override {
107 if (!secure_) {
108 return InsecureChannelCredentials();
109 }
110 SslCredentialsOptions ssl_opts = {test_root_cert, "", ""};
111 return SslCredentials(grpc::SslCredentialsOptions(ssl_opts));
112 }
GetCredentialUsage() const113 const grpc::string GetCredentialUsage() const override { return ""; }
114
115 private:
116 const bool secure_;
117 };
118
PrintStream(std::stringstream * ss,const grpc::string & output)119 bool PrintStream(std::stringstream* ss, const grpc::string& output) {
120 (*ss) << output;
121 return true;
122 }
123
124 template <typename T>
ArraySize(T & a)125 size_t ArraySize(T& a) {
126 return ((sizeof(a) / sizeof(*(a))) /
127 static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
128 }
129
130 class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
131 public:
Echo(ServerContext * context,const EchoRequest * request,EchoResponse * response)132 Status Echo(ServerContext* context, const EchoRequest* request,
133 EchoResponse* response) override {
134 if (!context->client_metadata().empty()) {
135 for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
136 iter = context->client_metadata().begin();
137 iter != context->client_metadata().end(); ++iter) {
138 context->AddInitialMetadata(ToString(iter->first),
139 ToString(iter->second));
140 }
141 }
142 context->AddTrailingMetadata("trailing_key", "trailing_value");
143 response->set_message(request->message());
144 return Status::OK;
145 }
146
RequestStream(ServerContext * context,ServerReader<EchoRequest> * reader,EchoResponse * response)147 Status RequestStream(ServerContext* context,
148 ServerReader<EchoRequest>* reader,
149 EchoResponse* response) override {
150 EchoRequest request;
151 response->set_message("");
152 if (!context->client_metadata().empty()) {
153 for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
154 iter = context->client_metadata().begin();
155 iter != context->client_metadata().end(); ++iter) {
156 context->AddInitialMetadata(ToString(iter->first),
157 ToString(iter->second));
158 }
159 }
160 context->AddTrailingMetadata("trailing_key", "trailing_value");
161 while (reader->Read(&request)) {
162 response->mutable_message()->append(request.message());
163 }
164
165 return Status::OK;
166 }
167
ResponseStream(ServerContext * context,const EchoRequest * request,ServerWriter<EchoResponse> * writer)168 Status ResponseStream(ServerContext* context, const EchoRequest* request,
169 ServerWriter<EchoResponse>* writer) override {
170 if (!context->client_metadata().empty()) {
171 for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
172 iter = context->client_metadata().begin();
173 iter != context->client_metadata().end(); ++iter) {
174 context->AddInitialMetadata(ToString(iter->first),
175 ToString(iter->second));
176 }
177 }
178 context->AddTrailingMetadata("trailing_key", "trailing_value");
179
180 EchoResponse response;
181 for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
182 response.set_message(request->message() + grpc::to_string(i));
183 writer->Write(response);
184 }
185
186 return Status::OK;
187 }
188
BidiStream(ServerContext * context,ServerReaderWriter<EchoResponse,EchoRequest> * stream)189 Status BidiStream(
190 ServerContext* context,
191 ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
192 EchoRequest request;
193 EchoResponse response;
194 if (!context->client_metadata().empty()) {
195 for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
196 iter = context->client_metadata().begin();
197 iter != context->client_metadata().end(); ++iter) {
198 context->AddInitialMetadata(ToString(iter->first),
199 ToString(iter->second));
200 }
201 }
202 context->AddTrailingMetadata("trailing_key", "trailing_value");
203
204 while (stream->Read(&request)) {
205 response.set_message(request.message());
206 stream->Write(response);
207 }
208
209 return Status::OK;
210 }
211 };
212
213 } // namespace
214
215 class GrpcToolTest : public ::testing::Test {
216 protected:
GrpcToolTest()217 GrpcToolTest() {}
218
219 // SetUpServer cannot be used with EXPECT_EXIT. grpc_pick_unused_port_or_die()
220 // uses atexit() to free chosen ports, and it will spawn a new thread in
221 // resolve_address_posix.c:192 at exit time.
SetUpServer(bool secure=false)222 const grpc::string SetUpServer(bool secure = false) {
223 std::ostringstream server_address;
224 int port = grpc_pick_unused_port_or_die();
225 server_address << "localhost:" << port;
226 // Setup server
227 ServerBuilder builder;
228 std::shared_ptr<grpc::ServerCredentials> creds;
229 if (secure) {
230 SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
231 test_server1_cert};
232 SslServerCredentialsOptions ssl_opts;
233 ssl_opts.pem_root_certs = "";
234 ssl_opts.pem_key_cert_pairs.push_back(pkcp);
235 creds = SslServerCredentials(ssl_opts);
236 } else {
237 creds = InsecureServerCredentials();
238 }
239 builder.AddListeningPort(server_address.str(), creds);
240 builder.RegisterService(&service_);
241 server_ = builder.BuildAndStart();
242 return server_address.str();
243 }
244
ShutdownServer()245 void ShutdownServer() { server_->Shutdown(); }
246
ExitWhenError(int argc,const char ** argv,const CliCredentials & cred,GrpcToolOutputCallback callback)247 void ExitWhenError(int argc, const char** argv, const CliCredentials& cred,
248 GrpcToolOutputCallback callback) {
249 int result = GrpcToolMainLib(argc, argv, cred, callback);
250 if (result) {
251 exit(result);
252 }
253 }
254
255 std::unique_ptr<Server> server_;
256 TestServiceImpl service_;
257 reflection::ProtoServerReflectionPlugin plugin_;
258 };
259
TEST_F(GrpcToolTest,NoCommand)260 TEST_F(GrpcToolTest, NoCommand) {
261 // Test input "grpc_cli"
262 std::stringstream output_stream;
263 const char* argv[] = {"grpc_cli"};
264 // Exit with 1, print usage instruction in stderr
265 EXPECT_EXIT(
266 GrpcToolMainLib(
267 ArraySize(argv), argv, TestCliCredentials(),
268 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
269 ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
270 // No output
271 EXPECT_TRUE(0 == output_stream.tellp());
272 }
273
TEST_F(GrpcToolTest,InvalidCommand)274 TEST_F(GrpcToolTest, InvalidCommand) {
275 // Test input "grpc_cli"
276 std::stringstream output_stream;
277 const char* argv[] = {"grpc_cli", "abc"};
278 // Exit with 1, print usage instruction in stderr
279 EXPECT_EXIT(
280 GrpcToolMainLib(
281 ArraySize(argv), argv, TestCliCredentials(),
282 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
283 ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
284 // No output
285 EXPECT_TRUE(0 == output_stream.tellp());
286 }
287
TEST_F(GrpcToolTest,HelpCommand)288 TEST_F(GrpcToolTest, HelpCommand) {
289 // Test input "grpc_cli help"
290 std::stringstream output_stream;
291 const char* argv[] = {"grpc_cli", "help"};
292 // Exit with 1, print usage instruction in stderr
293 EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
294 std::bind(PrintStream, &output_stream,
295 std::placeholders::_1)),
296 ::testing::ExitedWithCode(1), USAGE_REGEX);
297 // No output
298 EXPECT_TRUE(0 == output_stream.tellp());
299 }
300
TEST_F(GrpcToolTest,ListCommand)301 TEST_F(GrpcToolTest, ListCommand) {
302 // Test input "grpc_cli list localhost:<port>"
303 std::stringstream output_stream;
304
305 const grpc::string server_address = SetUpServer();
306 const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
307
308 FLAGS_l = false;
309 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
310 std::bind(PrintStream, &output_stream,
311 std::placeholders::_1)));
312 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
313 "grpc.testing.EchoTestService\n"
314 "grpc.reflection.v1alpha.ServerReflection\n"));
315
316 ShutdownServer();
317 }
318
TEST_F(GrpcToolTest,ListOneService)319 TEST_F(GrpcToolTest, ListOneService) {
320 // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
321 std::stringstream output_stream;
322
323 const grpc::string server_address = SetUpServer();
324 const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
325 "grpc.testing.EchoTestService"};
326 // without -l flag
327 FLAGS_l = false;
328 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
329 std::bind(PrintStream, &output_stream,
330 std::placeholders::_1)));
331 // Expected output: ECHO_TEST_SERVICE_SUMMARY
332 EXPECT_TRUE(0 ==
333 strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_SUMMARY));
334
335 // with -l flag
336 output_stream.str(grpc::string());
337 output_stream.clear();
338 FLAGS_l = true;
339 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
340 std::bind(PrintStream, &output_stream,
341 std::placeholders::_1)));
342 // Expected output: ECHO_TEST_SERVICE_DESCRIPTION
343 EXPECT_TRUE(
344 0 == strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_DESCRIPTION));
345
346 ShutdownServer();
347 }
348
TEST_F(GrpcToolTest,TypeCommand)349 TEST_F(GrpcToolTest, TypeCommand) {
350 // Test input "grpc_cli type localhost:<port> grpc.testing.EchoRequest"
351 std::stringstream output_stream;
352
353 const grpc::string server_address = SetUpServer();
354 const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
355 "grpc.testing.EchoRequest"};
356
357 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
358 std::bind(PrintStream, &output_stream,
359 std::placeholders::_1)));
360 const grpc::protobuf::Descriptor* desc =
361 grpc::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(
362 "grpc.testing.EchoRequest");
363 // Expected output: the DebugString of grpc.testing.EchoRequest
364 EXPECT_TRUE(0 ==
365 strcmp(output_stream.str().c_str(), desc->DebugString().c_str()));
366
367 ShutdownServer();
368 }
369
TEST_F(GrpcToolTest,ListOneMethod)370 TEST_F(GrpcToolTest, ListOneMethod) {
371 // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
372 std::stringstream output_stream;
373
374 const grpc::string server_address = SetUpServer();
375 const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
376 "grpc.testing.EchoTestService.Echo"};
377 // without -l flag
378 FLAGS_l = false;
379 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
380 std::bind(PrintStream, &output_stream,
381 std::placeholders::_1)));
382 // Expected output: "Echo"
383 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), "Echo\n"));
384
385 // with -l flag
386 output_stream.str(grpc::string());
387 output_stream.clear();
388 FLAGS_l = true;
389 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
390 std::bind(PrintStream, &output_stream,
391 std::placeholders::_1)));
392 // Expected output: ECHO_METHOD_DESCRIPTION
393 EXPECT_TRUE(0 ==
394 strcmp(output_stream.str().c_str(), ECHO_METHOD_DESCRIPTION));
395
396 ShutdownServer();
397 }
398
TEST_F(GrpcToolTest,TypeNotFound)399 TEST_F(GrpcToolTest, TypeNotFound) {
400 // Test input "grpc_cli type localhost:<port> grpc.testing.DummyRequest"
401 std::stringstream output_stream;
402
403 const grpc::string server_address = SetUpServer();
404 const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
405 "grpc.testing.DummyRequest"};
406
407 EXPECT_DEATH(ExitWhenError(ArraySize(argv), argv, TestCliCredentials(),
408 std::bind(PrintStream, &output_stream,
409 std::placeholders::_1)),
410 ".*Type grpc.testing.DummyRequest not found.*");
411
412 ShutdownServer();
413 }
414
TEST_F(GrpcToolTest,CallCommand)415 TEST_F(GrpcToolTest, CallCommand) {
416 // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
417 std::stringstream output_stream;
418
419 const grpc::string server_address = SetUpServer();
420 const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
421 "message: 'Hello'"};
422
423 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
424 std::bind(PrintStream, &output_stream,
425 std::placeholders::_1)));
426 // Expected output: "message: \"Hello\""
427 EXPECT_TRUE(nullptr !=
428 strstr(output_stream.str().c_str(), "message: \"Hello\""));
429 ShutdownServer();
430 }
431
TEST_F(GrpcToolTest,CallCommandBatch)432 TEST_F(GrpcToolTest, CallCommandBatch) {
433 // Test input "grpc_cli call Echo"
434 std::stringstream output_stream;
435
436 const grpc::string server_address = SetUpServer();
437 const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
438 "message: 'Hello0'"};
439
440 // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
441 std::streambuf* orig = std::cin.rdbuf();
442 std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
443 std::cin.rdbuf(ss.rdbuf());
444
445 FLAGS_batch = true;
446 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
447 std::bind(PrintStream, &output_stream,
448 std::placeholders::_1)));
449 FLAGS_batch = false;
450
451 // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
452 // "Hello2"\n"
453 EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
454 "message: \"Hello0\"\nmessage: "
455 "\"Hello1\"\nmessage: \"Hello2\"\n"));
456 std::cin.rdbuf(orig);
457 ShutdownServer();
458 }
459
TEST_F(GrpcToolTest,CallCommandBatchWithBadRequest)460 TEST_F(GrpcToolTest, CallCommandBatchWithBadRequest) {
461 // Test input "grpc_cli call Echo"
462 std::stringstream output_stream;
463
464 const grpc::string server_address = SetUpServer();
465 const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
466 "message: 'Hello0'"};
467
468 // Mock std::cin input "message: 1\n\n message: 'Hello2'\n\n"
469 std::streambuf* orig = std::cin.rdbuf();
470 std::istringstream ss("message: 1\n\n message: 'Hello2'\n\n");
471 std::cin.rdbuf(ss.rdbuf());
472
473 FLAGS_batch = true;
474 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
475 std::bind(PrintStream, &output_stream,
476 std::placeholders::_1)));
477 FLAGS_batch = false;
478
479 // Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
480 EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
481 "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
482 std::cin.rdbuf(orig);
483 ShutdownServer();
484 }
485
TEST_F(GrpcToolTest,CallCommandRequestStream)486 TEST_F(GrpcToolTest, CallCommandRequestStream) {
487 // Test input: grpc_cli call localhost:<port> RequestStream "message:
488 // 'Hello0'"
489 std::stringstream output_stream;
490
491 const grpc::string server_address = SetUpServer();
492 const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
493 "RequestStream", "message: 'Hello0'"};
494
495 // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
496 std::streambuf* orig = std::cin.rdbuf();
497 std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
498 std::cin.rdbuf(ss.rdbuf());
499
500 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
501 std::bind(PrintStream, &output_stream,
502 std::placeholders::_1)));
503
504 // Expected output: "message: \"Hello0Hello1Hello2\""
505 EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
506 "message: \"Hello0Hello1Hello2\""));
507 std::cin.rdbuf(orig);
508 ShutdownServer();
509 }
510
TEST_F(GrpcToolTest,CallCommandRequestStreamWithBadRequest)511 TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) {
512 // Test input: grpc_cli call localhost:<port> RequestStream "message:
513 // 'Hello0'"
514 std::stringstream output_stream;
515
516 const grpc::string server_address = SetUpServer();
517 const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
518 "RequestStream", "message: 'Hello0'"};
519
520 // Mock std::cin input "bad_field: 'Hello1'\n\n message: 'Hello2'\n\n"
521 std::streambuf* orig = std::cin.rdbuf();
522 std::istringstream ss("bad_field: 'Hello1'\n\n message: 'Hello2'\n\n");
523 std::cin.rdbuf(ss.rdbuf());
524
525 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
526 std::bind(PrintStream, &output_stream,
527 std::placeholders::_1)));
528
529 // Expected output: "message: \"Hello0Hello2\""
530 EXPECT_TRUE(nullptr !=
531 strstr(output_stream.str().c_str(), "message: \"Hello0Hello2\""));
532 std::cin.rdbuf(orig);
533 ShutdownServer();
534 }
535
TEST_F(GrpcToolTest,CallCommandResponseStream)536 TEST_F(GrpcToolTest, CallCommandResponseStream) {
537 // Test input: grpc_cli call localhost:<port> ResponseStream "message:
538 // 'Hello'"
539 std::stringstream output_stream;
540
541 const grpc::string server_address = SetUpServer();
542 const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
543 "ResponseStream", "message: 'Hello'"};
544
545 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
546 std::bind(PrintStream, &output_stream,
547 std::placeholders::_1)));
548
549 // Expected output: "message: \"Hello{n}\""
550 for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
551 grpc::string expected_response_text =
552 "message: \"Hello" + grpc::to_string(i) + "\"\n";
553 EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
554 expected_response_text.c_str()));
555 }
556
557 ShutdownServer();
558 }
559
TEST_F(GrpcToolTest,CallCommandBidiStream)560 TEST_F(GrpcToolTest, CallCommandBidiStream) {
561 // Test input: grpc_cli call localhost:<port> BidiStream "message: 'Hello0'"
562 std::stringstream output_stream;
563
564 const grpc::string server_address = SetUpServer();
565 const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
566 "BidiStream", "message: 'Hello0'"};
567
568 // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
569 std::streambuf* orig = std::cin.rdbuf();
570 std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
571 std::cin.rdbuf(ss.rdbuf());
572
573 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
574 std::bind(PrintStream, &output_stream,
575 std::placeholders::_1)));
576
577 // Expected output: "message: \"Hello0\"\nmessage: \"Hello1\"\nmessage:
578 // \"Hello2\"\n\n"
579 EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
580 "message: \"Hello0\"\nmessage: "
581 "\"Hello1\"\nmessage: \"Hello2\"\n"));
582 std::cin.rdbuf(orig);
583 ShutdownServer();
584 }
585
TEST_F(GrpcToolTest,CallCommandBidiStreamWithBadRequest)586 TEST_F(GrpcToolTest, CallCommandBidiStreamWithBadRequest) {
587 // Test input: grpc_cli call localhost:<port> BidiStream "message: 'Hello0'"
588 std::stringstream output_stream;
589
590 const grpc::string server_address = SetUpServer();
591 const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
592 "BidiStream", "message: 'Hello0'"};
593
594 // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
595 std::streambuf* orig = std::cin.rdbuf();
596 std::istringstream ss("message: 1.0\n\n message: 'Hello2'\n\n");
597 std::cin.rdbuf(ss.rdbuf());
598
599 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
600 std::bind(PrintStream, &output_stream,
601 std::placeholders::_1)));
602
603 // Expected output: "message: \"Hello0\"\nmessage: \"Hello1\"\nmessage:
604 // \"Hello2\"\n\n"
605 EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
606 "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
607 std::cin.rdbuf(orig);
608
609 ShutdownServer();
610 }
611
TEST_F(GrpcToolTest,ParseCommand)612 TEST_F(GrpcToolTest, ParseCommand) {
613 // Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
614 // ECHO_RESPONSE_MESSAGE"
615 std::stringstream output_stream;
616 std::stringstream binary_output_stream;
617
618 const grpc::string server_address = SetUpServer();
619 const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
620 "grpc.testing.EchoResponse", ECHO_RESPONSE_MESSAGE};
621
622 FLAGS_binary_input = false;
623 FLAGS_binary_output = false;
624 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
625 std::bind(PrintStream, &output_stream,
626 std::placeholders::_1)));
627 // Expected output: ECHO_RESPONSE_MESSAGE
628 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE));
629
630 // Parse text message to binary message and then parse it back to text message
631 output_stream.str(grpc::string());
632 output_stream.clear();
633 FLAGS_binary_output = true;
634 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
635 std::bind(PrintStream, &output_stream,
636 std::placeholders::_1)));
637 grpc::string binary_data = output_stream.str();
638 output_stream.str(grpc::string());
639 output_stream.clear();
640 argv[4] = binary_data.c_str();
641 FLAGS_binary_input = true;
642 FLAGS_binary_output = false;
643 EXPECT_TRUE(0 == GrpcToolMainLib(5, argv, TestCliCredentials(),
644 std::bind(PrintStream, &output_stream,
645 std::placeholders::_1)));
646
647 // Expected output: ECHO_RESPONSE_MESSAGE
648 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE));
649
650 FLAGS_binary_input = false;
651 FLAGS_binary_output = false;
652 ShutdownServer();
653 }
654
TEST_F(GrpcToolTest,TooFewArguments)655 TEST_F(GrpcToolTest, TooFewArguments) {
656 // Test input "grpc_cli call Echo"
657 std::stringstream output_stream;
658 const char* argv[] = {"grpc_cli", "call", "Echo"};
659
660 // Exit with 1
661 EXPECT_EXIT(
662 GrpcToolMainLib(
663 ArraySize(argv), argv, TestCliCredentials(),
664 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
665 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
666 // No output
667 EXPECT_TRUE(0 == output_stream.tellp());
668 }
669
TEST_F(GrpcToolTest,TooManyArguments)670 TEST_F(GrpcToolTest, TooManyArguments) {
671 // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
672 std::stringstream output_stream;
673 const char* argv[] = {"grpc_cli", "call", "localhost:10000",
674 "Echo", "Echo", "message: 'Hello'"};
675
676 // Exit with 1
677 EXPECT_EXIT(
678 GrpcToolMainLib(
679 ArraySize(argv), argv, TestCliCredentials(),
680 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
681 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
682 // No output
683 EXPECT_TRUE(0 == output_stream.tellp());
684 }
685
TEST_F(GrpcToolTest,CallCommandWithMetadata)686 TEST_F(GrpcToolTest, CallCommandWithMetadata) {
687 // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
688 const grpc::string server_address = SetUpServer();
689 const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
690 "message: 'Hello'"};
691
692 {
693 std::stringstream output_stream;
694 FLAGS_metadata = "key0:val0:key1:valq:key2:val2";
695 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
696 TestCliCredentials(),
697 std::bind(PrintStream, &output_stream,
698 std::placeholders::_1)));
699 // Expected output: "message: \"Hello\""
700 EXPECT_TRUE(nullptr !=
701 strstr(output_stream.str().c_str(), "message: \"Hello\""));
702 }
703
704 {
705 std::stringstream output_stream;
706 FLAGS_metadata = "key:val\\:val";
707 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
708 TestCliCredentials(),
709 std::bind(PrintStream, &output_stream,
710 std::placeholders::_1)));
711 // Expected output: "message: \"Hello\""
712 EXPECT_TRUE(nullptr !=
713 strstr(output_stream.str().c_str(), "message: \"Hello\""));
714 }
715
716 {
717 std::stringstream output_stream;
718 FLAGS_metadata = "key:val\\\\val";
719 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
720 TestCliCredentials(),
721 std::bind(PrintStream, &output_stream,
722 std::placeholders::_1)));
723 // Expected output: "message: \"Hello\""
724 EXPECT_TRUE(nullptr !=
725 strstr(output_stream.str().c_str(), "message: \"Hello\""));
726 }
727
728 FLAGS_metadata = "";
729 ShutdownServer();
730 }
731
TEST_F(GrpcToolTest,CallCommandWithBadMetadata)732 TEST_F(GrpcToolTest, CallCommandWithBadMetadata) {
733 // Test input "grpc_cli call localhost:10000 Echo "message: 'Hello'"
734 const char* argv[] = {"grpc_cli", "call", "localhost:10000", "Echo",
735 "message: 'Hello'"};
736 FLAGS_protofiles = "src/proto/grpc/testing/echo.proto";
737 char* test_srcdir = gpr_getenv("TEST_SRCDIR");
738 if (test_srcdir != nullptr) {
739 FLAGS_proto_path = test_srcdir + std::string("/com_github_grpc_grpc");
740 }
741
742 {
743 std::stringstream output_stream;
744 FLAGS_metadata = "key0:val0:key1";
745 // Exit with 1
746 EXPECT_EXIT(
747 GrpcToolMainLib(
748 ArraySize(argv), argv, TestCliCredentials(),
749 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
750 ::testing::ExitedWithCode(1), ".*Failed to parse metadata flag.*");
751 }
752
753 {
754 std::stringstream output_stream;
755 FLAGS_metadata = "key:val\\val";
756 // Exit with 1
757 EXPECT_EXIT(
758 GrpcToolMainLib(
759 ArraySize(argv), argv, TestCliCredentials(),
760 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
761 ::testing::ExitedWithCode(1), ".*Failed to parse metadata flag.*");
762 }
763
764 FLAGS_metadata = "";
765 FLAGS_protofiles = "";
766
767 gpr_free(test_srcdir);
768 }
769
TEST_F(GrpcToolTest,ListCommand_OverrideSslHostName)770 TEST_F(GrpcToolTest, ListCommand_OverrideSslHostName) {
771 const grpc::string server_address = SetUpServer(true);
772
773 // Test input "grpc_cli ls localhost:<port> --channel_creds_type=ssl
774 // --ssl_target=z.test.google.fr"
775 std::stringstream output_stream;
776 const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
777 FLAGS_l = false;
778 FLAGS_channel_creds_type = "ssl";
779 FLAGS_ssl_target = "z.test.google.fr";
780 EXPECT_TRUE(
781 0 == GrpcToolMainLib(
782 ArraySize(argv), argv, TestCliCredentials(true),
783 std::bind(PrintStream, &output_stream, std::placeholders::_1)));
784 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
785 "grpc.testing.EchoTestService\n"
786 "grpc.reflection.v1alpha.ServerReflection\n"));
787
788 FLAGS_channel_creds_type = "";
789 FLAGS_ssl_target = "";
790 ShutdownServer();
791 }
792
793 } // namespace testing
794 } // namespace grpc
795
main(int argc,char ** argv)796 int main(int argc, char** argv) {
797 grpc_test_init(argc, argv);
798 ::testing::InitGoogleTest(&argc, argv);
799 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
800 return RUN_ALL_TESTS();
801 }
802