• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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