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