1# Copyright 2016 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""The Python client used to test negative http2 conditions.""" 15 16import argparse 17import time 18 19import grpc 20 21from src.proto.grpc.testing import messages_pb2 22from src.proto.grpc.testing import test_pb2_grpc 23 24 25def _validate_payload_type_and_length(response, expected_type, expected_length): 26 if response.payload.type is not expected_type: 27 raise ValueError( 28 "expected payload type %s, got %s" 29 % (expected_type, type(response.payload.type)) 30 ) 31 elif len(response.payload.body) != expected_length: 32 raise ValueError( 33 "expected payload body size %d, got %d" 34 % (expected_length, len(response.payload.body)) 35 ) 36 37 38def _expect_status_code(call, expected_code): 39 if call.code() != expected_code: 40 raise ValueError( 41 "expected code %s, got %s" % (expected_code, call.code()) 42 ) 43 44 45def _expect_status_details(call, expected_details): 46 if call.details() != expected_details: 47 raise ValueError( 48 "expected message %s, got %s" % (expected_details, call.details()) 49 ) 50 51 52def _validate_status_code_and_details(call, expected_code, expected_details): 53 _expect_status_code(call, expected_code) 54 _expect_status_details(call, expected_details) 55 56 57# common requests 58_REQUEST_SIZE = 314159 59_RESPONSE_SIZE = 271828 60 61_SIMPLE_REQUEST = messages_pb2.SimpleRequest( 62 response_type=messages_pb2.COMPRESSABLE, 63 response_size=_RESPONSE_SIZE, 64 payload=messages_pb2.Payload(body=b"\x00" * _REQUEST_SIZE), 65) 66 67 68def _goaway(stub): 69 first_response = stub.UnaryCall(_SIMPLE_REQUEST) 70 _validate_payload_type_and_length( 71 first_response, messages_pb2.COMPRESSABLE, _RESPONSE_SIZE 72 ) 73 time.sleep(1) 74 second_response = stub.UnaryCall(_SIMPLE_REQUEST) 75 _validate_payload_type_and_length( 76 second_response, messages_pb2.COMPRESSABLE, _RESPONSE_SIZE 77 ) 78 79 80def _rst_after_header(stub): 81 resp_future = stub.UnaryCall.future(_SIMPLE_REQUEST) 82 _validate_status_code_and_details( 83 resp_future, 84 grpc.StatusCode.INTERNAL, 85 "Received RST_STREAM with error code 0", 86 ) 87 88 89def _rst_during_data(stub): 90 resp_future = stub.UnaryCall.future(_SIMPLE_REQUEST) 91 _validate_status_code_and_details( 92 resp_future, 93 grpc.StatusCode.INTERNAL, 94 "Received RST_STREAM with error code 0", 95 ) 96 97 98def _rst_after_data(stub): 99 resp_future = stub.UnaryCall.future(_SIMPLE_REQUEST) 100 _validate_status_code_and_details( 101 resp_future, 102 grpc.StatusCode.INTERNAL, 103 "Received RST_STREAM with error code 0", 104 ) 105 106 107def _ping(stub): 108 response = stub.UnaryCall(_SIMPLE_REQUEST) 109 _validate_payload_type_and_length( 110 response, messages_pb2.COMPRESSABLE, _RESPONSE_SIZE 111 ) 112 113 114def _max_streams(stub): 115 # send one req to ensure server sets MAX_STREAMS 116 response = stub.UnaryCall(_SIMPLE_REQUEST) 117 _validate_payload_type_and_length( 118 response, messages_pb2.COMPRESSABLE, _RESPONSE_SIZE 119 ) 120 121 # give the streams a workout 122 futures = [] 123 for _ in range(15): 124 futures.append(stub.UnaryCall.future(_SIMPLE_REQUEST)) 125 for future in futures: 126 _validate_payload_type_and_length( 127 future.result(), messages_pb2.COMPRESSABLE, _RESPONSE_SIZE 128 ) 129 130 131def _run_test_case(test_case, stub): 132 if test_case == "goaway": 133 _goaway(stub) 134 elif test_case == "rst_after_header": 135 _rst_after_header(stub) 136 elif test_case == "rst_during_data": 137 _rst_during_data(stub) 138 elif test_case == "rst_after_data": 139 _rst_after_data(stub) 140 elif test_case == "ping": 141 _ping(stub) 142 elif test_case == "max_streams": 143 _max_streams(stub) 144 else: 145 raise ValueError("Invalid test case: %s" % test_case) 146 147 148def _args(): 149 parser = argparse.ArgumentParser() 150 parser.add_argument( 151 "--server_host", 152 help="the host to which to connect", 153 type=str, 154 default="127.0.0.1", 155 ) 156 parser.add_argument( 157 "--server_port", 158 help="the port to which to connect", 159 type=int, 160 default="8080", 161 ) 162 parser.add_argument( 163 "--test_case", 164 help="the test case to execute", 165 type=str, 166 default="goaway", 167 ) 168 return parser.parse_args() 169 170 171def _stub(server_host, server_port): 172 target = "{}:{}".format(server_host, server_port) 173 channel = grpc.insecure_channel(target) 174 grpc.channel_ready_future(channel).result() 175 return test_pb2_grpc.TestServiceStub(channel) 176 177 178def main(): 179 args = _args() 180 stub = _stub(args.server_host, args.server_port) 181 _run_test_case(args.test_case, stub) 182 183 184if __name__ == "__main__": 185 main() 186