blob: 12ca6c4b80c6a9955afe6fe54fbf7b3884dcea8f [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
38#include <grpc++/channel.h>
39#include <grpc++/client_context.h>
40#include <grpc++/create_channel.h>
41#include <grpc++/ext/proto_server_reflection_plugin.h>
42#include <grpc++/server.h>
43#include <grpc++/server_builder.h>
44#include <grpc++/server_context.h>
45#include <grpc/grpc.h>
Yuchen Zeng387afd72016-08-26 14:25:21 -070046#include <gflags/gflags.h>
Yuchen Zeng29ca79b2016-07-25 12:00:08 -070047#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 Zeng29ca79b2016-07-25 12:00:08 -0700157 std::unique_ptr<Server> server_;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700158 TestServiceImpl service_;
159 reflection::ProtoServerReflectionPlugin plugin_;
160};
161
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700162TEST_F(GrpcToolTest, NoCommand) {
163 // Test input "grpc_cli"
164 std::stringstream output_stream;
165 const char* argv[] = {"grpc_cli"};
166 // Exit with 1, print usage instruction in stderr
167 EXPECT_EXIT(
168 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700169 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700170 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
171 ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
172 // No output
173 EXPECT_TRUE(0 == output_stream.tellp());
174}
175
176TEST_F(GrpcToolTest, InvalidCommand) {
177 // Test input "grpc_cli"
178 std::stringstream output_stream;
179 const char* argv[] = {"grpc_cli", "abc"};
180 // Exit with 1, print usage instruction in stderr
181 EXPECT_EXIT(
182 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700183 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700184 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
185 ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
186 // No output
187 EXPECT_TRUE(0 == output_stream.tellp());
188}
189
190TEST_F(GrpcToolTest, HelpCommand) {
191 // Test input "grpc_cli help"
192 std::stringstream output_stream;
193 const char* argv[] = {"grpc_cli", "help"};
194 // Exit with 1, print usage instruction in stderr
Yuchen Zeng02139a02016-08-15 11:34:21 -0700195 EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700196 std::bind(PrintStream, &output_stream,
197 std::placeholders::_1)),
198 ::testing::ExitedWithCode(1), USAGE_REGEX);
199 // No output
200 EXPECT_TRUE(0 == output_stream.tellp());
201}
202
Yuchen Zeng387afd72016-08-26 14:25:21 -0700203TEST_F(GrpcToolTest, ListCommand) {
204 // Test input "grpc_cli list localhost:<port>"
205 std::stringstream output_stream;
206
207 const grpc::string server_address = SetUpServer();
208 const char* argv[] = {"grpc_cli", "ls", server_address.c_str()};
209
210 FLAGS_l = false;
211 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
212 std::bind(PrintStream, &output_stream,
213 std::placeholders::_1)));
214 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
215 "grpc.testing.EchoTestService\n"
216 "grpc.reflection.v1alpha.ServerReflection\n"));
217
218 ShutdownServer();
219}
220
221TEST_F(GrpcToolTest, ListOneService) {
222 // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
223 std::stringstream output_stream;
224
225 const grpc::string server_address = SetUpServer();
226 const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
227 "grpc.testing.EchoTestService"};
228 // without -l flag
229 FLAGS_l = false;
230 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
231 std::bind(PrintStream, &output_stream,
232 std::placeholders::_1)));
233 // Expected output: ECHO_TEST_SERVICE_SUMMARY
234 EXPECT_TRUE(0 ==
235 strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_SUMMARY));
236
237 // with -l flag
238 output_stream.str(grpc::string());
239 output_stream.clear();
240 FLAGS_l = true;
241 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
242 std::bind(PrintStream, &output_stream,
243 std::placeholders::_1)));
244 // Expected output: ECHO_TEST_SERVICE_DESCRIPTION
245 EXPECT_TRUE(
246 0 == strcmp(output_stream.str().c_str(), ECHO_TEST_SERVICE_DESCRIPTION));
247
248 ShutdownServer();
249}
250
251TEST_F(GrpcToolTest, ListOneMethod) {
252 // Test input "grpc_cli list localhost:<port> grpc.testing.EchoTestService"
253 std::stringstream output_stream;
254
255 const grpc::string server_address = SetUpServer();
256 const char* argv[] = {"grpc_cli", "ls", server_address.c_str(),
257 "grpc.testing.EchoTestService.Echo"};
258 // without -l flag
259 FLAGS_l = false;
260 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
261 std::bind(PrintStream, &output_stream,
262 std::placeholders::_1)));
263 // Expected output: "Echo"
264 EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), "Echo\n"));
265
266 // with -l flag
267 output_stream.str(grpc::string());
268 output_stream.clear();
269 FLAGS_l = true;
270 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
271 std::bind(PrintStream, &output_stream,
272 std::placeholders::_1)));
273 // Expected output: ECHO_METHOD_DESCRIPTION
274 EXPECT_TRUE(0 ==
275 strcmp(output_stream.str().c_str(), ECHO_METHOD_DESCRIPTION));
276
277 ShutdownServer();
278}
279
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700280TEST_F(GrpcToolTest, CallCommand) {
Yuchen Zeng387afd72016-08-26 14:25:21 -0700281 // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700282 std::stringstream output_stream;
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700283
284 const grpc::string server_address = SetUpServer();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700285 const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
286 "message: 'Hello'"};
287
Yuchen Zeng02139a02016-08-15 11:34:21 -0700288 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700289 std::bind(PrintStream, &output_stream,
290 std::placeholders::_1)));
291 // Expected output: "message: \"Hello\""
292 EXPECT_TRUE(NULL !=
293 strstr(output_stream.str().c_str(), "message: \"Hello\""));
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700294 ShutdownServer();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700295}
296
297TEST_F(GrpcToolTest, TooFewArguments) {
Yuchen Zeng387afd72016-08-26 14:25:21 -0700298 // Test input "grpc_cli call Echo"
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700299 std::stringstream output_stream;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700300 const char* argv[] = {"grpc_cli", "call", "Echo"};
301
302 // Exit with 1
303 EXPECT_EXIT(
304 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700305 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700306 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
307 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
308 // No output
309 EXPECT_TRUE(0 == output_stream.tellp());
310}
311
312TEST_F(GrpcToolTest, TooManyArguments) {
313 // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
314 std::stringstream output_stream;
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700315 const char* argv[] = {"grpc_cli", "call", "localhost:10000",
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700316 "Echo", "Echo", "message: 'Hello'"};
317
318 // Exit with 1
319 EXPECT_EXIT(
320 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700321 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700322 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
323 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
324 // No output
325 EXPECT_TRUE(0 == output_stream.tellp());
326}
327
328} // namespace testing
329} // namespace grpc
330
331int main(int argc, char** argv) {
332 grpc_test_init(argc, argv);
333 ::testing::InitGoogleTest(&argc, argv);
334 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
335 return RUN_ALL_TESTS();
336}