1 //
2 // Copyright 2022 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <gmock/gmock.h>
18 #include <grpcpp/create_channel.h>
19 #include <grpcpp/security/credentials.h>
20 #include <grpcpp/server_builder.h>
21 #include <grpcpp/support/status.h>
22 #include <gtest/gtest.h>
23
24 #include <memory>
25
26 #include "absl/strings/str_cat.h"
27 #include "absl/strings/str_format.h"
28 #include "src/core/util/crash.h"
29 #include "src/core/util/host_port.h"
30 #include "test/core/test_util/port.h"
31 #include "test/core/test_util/test_config.h"
32 #include "test/cpp/interop/istio_echo_server_lib.h"
33
34 namespace grpc {
35 namespace testing {
36 namespace {
37
38 using proto::EchoRequest;
39 using proto::EchoResponse;
40 using proto::EchoTestService;
41 using proto::ForwardEchoRequest;
42 using proto::ForwardEchoResponse;
43
44 // A very simple EchoTestService implementation that just echoes back the
45 // message without handling any other expectations for ForwardEcho.
46 class SimpleEchoTestServerImpl : public proto::EchoTestService::Service {
47 public:
SimpleEchoTestServerImpl()48 explicit SimpleEchoTestServerImpl() {}
49
Echo(grpc::ServerContext *,const proto::EchoRequest *,proto::EchoResponse *)50 grpc::Status Echo(grpc::ServerContext* /* context */,
51 const proto::EchoRequest* /* request */,
52 proto::EchoResponse* /* response */) override {
53 grpc_core::Crash("unreachable");
54 return Status(StatusCode::INVALID_ARGUMENT, "Unexpected");
55 }
56
ForwardEcho(grpc::ServerContext *,const proto::ForwardEchoRequest * request,proto::ForwardEchoResponse * response)57 grpc::Status ForwardEcho(grpc::ServerContext* /*context*/,
58 const proto::ForwardEchoRequest* request,
59 proto::ForwardEchoResponse* response) override {
60 if (fail_rpc_) {
61 return Status(StatusCode::UNAVAILABLE, "fail rpc");
62 }
63 response->add_output(request->message());
64 return Status::OK;
65 }
66
set_fail_rpc(bool fail_rpc)67 void set_fail_rpc(bool fail_rpc) { fail_rpc_ = fail_rpc; }
68
69 private:
70 std::string hostname_;
71 std::string forwarding_address_;
72 std::atomic<bool> fail_rpc_{false};
73 // The following fields are not set yet. But we may need them later.
74 // int port_;
75 // std::string version_;
76 // std::string cluster_;
77 // std::string istio_version_;
78 };
79
80 class EchoTest : public ::testing::Test {
81 protected:
EchoTest()82 EchoTest() {
83 // Start the simple server which will handle protocols that
84 // EchoTestServiceImpl does not handle.
85 int forwarding_port = grpc_pick_unused_port_or_die();
86 forwarding_address_ = grpc_core::JoinHostPort("localhost", forwarding_port);
87 ServerBuilder simple_builder;
88 simple_builder.RegisterService(&simple_test_service_impl_);
89 simple_builder.AddListeningPort(forwarding_address_,
90 InsecureServerCredentials());
91 simple_server_ = simple_builder.BuildAndStart();
92 // Start the EchoTestServiceImpl server
93 ServerBuilder builder;
94 echo_test_service_impl_ = std::make_unique<EchoTestServiceImpl>(
95 "hostname", "v1", forwarding_address_);
96 builder.RegisterService(echo_test_service_impl_.get());
97 int port = grpc_pick_unused_port_or_die();
98 server_address_ = grpc_core::JoinHostPort("localhost", port);
99 builder.AddListeningPort(server_address_, InsecureServerCredentials());
100 server_ = builder.BuildAndStart();
101
102 auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
103 stub_ = EchoTestService::NewStub(channel);
104 }
105
106 std::string forwarding_address_;
107 SimpleEchoTestServerImpl simple_test_service_impl_;
108 std::unique_ptr<EchoTestServiceImpl> echo_test_service_impl_;
109 std::string server_address_;
110 std::unique_ptr<Server> server_;
111 std::unique_ptr<Server> simple_server_;
112 std::unique_ptr<EchoTestService::Stub> stub_;
113 };
114
TEST_F(EchoTest,SimpleEchoTest)115 TEST_F(EchoTest, SimpleEchoTest) {
116 ClientContext context;
117 EchoRequest request;
118 EchoResponse response;
119 request.set_message("hello");
120 auto status = stub_->Echo(&context, request, &response);
121 ASSERT_TRUE(status.ok());
122 EXPECT_THAT(response.message(),
123 ::testing::AllOf(::testing::HasSubstr("StatusCode=200\n"),
124 ::testing::HasSubstr("Hostname=hostname\n"),
125 ::testing::HasSubstr("Echo=hello\n"),
126 ::testing::HasSubstr("Host="),
127 ::testing::HasSubstr("IP="),
128 ::testing::HasSubstr("ServiceVersion=v1")));
129 }
130
TEST_F(EchoTest,ForwardEchoTest)131 TEST_F(EchoTest, ForwardEchoTest) {
132 ClientContext context;
133 ForwardEchoRequest request;
134 ForwardEchoResponse response;
135 request.set_count(3);
136 request.set_qps(1);
137 request.set_timeout_micros(20 * 1000 * 1000); // 20 seconds
138 request.set_url(absl::StrCat("grpc://", server_address_));
139 request.set_message("hello");
140 auto status = stub_->ForwardEcho(&context, request, &response);
141 ASSERT_TRUE(status.ok());
142 for (int i = 0; i < 3; ++i) {
143 EXPECT_THAT(
144 response.output()[i],
145 ::testing::AllOf(
146 ::testing::HasSubstr(
147 absl::StrFormat("[%d body] StatusCode=200\n", i)),
148 ::testing::HasSubstr(
149 absl::StrFormat("[%d body] Hostname=hostname\n", i)),
150 ::testing::HasSubstr(absl::StrFormat("[%d body] Echo=hello\n", i)),
151 ::testing::HasSubstr(absl::StrFormat("[%d body] Host=", i)),
152 ::testing::HasSubstr(
153 absl::StrFormat("[%d body] ServiceVersion=v1", i))));
154 }
155 }
156
TEST_F(EchoTest,ForwardEchoTestUnhandledProtocols)157 TEST_F(EchoTest, ForwardEchoTestUnhandledProtocols) {
158 ClientContext context;
159 ForwardEchoRequest request;
160 ForwardEchoResponse response;
161 request.set_count(3);
162 request.set_qps(1);
163 request.set_timeout_micros(20 * 1000 * 1000); // 20 seconds
164 // http protocol is unhandled by EchoTestServiceImpl and should be forwarded
165 // to SimpleEchoTestServiceImpl
166 request.set_url(absl::StrCat("http://", server_address_));
167 request.set_message("hello");
168 auto status = stub_->ForwardEcho(&context, request, &response);
169 ASSERT_TRUE(status.ok()) << "Code = " << status.error_code()
170 << " Message = " << status.error_message();
171 ASSERT_FALSE(response.output().empty());
172 EXPECT_EQ(response.output()[0], "hello");
173 }
174
TEST_F(EchoTest,ForwardEchoFailure)175 TEST_F(EchoTest, ForwardEchoFailure) {
176 simple_test_service_impl_.set_fail_rpc(true);
177 ClientContext context;
178 ForwardEchoRequest request;
179 ForwardEchoResponse response;
180 request.set_count(3);
181 request.set_qps(1);
182 request.set_timeout_micros(20 * 1000 * 1000); // 20 seconds
183 // Use the unhandled protocol to make sure that we forward the request to
184 // SimpleEchoTestServerImpl.
185 request.set_url(absl::StrCat("http://", server_address_));
186 request.set_message("hello");
187 auto status = stub_->ForwardEcho(&context, request, &response);
188 ASSERT_EQ(status.error_code(), StatusCode::UNAVAILABLE);
189 }
190
191 } // namespace
192 } // namespace testing
193 } // namespace grpc
194
main(int argc,char ** argv)195 int main(int argc, char** argv) {
196 ::testing::InitGoogleTest(&argc, argv);
197 grpc::testing::TestEnvironment env(&argc, argv);
198 grpc_init();
199 auto result = RUN_ALL_TESTS();
200 grpc_shutdown();
201 return result;
202 }
203