blob: b96afaf50cb57b145bfb9ad424721057c4058dab [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>
46#include <gtest/gtest.h>
47
48#include "src/proto/grpc/testing/echo.grpc.pb.h"
49#include "src/proto/grpc/testing/echo.pb.h"
50#include "test/core/util/port.h"
51#include "test/core/util/test_config.h"
Yuchen Zeng02139a02016-08-15 11:34:21 -070052#include "test/cpp/util/cli_credentials.h"
Yuchen Zeng29ca79b2016-07-25 12:00:08 -070053#include "test/cpp/util/string_ref_helper.h"
54
55using grpc::testing::EchoRequest;
56using grpc::testing::EchoResponse;
57
58namespace grpc {
59namespace testing {
Yuchen Zeng02139a02016-08-15 11:34:21 -070060namespace {
61
62class TestCliCredentials GRPC_FINAL : public grpc::testing::CliCredentials {
63 public:
64 std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const
65 GRPC_OVERRIDE {
66 return InsecureChannelCredentials();
67 }
68 const grpc::string GetCredentialUsage() const GRPC_OVERRIDE { return ""; }
69};
70
71} // namespame
Yuchen Zeng29ca79b2016-07-25 12:00:08 -070072
73class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
74 public:
75 Status Echo(ServerContext* context, const EchoRequest* request,
76 EchoResponse* response) GRPC_OVERRIDE {
77 if (!context->client_metadata().empty()) {
78 for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
79 iter = context->client_metadata().begin();
80 iter != context->client_metadata().end(); ++iter) {
81 context->AddInitialMetadata(ToString(iter->first),
82 ToString(iter->second));
83 }
84 }
85 context->AddTrailingMetadata("trailing_key", "trailing_value");
86 response->set_message(request->message());
87 return Status::OK;
88 }
89};
90
91class GrpcToolTest : public ::testing::Test {
92 protected:
93 GrpcToolTest() {}
94
Yuchen Zengf4046cd2016-07-26 12:22:42 -070095 // SetUpServer cannot be used with EXPECT_EXIT. grpc_pick_unused_port_or_die()
96 // uses atexit() to free chosen ports, and it will spawn a new thread in
97 // resolve_address_posix.c:192 at exit time.
98 const grpc::string SetUpServer() {
99 std::ostringstream server_address;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700100 int port = grpc_pick_unused_port_or_die();
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700101 server_address << "localhost:" << port;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700102 // Setup server
103 ServerBuilder builder;
Yuchen Zeng68ca3512016-07-26 16:48:46 -0700104 builder.AddListeningPort(server_address.str(), InsecureServerCredentials());
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700105 builder.RegisterService(&service_);
106 server_ = builder.BuildAndStart();
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700107 return server_address.str();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700108 }
109
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700110 void ShutdownServer() { server_->Shutdown(); }
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700111
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700112 std::unique_ptr<Server> server_;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700113 TestServiceImpl service_;
114 reflection::ProtoServerReflectionPlugin plugin_;
115};
116
117static bool PrintStream(std::stringstream* ss, const grpc::string& output) {
118 (*ss) << output << std::endl;
119 return true;
120}
121
122template <typename T>
123static size_t ArraySize(T& a) {
124 return ((sizeof(a) / sizeof(*(a))) /
125 static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
126}
127
128#define USAGE_REGEX "( grpc_cli .+\n){2,10}"
129
130TEST_F(GrpcToolTest, NoCommand) {
131 // Test input "grpc_cli"
132 std::stringstream output_stream;
133 const char* argv[] = {"grpc_cli"};
134 // Exit with 1, print usage instruction in stderr
135 EXPECT_EXIT(
136 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700137 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700138 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
139 ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
140 // No output
141 EXPECT_TRUE(0 == output_stream.tellp());
142}
143
144TEST_F(GrpcToolTest, InvalidCommand) {
145 // Test input "grpc_cli"
146 std::stringstream output_stream;
147 const char* argv[] = {"grpc_cli", "abc"};
148 // Exit with 1, print usage instruction in stderr
149 EXPECT_EXIT(
150 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700151 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700152 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
153 ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
154 // No output
155 EXPECT_TRUE(0 == output_stream.tellp());
156}
157
158TEST_F(GrpcToolTest, HelpCommand) {
159 // Test input "grpc_cli help"
160 std::stringstream output_stream;
161 const char* argv[] = {"grpc_cli", "help"};
162 // Exit with 1, print usage instruction in stderr
Yuchen Zeng02139a02016-08-15 11:34:21 -0700163 EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700164 std::bind(PrintStream, &output_stream,
165 std::placeholders::_1)),
166 ::testing::ExitedWithCode(1), USAGE_REGEX);
167 // No output
168 EXPECT_TRUE(0 == output_stream.tellp());
169}
170
171TEST_F(GrpcToolTest, CallCommand) {
172 // Test input "grpc_cli call Echo"
173 std::stringstream output_stream;
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700174
175 const grpc::string server_address = SetUpServer();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700176 const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
177 "message: 'Hello'"};
178
Yuchen Zeng02139a02016-08-15 11:34:21 -0700179 EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700180 std::bind(PrintStream, &output_stream,
181 std::placeholders::_1)));
182 // Expected output: "message: \"Hello\""
183 EXPECT_TRUE(NULL !=
184 strstr(output_stream.str().c_str(), "message: \"Hello\""));
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700185 ShutdownServer();
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700186}
187
188TEST_F(GrpcToolTest, TooFewArguments) {
189 // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
190 std::stringstream output_stream;
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700191 const char* argv[] = {"grpc_cli", "call", "Echo"};
192
193 // Exit with 1
194 EXPECT_EXIT(
195 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700196 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700197 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
198 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
199 // No output
200 EXPECT_TRUE(0 == output_stream.tellp());
201}
202
203TEST_F(GrpcToolTest, TooManyArguments) {
204 // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
205 std::stringstream output_stream;
Yuchen Zengf4046cd2016-07-26 12:22:42 -0700206 const char* argv[] = {"grpc_cli", "call", "localhost:10000",
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700207 "Echo", "Echo", "message: 'Hello'"};
208
209 // Exit with 1
210 EXPECT_EXIT(
211 GrpcToolMainLib(
Yuchen Zeng02139a02016-08-15 11:34:21 -0700212 ArraySize(argv), argv, TestCliCredentials(),
Yuchen Zeng29ca79b2016-07-25 12:00:08 -0700213 std::bind(PrintStream, &output_stream, std::placeholders::_1)),
214 ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
215 // No output
216 EXPECT_TRUE(0 == output_stream.tellp());
217}
218
219} // namespace testing
220} // namespace grpc
221
222int main(int argc, char** argv) {
223 grpc_test_init(argc, argv);
224 ::testing::InitGoogleTest(&argc, argv);
225 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
226 return RUN_ALL_TESTS();
227}