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 <chrono>
22 #include <sstream>
23 
24 #include <gtest/gtest.h>
25 
26 #include "absl/flags/declare.h"
27 #include "absl/flags/flag.h"
28 
29 #include <grpc/grpc.h>
30 #include <grpc/support/alloc.h>
31 #include <grpcpp/channel.h>
32 #include <grpcpp/client_context.h>
33 #include <grpcpp/create_channel.h>
34 #include <grpcpp/ext/proto_server_reflection_plugin.h>
35 #include <grpcpp/server.h>
36 #include <grpcpp/server_builder.h>
37 #include <grpcpp/server_context.h>
38 
39 #include "src/core/lib/gpr/env.h"
40 #include "src/core/lib/iomgr/load_file.h"
41 #include "src/proto/grpc/testing/echo.grpc.pb.h"
42 #include "src/proto/grpc/testing/echo.pb.h"
43 #include "test/core/util/port.h"
44 #include "test/core/util/test_config.h"
45 #include "test/cpp/util/cli_credentials.h"
46 #include "test/cpp/util/string_ref_helper.h"
47 #include "test/cpp/util/test_config.h"
48 
49 #define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
50 #define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
51 #define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
52 
53 using grpc::testing::EchoRequest;
54 using grpc::testing::EchoResponse;
55 
56 #define USAGE_REGEX "(  grpc_cli .+\n){2,10}"
57 
58 #define ECHO_TEST_SERVICE_SUMMARY \
59   "Echo\n"                        \
60   "Echo1\n"                       \
61   "Echo2\n"                       \
62   "CheckDeadlineUpperBound\n"     \
63   "CheckDeadlineSet\n"            \
64   "CheckClientInitialMetadata\n"  \
65   "RequestStream\n"               \
66   "ResponseStream\n"              \
67   "BidiStream\n"                  \
68   "Unimplemented\n"               \
69   "UnimplementedBidi\n"
70 
71 #define ECHO_TEST_SERVICE_DESCRIPTION                                          \
72   "filename: src/proto/grpc/testing/echo.proto\n"                              \
73   "package: grpc.testing;\n"                                                   \
74   "service EchoTestService {\n"                                                \
75   "  rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) "  \
76   "{}\n"                                                                       \
77   "  rpc Echo1(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
78   "{}\n"                                                                       \
79   "  rpc Echo2(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
80   "{}\n"                                                                       \
81   "  rpc CheckDeadlineUpperBound(grpc.testing.SimpleRequest) returns "         \
82   "(grpc.testing.StringValue) {}\n"                                            \
83   "  rpc CheckDeadlineSet(grpc.testing.SimpleRequest) returns "                \
84   "(grpc.testing.StringValue) {}\n"                                            \
85   "  rpc CheckClientInitialMetadata(grpc.testing.SimpleRequest) returns "      \
86   "(grpc.testing.SimpleResponse) {}\n"                                         \
87   "  rpc RequestStream(stream grpc.testing.EchoRequest) returns "              \
88   "(grpc.testing.EchoResponse) {}\n"                                           \
89   "  rpc ResponseStream(grpc.testing.EchoRequest) returns (stream "            \
90   "grpc.testing.EchoResponse) {}\n"                                            \
91   "  rpc BidiStream(stream grpc.testing.EchoRequest) returns (stream "         \
92   "grpc.testing.EchoResponse) {}\n"                                            \
93   "  rpc Unimplemented(grpc.testing.EchoRequest) returns "                     \
94   "(grpc.testing.EchoResponse) {}\n"                                           \
95   "  rpc UnimplementedBidi(stream grpc.testing.EchoRequest) returns (stream "  \
96   "grpc.testing.EchoResponse) {}\n"                                            \
97   "}\n"                                                                        \
98   "\n"
99 
100 #define ECHO_METHOD_DESCRIPTION                                               \
101   "  rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
102   "{}\n"
103 
104 #define ECHO_RESPONSE_MESSAGE_TEXT_FORMAT \
105   "message: \"echo\"\n"                   \
106   "param {\n"                             \
107   "  host: \"localhost\"\n"               \
108   "  peer: \"peer\"\n"                    \
109   "}\n\n"
110 
111 #define ECHO_RESPONSE_MESSAGE_JSON_FORMAT \
112   "{\n"                                   \
113   " \"message\": \"echo\",\n"             \
114   " \"param\": {\n"                       \
115   "  \"host\": \"localhost\",\n"          \
116   "  \"peer\": \"peer\"\n"                \
117   " }\n"                                  \
118   "}\n\n"
119 
120 ABSL_DECLARE_FLAG(std::string, channel_creds_type);
121 ABSL_DECLARE_FLAG(std::string, ssl_target);
122 ABSL_DECLARE_FLAG(bool, binary_input);
123 ABSL_DECLARE_FLAG(bool, binary_output);
124 ABSL_DECLARE_FLAG(bool, json_input);
125 ABSL_DECLARE_FLAG(bool, json_output);
126 ABSL_DECLARE_FLAG(bool, l);
127 ABSL_DECLARE_FLAG(bool, batch);
128 ABSL_DECLARE_FLAG(std::string, metadata);
129 ABSL_DECLARE_FLAG(std::string, protofiles);
130 ABSL_DECLARE_FLAG(std::string, proto_path);
131 ABSL_DECLARE_FLAG(std::string, default_service_config);
132 ABSL_DECLARE_FLAG(double, timeout);
133 
134 namespace grpc {
135 namespace testing {
136 namespace {
137 
138 const int kServerDefaultResponseStreamsToSend = 3;
139 
140 class TestCliCredentials final : public grpc::testing::CliCredentials {
141  public:
TestCliCredentials(bool secure=false)142   explicit TestCliCredentials(bool secure = false) : secure_(secure) {}
GetChannelCredentials() const143   std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials()
144       const override {
145     if (!secure_) {
146       return InsecureChannelCredentials();
147     }
148     grpc_slice ca_slice;
149     GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
150                                  grpc_load_file(CA_CERT_PATH, 1, &ca_slice)));
151     const char* test_root_cert =
152         reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
153     SslCredentialsOptions ssl_opts = {test_root_cert, "", ""};
154     std::shared_ptr<grpc::ChannelCredentials> credential_ptr =
155         grpc::SslCredentials(grpc::SslCredentialsOptions(ssl_opts));
156     grpc_slice_unref(ca_slice);
157     return credential_ptr;
158   }
GetCredentialUsage() const159   std::string GetCredentialUsage() const override { return ""; }
160 
161  private:
162   const bool secure_;
163 };
164 
PrintStream(std::stringstream * ss,const std::string & output)165 bool PrintStream(std::stringstream* ss, const std::string& output) {
166   (*ss) << output;
167   return true;
168 }
169 
170 template <typename T>
ArraySize(T & a)171 size_t ArraySize(T& a) {
172   return ((sizeof(a) / sizeof(*(a))) /
173           static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
174 }
175 
176 class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
177  public:
Echo(ServerContext * context,const EchoRequest * request,EchoResponse * response)178   Status Echo(ServerContext* context, const EchoRequest* request,
179               EchoResponse* response) override {
180     if (!context->client_metadata().empty()) {
181       for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
182                iter = context->client_metadata().begin();
183            iter != context->client_metadata().end(); ++iter) {
184         context->AddInitialMetadata(ToString(iter->first),
185                                     ToString(iter->second));
186       }
187     }
188     context->AddTrailingMetadata("trailing_key", "trailing_value");
189     response->set_message(request->message());
190     return Status::OK;
191   }
192 
CheckDeadlineSet(ServerContext * context,const SimpleRequest *,StringValue * response)193   Status CheckDeadlineSet(ServerContext* context,
194                           const SimpleRequest* /*request*/,
195                           StringValue* response) override {
196     response->set_message(context->deadline() !=
197                                   std::chrono::system_clock::time_point::max()
198                               ? "true"
199                               : "false");
200     return Status::OK;
201   }
202 
203   // Check if deadline - current time <= timeout
204   // If deadline set, timeout + current time should be an upper bound for it
CheckDeadlineUpperBound(ServerContext * context,const SimpleRequest *,StringValue * response)205   Status CheckDeadlineUpperBound(ServerContext* context,
206                                  const SimpleRequest* /*request*/,
207                                  StringValue* response) override {
208     auto seconds = std::chrono::duration_cast<std::chrono::seconds>(
209         context->deadline() - std::chrono::system_clock::now());
210 
211     // Returning string instead of bool to avoid using embedded messages in
212     // proto3
213     response->set_message(
214         seconds.count() <= absl::GetFlag(FLAGS_timeout) ? "true" : "false");
215     return Status::OK;
216   }
217 
RequestStream(ServerContext * context,ServerReader<EchoRequest> * reader,EchoResponse * response)218   Status RequestStream(ServerContext* context,
219                        ServerReader<EchoRequest>* reader,
220                        EchoResponse* response) override {
221     EchoRequest request;
222     response->set_message("");
223     if (!context->client_metadata().empty()) {
224       for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
225                iter = context->client_metadata().begin();
226            iter != context->client_metadata().end(); ++iter) {
227         context->AddInitialMetadata(ToString(iter->first),
228                                     ToString(iter->second));
229       }
230     }
231     context->AddTrailingMetadata("trailing_key", "trailing_value");
232     while (reader->Read(&request)) {
233       response->mutable_message()->append(request.message());
234     }
235 
236     return Status::OK;
237   }
238 
ResponseStream(ServerContext * context,const EchoRequest * request,ServerWriter<EchoResponse> * writer)239   Status ResponseStream(ServerContext* context, const EchoRequest* request,
240                         ServerWriter<EchoResponse>* writer) override {
241     if (!context->client_metadata().empty()) {
242       for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
243                iter = context->client_metadata().begin();
244            iter != context->client_metadata().end(); ++iter) {
245         context->AddInitialMetadata(ToString(iter->first),
246                                     ToString(iter->second));
247       }
248     }
249     context->AddTrailingMetadata("trailing_key", "trailing_value");
250 
251     EchoResponse response;
252     for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
253       response.set_message(request->message() + std::to_string(i));
254       writer->Write(response);
255     }
256 
257     return Status::OK;
258   }
259 
BidiStream(ServerContext * context,ServerReaderWriter<EchoResponse,EchoRequest> * stream)260   Status BidiStream(
261       ServerContext* context,
262       ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
263     EchoRequest request;
264     EchoResponse response;
265     if (!context->client_metadata().empty()) {
266       for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
267                iter = context->client_metadata().begin();
268            iter != context->client_metadata().end(); ++iter) {
269         context->AddInitialMetadata(ToString(iter->first),
270                                     ToString(iter->second));
271       }
272     }
273     context->AddTrailingMetadata("trailing_key", "trailing_value");
274 
275     while (stream->Read(&request)) {
276       response.set_message(request.message());
277       stream->Write(response);
278     }
279 
280     return Status::OK;
281   }
282 };
283 
284 }  // namespace
285 
286 class GrpcToolTest : public ::testing::Test {
287  protected:
GrpcToolTest()288   GrpcToolTest() {}
289 
290   // SetUpServer cannot be used with EXPECT_EXIT. grpc_pick_unused_port_or_die()
291   // uses atexit() to free chosen ports, and it will spawn a new thread in
292   // resolve_address_posix.c:192 at exit time.
SetUpServer(bool secure=false)293   std::string SetUpServer(bool secure = false) {
294     std::ostringstream server_address;
295     int port = grpc_pick_unused_port_or_die();
296     server_address << "localhost:" << port;
297     // Setup server
298     ServerBuilder builder;
299     std::shared_ptr<grpc::ServerCredentials> creds;
300     grpc_slice cert_slice, key_slice;
301     GPR_ASSERT(GRPC_LOG_IF_ERROR(
302         "load_file", grpc_load_file(SERVER_CERT_PATH, 1, &cert_slice)));
303     GPR_ASSERT(GRPC_LOG_IF_ERROR(
304         "load_file", grpc_load_file(SERVER_KEY_PATH, 1, &key_slice)));
305     const char* server_cert =
306         reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
307     const char* server_key =
308         reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
309     SslServerCredentialsOptions::PemKeyCertPair pkcp = {server_key,
310                                                         server_cert};
311     if (secure) {
312       SslServerCredentialsOptions ssl_opts;
313       ssl_opts.pem_root_certs = "";
314       ssl_opts.pem_key_cert_pairs.push_back(pkcp);
315       creds = SslServerCredentials(ssl_opts);
316     } else {
317       creds = InsecureServerCredentials();
318     }
319     builder.AddListeningPort(server_address.str(), creds);
320     builder.RegisterService(&service_);
321     server_ = builder.BuildAndStart();
322     grpc_slice_unref(cert_slice);
323     grpc_slice_unref(key_slice);
324     return server_address.str();
325   }
326 
ShutdownServer()327   void ShutdownServer() { server_->Shutdown(); }
328 
329   std::unique_ptr<Server> server_;
330   TestServiceImpl service_;
331   reflection::ProtoServerReflectionPlugin plugin_;
332 };
333 
TEST_F(GrpcToolTest,NoCommand)334 TEST_F(GrpcToolTest, NoCommand) {
335   // Test input "grpc_cli"
336   std::stringstream output_stream;
337   const char* argv[] = {"grpc_cli"};
338   // Exit with 1, print usage instruction in stderr
339   EXPECT_EXIT(
340       GrpcToolMainLib(
341           ArraySize(argv), argv, TestCliCredentials(),
342           std::bind(PrintStream, &output_stream, std::placeholders::_1)),
343       ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
344   // No output
345   EXPECT_TRUE(0 == output_stream.tellp());
346 }
347 
TEST_F(GrpcToolTest,InvalidCommand)348 TEST_F(GrpcToolTest, InvalidCommand) {
349   // Test input "grpc_cli"
350   std::stringstream output_stream;
351   const char* argv[] = {"grpc_cli", "abc"};
352   // Exit with 1, print usage instruction in stderr
353   EXPECT_EXIT(
354       GrpcToolMainLib(
355           ArraySize(argv), argv, TestCliCredentials(),
356           std::bind(PrintStream, &output_stream, std::placeholders::_1)),
357       ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
358   // No output
359   EXPECT_TRUE(0 == output_stream.tellp());
360 }
361 
TEST_F(GrpcToolTest,HelpCommand)362 TEST_F(GrpcToolTest, HelpCommand) {
363   // Test input "grpc_cli help"
364   std::stringstream output_stream;
365   const char* argv[] = {"grpc_cli", "help"};
366   // Exit with 1, print usage instruction in stderr
367   EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
368                               std::bind(PrintStream, &output_stream,
369                                         std::placeholders::_1)),
370               ::testing::ExitedWithCode(1), USAGE_REGEX);
371   // No output
372   EXPECT_TRUE(0 == output_stream.tellp());
373 }
374 
TEST_F(GrpcToolTest,ListCommand)375 TEST_F(GrpcToolTest, ListCommand) {
376   // Test input "grpc_cli list localhost:<port>"
377   std::stringstream output_stream;
378 
379   const std::string server_address = SetUpServer();
380   const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
381 
382   absl::SetFlag(&FLAGS_l, false);
383   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
384                                    std::bind(PrintStream, &output_stream,
385                                              std::placeholders::_1)));
386   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
387                           "grpc.testing.EchoTestService\n"
388                           "grpc.reflection.v1alpha.ServerReflection\n"));
389 
390   ShutdownServer();
391 }
392 
TEST_F(GrpcToolTest,ListOneService)393 TEST_F(GrpcToolTest, ListOneService) {
394   // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
395   std::stringstream output_stream;
396 
397   const std::string server_address = SetUpServer();
398   const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
399                         "grpc.testing.EchoTestService"};
400   // without -l flag
401   absl::SetFlag(&FLAGS_l, false);
402   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
403                                    std::bind(PrintStream, &output_stream,
404                                              std::placeholders::_1)));
405   // Expected output: ECHO_TEST_SERVICE_SUMMARY
406   EXPECT_TRUE(0 ==
407               strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_SUMMARY));
408 
409   // with -l flag
410   output_stream.str(std::string());
411   output_stream.clear();
412   absl::SetFlag(&FLAGS_l, true);
413   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
414                                    std::bind(PrintStream, &output_stream,
415                                              std::placeholders::_1)));
416   // Expected output: ECHO_TEST_SERVICE_DESCRIPTION
417   EXPECT_TRUE(
418       0 == strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_DESCRIPTION));
419 
420   ShutdownServer();
421 }
422 
TEST_F(GrpcToolTest,TypeCommand)423 TEST_F(GrpcToolTest, TypeCommand) {
424   // Test input "grpc_cli type localhost:<port> grpc.testing.EchoRequest"
425   std::stringstream output_stream;
426 
427   const std::string server_address = SetUpServer();
428   const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
429                         "grpc.testing.EchoRequest"};
430 
431   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
432                                    std::bind(PrintStream, &output_stream,
433                                              std::placeholders::_1)));
434   const grpc::protobuf::Descriptor* desc =
435       grpc::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(
436           "grpc.testing.EchoRequest");
437   // Expected output: the DebugString of grpc.testing.EchoRequest
438   EXPECT_TRUE(0 ==
439               strcmp(output_stream.str().c_str(), desc->DebugString().c_str()));
440 
441   ShutdownServer();
442 }
443 
TEST_F(GrpcToolTest,ListOneMethod)444 TEST_F(GrpcToolTest, ListOneMethod) {
445   // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
446   std::stringstream output_stream;
447 
448   const std::string server_address = SetUpServer();
449   const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
450                         "grpc.testing.EchoTestService.Echo"};
451   // without -l flag
452   absl::SetFlag(&FLAGS_l, false);
453   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
454                                    std::bind(PrintStream, &output_stream,
455                                              std::placeholders::_1)));
456   // Expected output: "Echo"
457   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), "Echo\n"));
458 
459   // with -l flag
460   output_stream.str(std::string());
461   output_stream.clear();
462   absl::SetFlag(&FLAGS_l, true);
463   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
464                                    std::bind(PrintStream, &output_stream,
465                                              std::placeholders::_1)));
466   // Expected output: ECHO_METHOD_DESCRIPTION
467   EXPECT_TRUE(0 ==
468               strcmp(output_stream.str().c_str(), ECHO_METHOD_DESCRIPTION));
469 
470   ShutdownServer();
471 }
472 
TEST_F(GrpcToolTest,TypeNotFound)473 TEST_F(GrpcToolTest, TypeNotFound) {
474   // Test input "grpc_cli type localhost:<port> grpc.testing.PhonyRequest"
475   std::stringstream output_stream;
476 
477   const std::string server_address = SetUpServer();
478   const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
479                         "grpc.testing.PhonyRequest"};
480 
481   EXPECT_TRUE(1 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
482                                    std::bind(PrintStream, &output_stream,
483                                              std::placeholders::_1)));
484   ShutdownServer();
485 }
486 
TEST_F(GrpcToolTest,CallCommand)487 TEST_F(GrpcToolTest, CallCommand) {
488   // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
489   std::stringstream output_stream;
490 
491   const std::string server_address = SetUpServer();
492   const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
493                         "message: 'Hello'"};
494 
495   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
496                                    std::bind(PrintStream, &output_stream,
497                                              std::placeholders::_1)));
498   // Expected output: "message: \"Hello\""
499   EXPECT_TRUE(nullptr !=
500               strstr(output_stream.str().c_str(), "message: \"Hello\""));
501 
502   // with json_output
503   output_stream.str(std::string());
504   output_stream.clear();
505 
506   // TODO(Capstan): Consider using absl::FlagSaver
507   absl::SetFlag(&FLAGS_json_output, true);
508   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
509                                    std::bind(PrintStream, &output_stream,
510                                              std::placeholders::_1)));
511   absl::SetFlag(&FLAGS_json_output, false);
512 
513   // Expected output:
514   // {
515   //  "message": "Hello"
516   // }
517   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
518                                 "{\n \"message\": \"Hello\"\n}"));
519 
520   ShutdownServer();
521 }
522 
TEST_F(GrpcToolTest,CallCommandJsonInput)523 TEST_F(GrpcToolTest, CallCommandJsonInput) {
524   // Test input "grpc_cli call localhost:<port> Echo "{ \"message\": \"Hello\"}"
525   std::stringstream output_stream;
526 
527   const std::string server_address = SetUpServer();
528   const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
529                         "{ \"message\": \"Hello\"}"};
530 
531   absl::SetFlag(&FLAGS_json_input, true);
532   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
533                                    std::bind(PrintStream, &output_stream,
534                                              std::placeholders::_1)));
535   // Expected output: "message: \"Hello\""
536   EXPECT_TRUE(nullptr !=
537               strstr(output_stream.str().c_str(), "message: \"Hello\""));
538 
539   // with json_output
540   output_stream.str(std::string());
541   output_stream.clear();
542 
543   absl::SetFlag(&FLAGS_json_output, true);
544   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
545                                    std::bind(PrintStream, &output_stream,
546                                              std::placeholders::_1)));
547   absl::SetFlag(&FLAGS_json_output, false);
548   absl::SetFlag(&FLAGS_json_input, false);
549 
550   // Expected output:
551   // {
552   //  "message": "Hello"
553   // }
554   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
555                                 "{\n \"message\": \"Hello\"\n}"));
556 
557   ShutdownServer();
558 }
559 
TEST_F(GrpcToolTest,CallCommandBatch)560 TEST_F(GrpcToolTest, CallCommandBatch) {
561   // Test input "grpc_cli call Echo"
562   std::stringstream output_stream;
563 
564   const std::string server_address = SetUpServer();
565   const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
566                         "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   absl::SetFlag(&FLAGS_batch, true);
574   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
575                                    std::bind(PrintStream, &output_stream,
576                                              std::placeholders::_1)));
577   absl::SetFlag(&FLAGS_batch, false);
578 
579   // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
580   // "Hello2"\n"
581   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
582                                 "message: \"Hello0\"\nmessage: "
583                                 "\"Hello1\"\nmessage: \"Hello2\"\n"));
584   // with json_output
585   output_stream.str(std::string());
586   output_stream.clear();
587   ss.clear();
588   ss.seekg(0);
589   std::cin.rdbuf(ss.rdbuf());
590 
591   absl::SetFlag(&FLAGS_batch, true);
592   absl::SetFlag(&FLAGS_json_output, true);
593   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
594                                    std::bind(PrintStream, &output_stream,
595                                              std::placeholders::_1)));
596   absl::SetFlag(&FLAGS_json_output, false);
597   absl::SetFlag(&FLAGS_batch, false);
598 
599   // Expected output:
600   // {
601   //  "message": "Hello0"
602   // }
603   // {
604   //  "message": "Hello1"
605   // }
606   // {
607   //  "message": "Hello2"
608   // }
609   // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
610   // "Hello2"\n"
611   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
612                                 "{\n \"message\": \"Hello0\"\n}\n"
613                                 "{\n \"message\": \"Hello1\"\n}\n"
614                                 "{\n \"message\": \"Hello2\"\n}\n"));
615 
616   std::cin.rdbuf(orig);
617   ShutdownServer();
618 }
619 
TEST_F(GrpcToolTest,CallCommandBatchJsonInput)620 TEST_F(GrpcToolTest, CallCommandBatchJsonInput) {
621   // Test input "grpc_cli call Echo"
622   std::stringstream output_stream;
623 
624   const std::string server_address = SetUpServer();
625   const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
626                         "{\"message\": \"Hello0\"}"};
627 
628   // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
629   std::streambuf* orig = std::cin.rdbuf();
630   std::istringstream ss(
631       "{\"message\": \"Hello1\"}\n\n{\"message\": \"Hello2\" }\n\n");
632   std::cin.rdbuf(ss.rdbuf());
633 
634   absl::SetFlag(&FLAGS_json_input, true);
635   absl::SetFlag(&FLAGS_batch, true);
636   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
637                                    std::bind(PrintStream, &output_stream,
638                                              std::placeholders::_1)));
639   absl::SetFlag(&FLAGS_batch, false);
640 
641   // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
642   // "Hello2"\n"
643   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
644                                 "message: \"Hello0\"\nmessage: "
645                                 "\"Hello1\"\nmessage: \"Hello2\"\n"));
646   // with json_output
647   output_stream.str(std::string());
648   output_stream.clear();
649   ss.clear();
650   ss.seekg(0);
651   std::cin.rdbuf(ss.rdbuf());
652 
653   absl::SetFlag(&FLAGS_batch, true);
654   absl::SetFlag(&FLAGS_json_output, true);
655   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
656                                    std::bind(PrintStream, &output_stream,
657                                              std::placeholders::_1)));
658   absl::SetFlag(&FLAGS_json_output, false);
659   absl::SetFlag(&FLAGS_batch, false);
660   absl::SetFlag(&FLAGS_json_input, false);
661 
662   // Expected output:
663   // {
664   //  "message": "Hello0"
665   // }
666   // {
667   //  "message": "Hello1"
668   // }
669   // {
670   //  "message": "Hello2"
671   // }
672   // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
673   // "Hello2"\n"
674   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
675                                 "{\n \"message\": \"Hello0\"\n}\n"
676                                 "{\n \"message\": \"Hello1\"\n}\n"
677                                 "{\n \"message\": \"Hello2\"\n}\n"));
678 
679   std::cin.rdbuf(orig);
680   ShutdownServer();
681 }
682 
TEST_F(GrpcToolTest,CallCommandBatchWithBadRequest)683 TEST_F(GrpcToolTest, CallCommandBatchWithBadRequest) {
684   // Test input "grpc_cli call Echo"
685   std::stringstream output_stream;
686 
687   const std::string server_address = SetUpServer();
688   const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
689                         "message: 'Hello0'"};
690 
691   // Mock std::cin input "message: 1\n\n message: 'Hello2'\n\n"
692   std::streambuf* orig = std::cin.rdbuf();
693   std::istringstream ss("message: 1\n\n message: 'Hello2'\n\n");
694   std::cin.rdbuf(ss.rdbuf());
695 
696   absl::SetFlag(&FLAGS_batch, true);
697   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
698                                    std::bind(PrintStream, &output_stream,
699                                              std::placeholders::_1)));
700   absl::SetFlag(&FLAGS_batch, false);
701 
702   // Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
703   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
704                                 "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
705 
706   // with json_output
707   output_stream.str(std::string());
708   output_stream.clear();
709   ss.clear();
710   ss.seekg(0);
711   std::cin.rdbuf(ss.rdbuf());
712 
713   absl::SetFlag(&FLAGS_batch, true);
714   absl::SetFlag(&FLAGS_json_output, true);
715   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
716                                    std::bind(PrintStream, &output_stream,
717                                              std::placeholders::_1)));
718   absl::SetFlag(&FLAGS_json_output, false);
719   absl::SetFlag(&FLAGS_batch, false);
720 
721   // Expected output:
722   // {
723   //  "message": "Hello0"
724   // }
725   // {
726   //  "message": "Hello2"
727   // }
728   // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
729   // "Hello2"\n"
730   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
731                                 "{\n \"message\": \"Hello0\"\n}\n"
732                                 "{\n \"message\": \"Hello2\"\n}\n"));
733 
734   std::cin.rdbuf(orig);
735   ShutdownServer();
736 }
737 
TEST_F(GrpcToolTest,CallCommandBatchJsonInputWithBadRequest)738 TEST_F(GrpcToolTest, CallCommandBatchJsonInputWithBadRequest) {
739   // Test input "grpc_cli call Echo"
740   std::stringstream output_stream;
741 
742   const std::string server_address = SetUpServer();
743   const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
744                         "{ \"message\": \"Hello0\"}"};
745 
746   // Mock std::cin input "message: 1\n\n message: 'Hello2'\n\n"
747   std::streambuf* orig = std::cin.rdbuf();
748   std::istringstream ss(
749       "{ \"message\": 1 }\n\n { \"message\": \"Hello2\" }\n\n");
750   std::cin.rdbuf(ss.rdbuf());
751 
752   absl::SetFlag(&FLAGS_batch, true);
753   absl::SetFlag(&FLAGS_json_input, true);
754   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
755                                    std::bind(PrintStream, &output_stream,
756                                              std::placeholders::_1)));
757   absl::SetFlag(&FLAGS_json_input, false);
758   absl::SetFlag(&FLAGS_batch, false);
759 
760   // Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
761   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
762                                 "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
763 
764   // with json_output
765   output_stream.str(std::string());
766   output_stream.clear();
767   ss.clear();
768   ss.seekg(0);
769   std::cin.rdbuf(ss.rdbuf());
770 
771   absl::SetFlag(&FLAGS_batch, true);
772   absl::SetFlag(&FLAGS_json_input, true);
773   absl::SetFlag(&FLAGS_json_output, true);
774   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
775                                    std::bind(PrintStream, &output_stream,
776                                              std::placeholders::_1)));
777   absl::SetFlag(&FLAGS_json_output, false);
778   absl::SetFlag(&FLAGS_json_input, false);
779   absl::SetFlag(&FLAGS_batch, false);
780 
781   // Expected output:
782   // {
783   //  "message": "Hello0"
784   // }
785   // {
786   //  "message": "Hello2"
787   // }
788   // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
789   // "Hello2"\n"
790   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
791                                 "{\n \"message\": \"Hello0\"\n}\n"
792                                 "{\n \"message\": \"Hello2\"\n}\n"));
793 
794   std::cin.rdbuf(orig);
795   ShutdownServer();
796 }
797 
TEST_F(GrpcToolTest,CallCommandRequestStream)798 TEST_F(GrpcToolTest, CallCommandRequestStream) {
799   // Test input: grpc_cli call localhost:<port> RequestStream "message:
800   // 'Hello0'"
801   std::stringstream output_stream;
802 
803   const std::string server_address = SetUpServer();
804   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
805                         "RequestStream", "message: 'Hello0'"};
806 
807   // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
808   std::streambuf* orig = std::cin.rdbuf();
809   std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
810   std::cin.rdbuf(ss.rdbuf());
811 
812   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
813                                    std::bind(PrintStream, &output_stream,
814                                              std::placeholders::_1)));
815 
816   // Expected output: "message: \"Hello0Hello1Hello2\""
817   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
818                                 "message: \"Hello0Hello1Hello2\""));
819   std::cin.rdbuf(orig);
820   ShutdownServer();
821 }
822 
TEST_F(GrpcToolTest,CallCommandRequestStreamJsonInput)823 TEST_F(GrpcToolTest, CallCommandRequestStreamJsonInput) {
824   // Test input: grpc_cli call localhost:<port> RequestStream "{ \"message\":
825   // \"Hello0\"}"
826   std::stringstream output_stream;
827 
828   const std::string server_address = SetUpServer();
829   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
830                         "RequestStream", "{ \"message\": \"Hello0\" }"};
831 
832   // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
833   std::streambuf* orig = std::cin.rdbuf();
834   std::istringstream ss(
835       "{ \"message\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
836   std::cin.rdbuf(ss.rdbuf());
837 
838   absl::SetFlag(&FLAGS_json_input, true);
839   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
840                                    std::bind(PrintStream, &output_stream,
841                                              std::placeholders::_1)));
842   absl::SetFlag(&FLAGS_json_input, false);
843 
844   // Expected output: "message: \"Hello0Hello1Hello2\""
845   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
846                                 "message: \"Hello0Hello1Hello2\""));
847   std::cin.rdbuf(orig);
848   ShutdownServer();
849 }
850 
TEST_F(GrpcToolTest,CallCommandRequestStreamWithBadRequest)851 TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) {
852   // Test input: grpc_cli call localhost:<port> RequestStream "message:
853   // 'Hello0'"
854   std::stringstream output_stream;
855 
856   const std::string server_address = SetUpServer();
857   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
858                         "RequestStream", "message: 'Hello0'"};
859 
860   // Mock std::cin input "bad_field: 'Hello1'\n\n message: 'Hello2'\n\n"
861   std::streambuf* orig = std::cin.rdbuf();
862   std::istringstream ss("bad_field: 'Hello1'\n\n message: 'Hello2'\n\n");
863   std::cin.rdbuf(ss.rdbuf());
864 
865   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
866                                    std::bind(PrintStream, &output_stream,
867                                              std::placeholders::_1)));
868 
869   // Expected output: "message: \"Hello0Hello2\""
870   EXPECT_TRUE(nullptr !=
871               strstr(output_stream.str().c_str(), "message: \"Hello0Hello2\""));
872   std::cin.rdbuf(orig);
873   ShutdownServer();
874 }
875 
TEST_F(GrpcToolTest,CallCommandRequestStreamWithBadRequestJsonInput)876 TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequestJsonInput) {
877   // Test input: grpc_cli call localhost:<port> RequestStream "message:
878   // 'Hello0'"
879   std::stringstream output_stream;
880 
881   const std::string server_address = SetUpServer();
882   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
883                         "RequestStream", "{ \"message\": \"Hello0\" }"};
884 
885   // Mock std::cin input "bad_field: 'Hello1'\n\n message: 'Hello2'\n\n"
886   std::streambuf* orig = std::cin.rdbuf();
887   std::istringstream ss(
888       "{ \"bad_field\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
889   std::cin.rdbuf(ss.rdbuf());
890 
891   absl::SetFlag(&FLAGS_json_input, true);
892   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
893                                    std::bind(PrintStream, &output_stream,
894                                              std::placeholders::_1)));
895   absl::SetFlag(&FLAGS_json_input, false);
896 
897   // Expected output: "message: \"Hello0Hello2\""
898   EXPECT_TRUE(nullptr !=
899               strstr(output_stream.str().c_str(), "message: \"Hello0Hello2\""));
900   std::cin.rdbuf(orig);
901   ShutdownServer();
902 }
903 
TEST_F(GrpcToolTest,CallCommandWithTimeoutDeadlineSet)904 TEST_F(GrpcToolTest, CallCommandWithTimeoutDeadlineSet) {
905   // Test input "grpc_cli call CheckDeadlineSet --timeout=5000.25"
906   std::stringstream output_stream;
907 
908   const std::string server_address = SetUpServer();
909   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
910                         "CheckDeadlineSet"};
911 
912   // Set timeout to 5000.25 seconds
913   absl::SetFlag(&FLAGS_timeout, 5000.25);
914 
915   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
916                                    std::bind(PrintStream, &output_stream,
917                                              std::placeholders::_1)));
918 
919   // Expected output: "message: "true"", deadline set
920   EXPECT_TRUE(nullptr !=
921               strstr(output_stream.str().c_str(), "message: \"true\""));
922   ShutdownServer();
923 }
924 
TEST_F(GrpcToolTest,CallCommandWithTimeoutDeadlineUpperBound)925 TEST_F(GrpcToolTest, CallCommandWithTimeoutDeadlineUpperBound) {
926   // Test input "grpc_cli call CheckDeadlineUpperBound --timeout=900"
927   std::stringstream output_stream;
928 
929   const std::string server_address = SetUpServer();
930   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
931                         "CheckDeadlineUpperBound"};
932 
933   // Set timeout to 900 seconds
934   absl::SetFlag(&FLAGS_timeout, 900);
935 
936   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
937                                    std::bind(PrintStream, &output_stream,
938                                              std::placeholders::_1)));
939 
940   // Expected output: "message: "true""
941   // deadline not greater than timeout + current time
942   EXPECT_TRUE(nullptr !=
943               strstr(output_stream.str().c_str(), "message: \"true\""));
944   ShutdownServer();
945 }
946 
TEST_F(GrpcToolTest,CallCommandWithNegativeTimeoutValue)947 TEST_F(GrpcToolTest, CallCommandWithNegativeTimeoutValue) {
948   // Test input "grpc_cli call CheckDeadlineSet --timeout=-5"
949   std::stringstream output_stream;
950 
951   const std::string server_address = SetUpServer();
952   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
953                         "CheckDeadlineSet"};
954 
955   // Set timeout to -5 (deadline not set)
956   absl::SetFlag(&FLAGS_timeout, -5);
957 
958   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
959                                    std::bind(PrintStream, &output_stream,
960                                              std::placeholders::_1)));
961 
962   // Expected output: "message: "false"", deadline not set
963   EXPECT_TRUE(nullptr !=
964               strstr(output_stream.str().c_str(), "message: \"false\""));
965 
966   ShutdownServer();
967 }
968 
TEST_F(GrpcToolTest,CallCommandWithDefaultTimeoutValue)969 TEST_F(GrpcToolTest, CallCommandWithDefaultTimeoutValue) {
970   // Test input "grpc_cli call CheckDeadlineSet --timeout=-1"
971   std::stringstream output_stream;
972 
973   const std::string server_address = SetUpServer();
974   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
975                         "CheckDeadlineSet"};
976 
977   // Set timeout to -1 (default value, deadline not set)
978   absl::SetFlag(&FLAGS_timeout, -1);
979 
980   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
981                                    std::bind(PrintStream, &output_stream,
982                                              std::placeholders::_1)));
983 
984   // Expected output: "message: "false"", deadline not set
985   EXPECT_TRUE(nullptr !=
986               strstr(output_stream.str().c_str(), "message: \"false\""));
987 
988   ShutdownServer();
989 }
990 
TEST_F(GrpcToolTest,CallCommandResponseStream)991 TEST_F(GrpcToolTest, CallCommandResponseStream) {
992   // Test input: grpc_cli call localhost:<port> ResponseStream "message:
993   // 'Hello'"
994   std::stringstream output_stream;
995 
996   const std::string server_address = SetUpServer();
997   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
998                         "ResponseStream", "message: 'Hello'"};
999 
1000   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1001                                    std::bind(PrintStream, &output_stream,
1002                                              std::placeholders::_1)));
1003 
1004   // Expected output: "message: \"Hello{n}\""
1005   for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
1006     std::string expected_response_text =
1007         "message: \"Hello" + std::to_string(i) + "\"\n";
1008     EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
1009                                   expected_response_text.c_str()));
1010   }
1011 
1012   // with json_output
1013   output_stream.str(std::string());
1014   output_stream.clear();
1015 
1016   absl::SetFlag(&FLAGS_json_output, true);
1017   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1018                                    std::bind(PrintStream, &output_stream,
1019                                              std::placeholders::_1)));
1020   absl::SetFlag(&FLAGS_json_output, false);
1021 
1022   // Expected output: "{\n \"message\": \"Hello{n}\"\n}\n"
1023   for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
1024     std::string expected_response_text =
1025         "{\n \"message\": \"Hello" + std::to_string(i) + "\"\n}\n";
1026     EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
1027                                   expected_response_text.c_str()));
1028   }
1029 
1030   ShutdownServer();
1031 }
1032 
TEST_F(GrpcToolTest,CallCommandBidiStream)1033 TEST_F(GrpcToolTest, CallCommandBidiStream) {
1034   // Test input: grpc_cli call localhost:<port> BidiStream "message: 'Hello0'"
1035   std::stringstream output_stream;
1036 
1037   const std::string server_address = SetUpServer();
1038   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
1039                         "BidiStream", "message: 'Hello0'"};
1040 
1041   // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
1042   std::streambuf* orig = std::cin.rdbuf();
1043   std::istringstream ss("message: 'Hello1'\n\n message: 'Hello2'\n\n");
1044   std::cin.rdbuf(ss.rdbuf());
1045 
1046   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1047                                    std::bind(PrintStream, &output_stream,
1048                                              std::placeholders::_1)));
1049 
1050   // Expected output: "message: \"Hello0\"\nmessage: \"Hello1\"\nmessage:
1051   // \"Hello2\"\n\n"
1052   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
1053                                 "message: \"Hello0\"\nmessage: "
1054                                 "\"Hello1\"\nmessage: \"Hello2\"\n"));
1055   std::cin.rdbuf(orig);
1056   ShutdownServer();
1057 }
1058 
TEST_F(GrpcToolTest,CallCommandBidiStreamWithBadRequest)1059 TEST_F(GrpcToolTest, CallCommandBidiStreamWithBadRequest) {
1060   // Test input: grpc_cli call localhost:<port> BidiStream "message: 'Hello0'"
1061   std::stringstream output_stream;
1062 
1063   const std::string server_address = SetUpServer();
1064   const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
1065                         "BidiStream", "message: 'Hello0'"};
1066 
1067   // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
1068   std::streambuf* orig = std::cin.rdbuf();
1069   std::istringstream ss("message: 1.0\n\n message: 'Hello2'\n\n");
1070   std::cin.rdbuf(ss.rdbuf());
1071 
1072   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1073                                    std::bind(PrintStream, &output_stream,
1074                                              std::placeholders::_1)));
1075 
1076   // Expected output: "message: \"Hello0\"\nmessage: \"Hello1\"\nmessage:
1077   // \"Hello2\"\n\n"
1078   EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
1079                                 "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
1080   std::cin.rdbuf(orig);
1081 
1082   ShutdownServer();
1083 }
1084 
TEST_F(GrpcToolTest,ParseCommand)1085 TEST_F(GrpcToolTest, ParseCommand) {
1086   // Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
1087   // ECHO_RESPONSE_MESSAGE"
1088   std::stringstream output_stream;
1089   std::stringstream binary_output_stream;
1090 
1091   const std::string server_address = SetUpServer();
1092   const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
1093                         "grpc.testing.EchoResponse",
1094                         ECHO_RESPONSE_MESSAGE_TEXT_FORMAT};
1095 
1096   absl::SetFlag(&FLAGS_binary_input, false);
1097   absl::SetFlag(&FLAGS_binary_output, false);
1098   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1099                                    std::bind(PrintStream, &output_stream,
1100                                              std::placeholders::_1)));
1101   // Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
1102   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
1103                           ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
1104 
1105   // with json_output
1106   output_stream.str(std::string());
1107   output_stream.clear();
1108 
1109   absl::SetFlag(&FLAGS_json_output, true);
1110   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1111                                    std::bind(PrintStream, &output_stream,
1112                                              std::placeholders::_1)));
1113   absl::SetFlag(&FLAGS_json_output, false);
1114 
1115   // Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
1116   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
1117                           ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
1118 
1119   // Parse text message to binary message and then parse it back to text message
1120   output_stream.str(std::string());
1121   output_stream.clear();
1122   absl::SetFlag(&FLAGS_binary_output, true);
1123   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1124                                    std::bind(PrintStream, &output_stream,
1125                                              std::placeholders::_1)));
1126   std::string binary_data = output_stream.str();
1127   output_stream.str(std::string());
1128   output_stream.clear();
1129   argv[4] = binary_data.c_str();
1130   absl::SetFlag(&FLAGS_binary_input, true);
1131   absl::SetFlag(&FLAGS_binary_output, false);
1132   EXPECT_TRUE(0 == GrpcToolMainLib(5, argv, TestCliCredentials(),
1133                                    std::bind(PrintStream, &output_stream,
1134                                              std::placeholders::_1)));
1135 
1136   // Expected output: ECHO_RESPONSE_MESSAGE
1137   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
1138                           ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
1139 
1140   absl::SetFlag(&FLAGS_binary_input, false);
1141   absl::SetFlag(&FLAGS_binary_output, false);
1142   ShutdownServer();
1143 }
1144 
TEST_F(GrpcToolTest,ParseCommandJsonFormat)1145 TEST_F(GrpcToolTest, ParseCommandJsonFormat) {
1146   // Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
1147   // ECHO_RESPONSE_MESSAGE_JSON_FORMAT"
1148   std::stringstream output_stream;
1149   std::stringstream binary_output_stream;
1150 
1151   const std::string server_address = SetUpServer();
1152   const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
1153                         "grpc.testing.EchoResponse",
1154                         ECHO_RESPONSE_MESSAGE_JSON_FORMAT};
1155 
1156   absl::SetFlag(&FLAGS_json_input, true);
1157   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1158                                    std::bind(PrintStream, &output_stream,
1159                                              std::placeholders::_1)));
1160 
1161   // Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
1162   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
1163                           ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
1164 
1165   // with json_output
1166   output_stream.str(std::string());
1167   output_stream.clear();
1168 
1169   absl::SetFlag(&FLAGS_json_output, true);
1170   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1171                                    std::bind(PrintStream, &output_stream,
1172                                              std::placeholders::_1)));
1173   absl::SetFlag(&FLAGS_json_output, false);
1174   absl::SetFlag(&FLAGS_json_input, false);
1175 
1176   // Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
1177   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
1178                           ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
1179 
1180   ShutdownServer();
1181 }
1182 
TEST_F(GrpcToolTest,TooFewArguments)1183 TEST_F(GrpcToolTest, TooFewArguments) {
1184   // Test input "grpc_cli call Echo"
1185   std::stringstream output_stream;
1186   const char* argv[] = {"grpc_cli", "call", "Echo"};
1187 
1188   // Exit with 1
1189   EXPECT_EXIT(
1190       GrpcToolMainLib(
1191           ArraySize(argv), argv, TestCliCredentials(),
1192           std::bind(PrintStream, &output_stream, std::placeholders::_1)),
1193       ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
1194   // No output
1195   EXPECT_TRUE(0 == output_stream.tellp());
1196 }
1197 
TEST_F(GrpcToolTest,TooManyArguments)1198 TEST_F(GrpcToolTest, TooManyArguments) {
1199   // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
1200   std::stringstream output_stream;
1201   const char* argv[] = {"grpc_cli", "call", "localhost:10000",
1202                         "Echo",     "Echo", "message: 'Hello'"};
1203 
1204   // Exit with 1
1205   EXPECT_EXIT(
1206       GrpcToolMainLib(
1207           ArraySize(argv), argv, TestCliCredentials(),
1208           std::bind(PrintStream, &output_stream, std::placeholders::_1)),
1209       ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
1210   // No output
1211   EXPECT_TRUE(0 == output_stream.tellp());
1212 }
1213 
TEST_F(GrpcToolTest,CallCommandWithMetadata)1214 TEST_F(GrpcToolTest, CallCommandWithMetadata) {
1215   // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
1216   const std::string server_address = SetUpServer();
1217   const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
1218                         "message: 'Hello'"};
1219 
1220   {
1221     std::stringstream output_stream;
1222     absl::SetFlag(&FLAGS_metadata, "key0:val0:key1:valq:key2:val2");
1223     EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
1224                                      TestCliCredentials(),
1225                                      std::bind(PrintStream, &output_stream,
1226                                                std::placeholders::_1)));
1227     // Expected output: "message: \"Hello\""
1228     EXPECT_TRUE(nullptr !=
1229                 strstr(output_stream.str().c_str(), "message: \"Hello\""));
1230   }
1231 
1232   {
1233     std::stringstream output_stream;
1234     absl::SetFlag(&FLAGS_metadata, "key:val\\:val");
1235     EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
1236                                      TestCliCredentials(),
1237                                      std::bind(PrintStream, &output_stream,
1238                                                std::placeholders::_1)));
1239     // Expected output: "message: \"Hello\""
1240     EXPECT_TRUE(nullptr !=
1241                 strstr(output_stream.str().c_str(), "message: \"Hello\""));
1242   }
1243 
1244   {
1245     std::stringstream output_stream;
1246     absl::SetFlag(&FLAGS_metadata, "key:val\\\\val");
1247     EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv,
1248                                      TestCliCredentials(),
1249                                      std::bind(PrintStream, &output_stream,
1250                                                std::placeholders::_1)));
1251     // Expected output: "message: \"Hello\""
1252     EXPECT_TRUE(nullptr !=
1253                 strstr(output_stream.str().c_str(), "message: \"Hello\""));
1254   }
1255 
1256   absl::SetFlag(&FLAGS_metadata, "");
1257   ShutdownServer();
1258 }
1259 
TEST_F(GrpcToolTest,CallCommandWithBadMetadata)1260 TEST_F(GrpcToolTest, CallCommandWithBadMetadata) {
1261   // Test input "grpc_cli call localhost:10000 Echo "message: 'Hello'"
1262   const char* argv[] = {"grpc_cli", "call", "localhost:10000",
1263                         "grpc.testing.EchoTestService.Echo",
1264                         "message: 'Hello'"};
1265   absl::SetFlag(&FLAGS_protofiles, "src/proto/grpc/testing/echo.proto");
1266   char* test_srcdir = gpr_getenv("TEST_SRCDIR");
1267   if (test_srcdir != nullptr) {
1268     absl::SetFlag(&FLAGS_proto_path,
1269                   test_srcdir + std::string("/com_github_grpc_grpc"));
1270   }
1271 
1272   {
1273     std::stringstream output_stream;
1274     absl::SetFlag(&FLAGS_metadata, "key0:val0:key1");
1275     // Exit with 1
1276     EXPECT_EXIT(
1277         GrpcToolMainLib(
1278             ArraySize(argv), argv, TestCliCredentials(),
1279             std::bind(PrintStream, &output_stream, std::placeholders::_1)),
1280         ::testing::ExitedWithCode(1), ".*Failed to parse metadata flag.*");
1281   }
1282 
1283   {
1284     std::stringstream output_stream;
1285     absl::SetFlag(&FLAGS_metadata, "key:val\\val");
1286     // Exit with 1
1287     EXPECT_EXIT(
1288         GrpcToolMainLib(
1289             ArraySize(argv), argv, TestCliCredentials(),
1290             std::bind(PrintStream, &output_stream, std::placeholders::_1)),
1291         ::testing::ExitedWithCode(1), ".*Failed to parse metadata flag.*");
1292   }
1293 
1294   absl::SetFlag(&FLAGS_metadata, "");
1295   absl::SetFlag(&FLAGS_protofiles, "");
1296 
1297   gpr_free(test_srcdir);
1298 }
1299 
TEST_F(GrpcToolTest,ListCommand_OverrideSslHostName)1300 TEST_F(GrpcToolTest, ListCommand_OverrideSslHostName) {
1301   const std::string server_address = SetUpServer(true);
1302 
1303   // Test input "grpc_cli ls localhost:<port> --channel_creds_type=ssl
1304   // --ssl_target=z.test.google.fr"
1305   std::stringstream output_stream;
1306   const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
1307   absl::SetFlag(&FLAGS_l, false);
1308   absl::SetFlag(&FLAGS_channel_creds_type, "ssl");
1309   absl::SetFlag(&FLAGS_ssl_target, "z.test.google.fr");
1310   EXPECT_TRUE(
1311       0 == GrpcToolMainLib(
1312                ArraySize(argv), argv, TestCliCredentials(true),
1313                std::bind(PrintStream, &output_stream, std::placeholders::_1)));
1314   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
1315                           "grpc.testing.EchoTestService\n"
1316                           "grpc.reflection.v1alpha.ServerReflection\n"));
1317 
1318   absl::SetFlag(&FLAGS_channel_creds_type, "");
1319   absl::SetFlag(&FLAGS_ssl_target, "");
1320   ShutdownServer();
1321 }
1322 
TEST_F(GrpcToolTest,ConfiguringDefaultServiceConfig)1323 TEST_F(GrpcToolTest, ConfiguringDefaultServiceConfig) {
1324   // Test input "grpc_cli list localhost:<port>
1325   // --default_service_config={\"loadBalancingConfig\":[{\"pick_first\":{}}]}"
1326   std::stringstream output_stream;
1327   const std::string server_address = SetUpServer();
1328   const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
1329   // Just check that the tool is still operational when --default_service_config
1330   // is configured. This particular service config is in reality redundant with
1331   // the channel's default configuration.
1332   absl::SetFlag(&FLAGS_l, false);
1333   absl::SetFlag(&FLAGS_default_service_config,
1334                 "{\"loadBalancingConfig\":[{\"pick_first\":{}}]}");
1335   EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
1336                                    std::bind(PrintStream, &output_stream,
1337                                              std::placeholders::_1)));
1338   absl::SetFlag(&FLAGS_default_service_config, "");
1339   EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
1340                           "grpc.testing.EchoTestService\n"
1341                           "grpc.reflection.v1alpha.ServerReflection\n"));
1342   ShutdownServer();
1343 }
1344 
1345 }  // namespace testing
1346 }  // namespace grpc
1347 
main(int argc,char ** argv)1348 int main(int argc, char** argv) {
1349   grpc::testing::TestEnvironment env(argc, argv);
1350   ::testing::InitGoogleTest(&argc, argv);
1351   GRPC_GTEST_FLAG_SET_DEATH_TEST_STYLE("threadsafe");
1352   return RUN_ALL_TESTS();
1353 }
1354