blob: bad1579f11eab9707f9ef8876fbf19340b806586 [file] [log] [blame]
Yuchen Zeng29ca79b2016-07-25 12:00:08 -07001/*
2 *
Yuchen Zeng02139a02016-08-15 11:34:21 -07003 * Copyright 2016, Google Inc.
Yuchen Zeng29ca79b2016-07-25 12:00:08 -07004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "test/cpp/util/grpc_tool.h"
35
36#include <sstream>
37
Yuchen Zengb4bca542016-09-15 11:38:36 -070038#include <gflags/gflags.h>
Yuchen Zeng29ca79b2016-07-25 12:00:08 -070039#include <grpc++/channel.h>
40#include <grpc++/client_context.h>
41#include <grpc++/create_channel.h>
42#include <grpc++/ext/proto_server_reflection_plugin.h>
43#include <grpc++/server.h>
44#include <grpc++/server_builder.h>
45#include <grpc++/server_context.h>
46#include <grpc/grpc.h>
47#include <gtest/gtest.h>
48
49#include "src/proto/grpc/testing/echo.grpc.pb.h"
50#include "src/proto/grpc/testing/echo.pb.h"
51#include "test/core/util/port.h"
52#include "test/core/util/test_config.h"
Yuchen Zeng02139a02016-08-15 11:34:21 -070053#include "test/cpp/util/cli_credentials.h"
Yuchen Zeng29ca79b2016-07-25 12:00:08 -070054#include "test/cpp/util/string_ref_helper.h"
55
56using grpc::testing::EchoRequest;
57using grpc::testing::EchoResponse;
58
Yuchen Zeng387afd72016-08-26 14:25:21 -070059#define USAGE_REGEX "( grpc_cli .+\n){2,10}"
60
61#define ECHO_TEST_SERVICE_SUMMARY \
62 "Echo\n" \
63 "RequestStream\n" \
64 "ResponseStream\n" \
65 "BidiStream\n" \
66 "Unimplemented\n"
67
68#define ECHO_TEST_SERVICE_DESCRIPTION \
69 "filename: src/proto/grpc/testing/echo.proto\n" \
70 "package: grpc.testing;\n" \
71 "service EchoTestService {\n" \
72 " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
73 "{}\n" \
74 " rpc RequestStream(stream grpc.testing.EchoRequest) returns " \
75 "(grpc.testing.EchoResponse) {}\n" \
76 " rpc ResponseStream(grpc.testing.EchoRequest) returns (stream " \
77 "grpc.testing.EchoResponse) {}\n" \
78 " rpc BidiStream(stream grpc.testing.EchoRequest) returns (stream " \
79 "grpc.testing.EchoResponse) {}\n" \
80 " rpc Unimplemented(grpc.testing.EchoRequest) returns " \
81 "(grpc.testing.EchoResponse) {}\n" \
82 "}\n" \
83 "\n"
84
85#define ECHO_METHOD_DESCRIPTION \
86 " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
87 "{}\n"
88
Yuchen Zeng29ca79b2016-07-25 12:00:08 -070089namespace grpc {
90namespace testing {
Yuchen Zeng387afd72016-08-26 14:25:21 -070091
92DECLARE_bool(l);
93
Yuchen Zeng02139a02016-08-15 11:34:21 -070094namespace {
95
96class TestCliCredentials GRPC_FINAL : public grpc::testing::CliCredentials {
97 public:
98 std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const
99 GRPC_OVERRIDE {
100 return InsecureChannelCredentials();
101 }
102 const grpc::string GetCredentialUsage() const GRPC_OVERRIDE { return ""; }
103};
104
Yuchen Zeng387afd72016-08-26 14:25:21 -0700105bool PrintStream(std::stringstream* ss, const grpc::string& output) {
106 (*ss) << output;
107 return true;
108}
109
110template <typename T>
111size_t ArraySize(T& a) {
112 return ((sizeof(a) / sizeof(*(a))) /
113 static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
114}
115
Yuchen Zeng02139a02016-08-15 11:34:21 -0700116} // namespame
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700117
118class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
119 public:
120 Status Echo(ServerContext* context, const EchoRequest* request,
121 EchoResponse* response) GRPC_OVERRIDE {
122 if (!context->client_metadata().empty()) {
123 for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
124 iter = context->client_metadata().begin();
125 iter != context->client_metadata().end(); ++iter) {
126 context->AddInitialMetadata(ToString(iter->first),
127 ToString(iter->second));
128 }
129 }
130 context->AddTrailingMetadata("trailing_key", "trailing_value");
131 response->set_message(request->message());
132 return Status::OK;
133 }
134};
135
136class GrpcToolTest : public ::testing::Test {
137 protected:
138 GrpcToolTest() {}
139
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700140 // SetUpServer cannot be used with EXPECT_EXIT. grpc_pick_unused_port_or_die()
141 // uses atexit() to free chosen ports, and it will spawn a new thread in
142 // resolve_address_posix.c:192 at exit time.
143 const grpc::string SetUpServer() {
144 std::ostringstream server_address;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700145 int port = grpc_pick_unused_port_or_die();
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700146 server_address << "localhost:" << port;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700147 // Setup server
148 ServerBuilder builder;
Yuchen Zeng68ca3512016-07-26 16:48:46 -0700149 builder.AddListeningPort(server_address.str(), InsecureServerCredentials());
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700150 builder.RegisterService(&service_);
151 server_ = builder.BuildAndStart();
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700152 return server_address.str();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700153 }
154
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700155 void ShutdownServer() { server_->Shutdown(); }
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700156
Yuchen Zeng734fd712016-09-16 16:10:53 -0700157 void ExitWhenError(int argc, const char** argv, const CliCredentials& cred,
Yuchen Zeng94d786f2016-08-26 16:23:29 -0700158 GrpcToolOutputCallback callback) {
159 int result = GrpcToolMainLib(argc, argv, cred, callback);
160 if (result) {
161 exit(result);
162 }
163 }
164
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700165 std::unique_ptr<Server> server_;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700166 TestServiceImpl service_;
167 reflection::ProtoServerReflectionPlugin plugin_;
168};
169
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700170TEST_F(GrpcToolTest, NoCommand) {
171 // Test input "grpc_cli"
172 std::stringstream output_stream;
173 const char* argv[] = {"grpc_cli"};
174 // Exit with 1, print usage instruction in stderr
175 EXPECT_EXIT(
176 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700177 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700178 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
179 ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
180 // No output
181 EXPECT_TRUE(0 == output_stream.tellp());
182}
183
184TEST_F(GrpcToolTest, InvalidCommand) {
185 // Test input "grpc_cli"
186 std::stringstream output_stream;
187 const char* argv[] = {"grpc_cli", "abc"};
188 // Exit with 1, print usage instruction in stderr
189 EXPECT_EXIT(
190 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700191 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700192 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
193 ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
194 // No output
195 EXPECT_TRUE(0 == output_stream.tellp());
196}
197
198TEST_F(GrpcToolTest, HelpCommand) {
199 // Test input "grpc_cli help"
200 std::stringstream output_stream;
201 const char* argv[] = {"grpc_cli", "help"};
202 // Exit with 1, print usage instruction in stderr
Yuchen Zeng02139a02016-08-15 11:34:21 -0700203 EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700204 std::bind(PrintStream, &output_stream,
205 std::placeholders::_1)),
206 ::testing::ExitedWithCode(1), USAGE_REGEX);
207 // No output
208 EXPECT_TRUE(0 == output_stream.tellp());
209}
210
Yuchen Zeng387afd72016-08-26 14:25:21 -0700211TEST_F(GrpcToolTest, ListCommand) {
212 // Test input "grpc_cli list localhost:<port>"
213 std::stringstream output_stream;
214
215 const grpc::string server_address = SetUpServer();
216 const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
217
218 FLAGS_l = false;
219 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
220 std::bind(PrintStream, &output_stream,
221 std::placeholders::_1)));
222 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
223 "grpc.testing.EchoTestService\n"
224 "grpc.reflection.v1alpha.ServerReflection\n"));
225
226 ShutdownServer();
227}
228
229TEST_F(GrpcToolTest, ListOneService) {
230 // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
231 std::stringstream output_stream;
232
233 const grpc::string server_address = SetUpServer();
234 const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
235 "grpc.testing.EchoTestService"};
236 // without -l flag
237 FLAGS_l = false;
238 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
239 std::bind(PrintStream, &output_stream,
240 std::placeholders::_1)));
241 // Expected output: ECHO_TEST_SERVICE_SUMMARY
242 EXPECT_TRUE(0 ==
243 strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_SUMMARY));
244
245 // with -l flag
246 output_stream.str(grpc::string());
247 output_stream.clear();
248 FLAGS_l = true;
249 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
250 std::bind(PrintStream, &output_stream,
251 std::placeholders::_1)));
252 // Expected output: ECHO_TEST_SERVICE_DESCRIPTION
253 EXPECT_TRUE(
254 0 == strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_DESCRIPTION));
255
256 ShutdownServer();
257}
258
Yuchen Zeng94d786f2016-08-26 16:23:29 -0700259TEST_F(GrpcToolTest, TypeCommand) {
260 // Test input "grpc_cli type localhost:<port> grpc.testing.EchoRequest"
261 std::stringstream output_stream;
262
263 const grpc::string server_address = SetUpServer();
264 const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
265 "grpc.testing.EchoRequest"};
266
267 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
268 std::bind(PrintStream, &output_stream,
269 std::placeholders::_1)));
270 const grpc::protobuf::Descriptor* desc =
271 grpc::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(
272 "grpc.testing.EchoRequest");
273 // Expected output: the DebugString of grpc.testing.EchoRequest
274 EXPECT_TRUE(0 ==
275 strcmp(output_stream.str().c_str(), desc->DebugString().c_str()));
276
277 ShutdownServer();
278}
279
Yuchen Zeng387afd72016-08-26 14:25:21 -0700280TEST_F(GrpcToolTest, ListOneMethod) {
281 // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
282 std::stringstream output_stream;
283
284 const grpc::string server_address = SetUpServer();
285 const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
286 "grpc.testing.EchoTestService.Echo"};
287 // without -l flag
288 FLAGS_l = false;
289 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
290 std::bind(PrintStream, &output_stream,
291 std::placeholders::_1)));
292 // Expected output: "Echo"
293 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), "Echo\n"));
294
295 // with -l flag
296 output_stream.str(grpc::string());
297 output_stream.clear();
298 FLAGS_l = true;
299 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
300 std::bind(PrintStream, &output_stream,
301 std::placeholders::_1)));
302 // Expected output: ECHO_METHOD_DESCRIPTION
303 EXPECT_TRUE(0 ==
304 strcmp(output_stream.str().c_str(), ECHO_METHOD_DESCRIPTION));
305
306 ShutdownServer();
307}
308
Yuchen Zeng94d786f2016-08-26 16:23:29 -0700309TEST_F(GrpcToolTest, TypeNotFound) {
310 // Test input "grpc_cli type localhost:<port> grpc.testing.DummyRequest"
311 std::stringstream output_stream;
312
313 const grpc::string server_address = SetUpServer();
314 const char* argv[] = {"grpc_cli", "type", server_address.c_str(),
315 "grpc.testing.DummyRequest"};
316
317 EXPECT_DEATH(ExitWhenError(ArraySize(argv), argv, TestCliCredentials(),
318 std::bind(PrintStream, &output_stream,
319 std::placeholders::_1)),
320 ".*Type grpc.testing.DummyRequest not found.*");
321
322 ShutdownServer();
323}
324
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700325TEST_F(GrpcToolTest, CallCommand) {
Yuchen Zeng387afd72016-08-26 14:25:21 -0700326 // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700327 std::stringstream output_stream;
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700328
329 const grpc::string server_address = SetUpServer();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700330 const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
331 "message: 'Hello'"};
332
Yuchen Zeng02139a02016-08-15 11:34:21 -0700333 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700334 std::bind(PrintStream, &output_stream,
335 std::placeholders::_1)));
336 // Expected output: "message: \"Hello\""
337 EXPECT_TRUE(NULL !=
338 strstr(output_stream.str().c_str(), "message: \"Hello\""));
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700339 ShutdownServer();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700340}
341
342TEST_F(GrpcToolTest, TooFewArguments) {
Yuchen Zeng387afd72016-08-26 14:25:21 -0700343 // Test input "grpc_cli call Echo"
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700344 std::stringstream output_stream;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700345 const char* argv[] = {"grpc_cli", "call", "Echo"};
346
347 // Exit with 1
348 EXPECT_EXIT(
349 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700350 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700351 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
352 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
353 // No output
354 EXPECT_TRUE(0 == output_stream.tellp());
355}
356
357TEST_F(GrpcToolTest, TooManyArguments) {
358 // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
359 std::stringstream output_stream;
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700360 const char* argv[] = {"grpc_cli", "call", "localhost:10000",
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700361 "Echo", "Echo", "message: 'Hello'"};
362
363 // Exit with 1
364 EXPECT_EXIT(
365 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700366 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700367 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
368 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
369 // No output
370 EXPECT_TRUE(0 == output_stream.tellp());
371}
372
373} // namespace testing
374} // namespace grpc
375
376int main(int argc, char** argv) {
377 grpc_test_init(argc, argv);
378 ::testing::InitGoogleTest(&argc, argv);
379 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
380 return RUN_ALL_TESTS();
381}