1 /* 2 * 3 * Copyright 2016 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #include <thread> 20 21 #include <gflags/gflags.h> 22 #include <grpc/support/alloc.h> 23 #include <grpc/support/log.h> 24 #include <grpcpp/channel.h> 25 #include <grpcpp/client_context.h> 26 27 #include "src/core/lib/transport/byte_stream.h" 28 #include "src/proto/grpc/testing/messages.pb.h" 29 #include "src/proto/grpc/testing/test.grpc.pb.h" 30 #include "test/cpp/interop/http2_client.h" 31 32 #include "src/core/lib/gpr/string.h" 33 #include "src/core/lib/gpr/useful.h" 34 #include "test/cpp/util/create_test_channel.h" 35 #include "test/cpp/util/test_config.h" 36 37 namespace grpc { 38 namespace testing { 39 40 namespace { 41 const int kLargeRequestSize = 271828; 42 const int kLargeResponseSize = 314159; 43 } // namespace 44 45 Http2Client::ServiceStub::ServiceStub(const std::shared_ptr<Channel>& channel) 46 : channel_(std::move(channel)) { 47 stub_ = TestService::NewStub(channel); 48 } 49 50 TestService::Stub* Http2Client::ServiceStub::Get() { return stub_.get(); } 51 52 Http2Client::Http2Client(const std::shared_ptr<Channel>& channel) 53 : serviceStub_(channel), 54 channel_(std::move(channel)), 55 defaultRequest_(BuildDefaultRequest()) {} 56 57 bool Http2Client::AssertStatusCode(const Status& s, StatusCode expected_code) { 58 if (s.error_code() == expected_code) { 59 return true; 60 } 61 62 gpr_log(GPR_ERROR, "Error status code: %d (expected: %d), message: %s", 63 s.error_code(), expected_code, s.error_message().c_str()); 64 abort(); 65 } 66 67 Status Http2Client::SendUnaryCall(SimpleResponse* response) { 68 ClientContext context; 69 return serviceStub_.Get()->UnaryCall(&context, defaultRequest_, response); 70 } 71 72 SimpleRequest Http2Client::BuildDefaultRequest() { 73 SimpleRequest request; 74 request.set_response_size(kLargeResponseSize); 75 grpc::string payload(kLargeRequestSize, '\0'); 76 request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize); 77 return request; 78 } 79 80 bool Http2Client::DoRstAfterHeader() { 81 gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after header"); 82 83 SimpleResponse response; 84 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::INTERNAL); 85 GPR_ASSERT(!response.has_payload()); // no data should be received 86 87 gpr_log(GPR_DEBUG, "Done testing reset stream after header"); 88 return true; 89 } 90 91 bool Http2Client::DoRstAfterData() { 92 gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after data"); 93 94 SimpleResponse response; 95 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::INTERNAL); 96 // There is no guarantee that data would be received. 97 98 gpr_log(GPR_DEBUG, "Done testing reset stream after data"); 99 return true; 100 } 101 102 bool Http2Client::DoRstDuringData() { 103 gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream during data"); 104 105 SimpleResponse response; 106 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::INTERNAL); 107 GPR_ASSERT(!response.has_payload()); // no data should be received 108 109 gpr_log(GPR_DEBUG, "Done testing reset stream during data"); 110 return true; 111 } 112 113 bool Http2Client::DoGoaway() { 114 gpr_log(GPR_DEBUG, "Sending two RPCs and expecting goaway"); 115 SimpleResponse response; 116 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK); 117 GPR_ASSERT(response.payload().body() == 118 grpc::string(kLargeResponseSize, '\0')); 119 120 // Sleep for one second to give time for client to receive goaway frame. 121 gpr_timespec sleep_time = gpr_time_add( 122 gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(1, GPR_TIMESPAN)); 123 gpr_sleep_until(sleep_time); 124 125 response.Clear(); 126 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK); 127 GPR_ASSERT(response.payload().body() == 128 grpc::string(kLargeResponseSize, '\0')); 129 gpr_log(GPR_DEBUG, "Done testing goaway"); 130 return true; 131 } 132 133 bool Http2Client::DoPing() { 134 gpr_log(GPR_DEBUG, "Sending RPC and expecting ping"); 135 SimpleResponse response; 136 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK); 137 GPR_ASSERT(response.payload().body() == 138 grpc::string(kLargeResponseSize, '\0')); 139 gpr_log(GPR_DEBUG, "Done testing ping"); 140 return true; 141 } 142 143 void Http2Client::MaxStreamsWorker( 144 const std::shared_ptr<grpc::Channel>& channel) { 145 SimpleResponse response; 146 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK); 147 GPR_ASSERT(response.payload().body() == 148 grpc::string(kLargeResponseSize, '\0')); 149 } 150 151 bool Http2Client::DoMaxStreams() { 152 gpr_log(GPR_DEBUG, "Testing max streams"); 153 154 // Make an initial call on the channel to ensure the server's max streams 155 // setting is received 156 SimpleResponse response; 157 AssertStatusCode(SendUnaryCall(&response), grpc::StatusCode::OK); 158 GPR_ASSERT(response.payload().body() == 159 grpc::string(kLargeResponseSize, '\0')); 160 161 std::vector<std::thread> test_threads; 162 163 for (int i = 0; i < 10; i++) { 164 test_threads.emplace_back( 165 std::thread(&Http2Client::MaxStreamsWorker, this, channel_)); 166 } 167 168 for (auto it = test_threads.begin(); it != test_threads.end(); it++) { 169 it->join(); 170 } 171 172 gpr_log(GPR_DEBUG, "Done testing max streams"); 173 return true; 174 } 175 176 } // namespace testing 177 } // namespace grpc 178 179 DEFINE_int32(server_port, 0, "Server port."); 180 DEFINE_string(server_host, "localhost", "Server host to connect to"); 181 DEFINE_string(test_case, "rst_after_header", 182 "Configure different test cases. Valid options are:\n\n" 183 "goaway\n" 184 "max_streams\n" 185 "ping\n" 186 "rst_after_data\n" 187 "rst_after_header\n" 188 "rst_during_data\n"); 189 190 int main(int argc, char** argv) { 191 grpc::testing::InitTest(&argc, &argv, true); 192 GPR_ASSERT(FLAGS_server_port); 193 const int host_port_buf_size = 1024; 194 char host_port[host_port_buf_size]; 195 snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(), 196 FLAGS_server_port); 197 std::shared_ptr<grpc::Channel> channel = 198 grpc::CreateTestChannel(host_port, grpc::testing::INSECURE); 199 GPR_ASSERT(channel->WaitForConnected(gpr_time_add( 200 gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(300, GPR_TIMESPAN)))); 201 grpc::testing::Http2Client client(channel); 202 gpr_log(GPR_INFO, "Testing case: %s", FLAGS_test_case.c_str()); 203 int ret = 0; 204 if (FLAGS_test_case == "rst_after_header") { 205 client.DoRstAfterHeader(); 206 } else if (FLAGS_test_case == "rst_after_data") { 207 client.DoRstAfterData(); 208 } else if (FLAGS_test_case == "rst_during_data") { 209 client.DoRstDuringData(); 210 } else if (FLAGS_test_case == "goaway") { 211 client.DoGoaway(); 212 } else if (FLAGS_test_case == "ping") { 213 client.DoPing(); 214 } else if (FLAGS_test_case == "max_streams") { 215 client.DoMaxStreams(); 216 } else { 217 const char* testcases[] = { 218 "goaway", "max_streams", "ping", 219 "rst_after_data", "rst_after_header", "rst_during_data"}; 220 char* joined_testcases = 221 gpr_strjoin_sep(testcases, GPR_ARRAY_SIZE(testcases), "\n", nullptr); 222 223 gpr_log(GPR_ERROR, "Unsupported test case %s. Valid options are\n%s", 224 FLAGS_test_case.c_str(), joined_testcases); 225 gpr_free(joined_testcases); 226 ret = 1; 227 } 228 229 return ret; 230 } 231