xref: /aosp_15_r20/external/grpc-grpc/src/python/grpcio_tests/tests/http2/negative_http2_client.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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