async def test_send_trailing_metadata_on_closed_stream(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) request = Request(method='POST', scheme='http', path='/', content_type='application/grpc+proto', authority='test.com') client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(request.to_headers(), _processor=client_proc) request = DummyRequest(value='ping') await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = decode_metadata(server_proc.handler.headers) send_trailing_metadata_done = False async with Stream(server_h2_stream, Cardinality.UNARY_UNARY, ProtoCodec(), DummyRequest, DummyReply, metadata=request_metadata) as server_stream: await server_stream.send_trailing_metadata(status=Status.UNKNOWN) send_trailing_metadata_done = True assert send_trailing_metadata_done
async def test_send_headers_into_closed_stream(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_processor = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() server_processor = EventsProcessor(DummyHandler(), server_conn) request = Request(method='POST', scheme='http', path='/', content_type='application/grpc+proto', authority='test.com') await client_stream.send_request(request.to_headers(), _processor=client_processor) to_server_transport.process(server_processor) server_stream, = server_processor.streams.values() server_stream._h2_connection.streams.pop(server_stream.id) with pytest.raises(StreamClosedError): await server_stream.send_headers([(':status', '200')])
async def test_unread_data_ack(loop): client_h2c, server_h2c = create_connections() initial_window = client_h2c.outbound_flow_control_window # should be large enough to trigger WINDOW_UPDATE frame data_size = initial_window - 1 to_client_transport = TransportStub(client_h2c) server_handler = DummyHandler() server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(server_handler, server_conn) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_proc = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() await client_stream.send_request(create_headers(), _processor=client_proc) await client_stream.send_data(b'x' * data_size) assert client_h2c.outbound_flow_control_window == initial_window - data_size to_server_transport.process(server_proc) # server_handler.stream.recv_data(data_size) intentionally not called await server_handler.stream.send_headers( [ # trailers-only error (':status', '200'), ('content-type', 'application/grpc+proto'), ('grpc-status', str(Status.UNKNOWN.value)), ], end_stream=True) to_client_transport.process(client_proc) assert client_h2c.outbound_flow_control_window == initial_window - data_size server_handler.release_stream() # should ack received data assert client_h2c.outbound_flow_control_window == initial_window
async def test_exit_and_connection_was_closed(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) request = Request('POST', 'http', '/', content_type='application/grpc+proto', authority='test.com') client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(request.to_headers(), _processor=client_proc) request = DummyRequest(value='ping') await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = Metadata.from_headers(server_proc.handler.headers) async with Stream(server_h2_stream, Cardinality.UNARY_UNARY, ProtoCodec(), DummyRequest, DummyReply, metadata=request_metadata) as server_stream: await server_stream.recv_message() client_h2c.close_connection() to_server_transport.process(server_proc) raise ServerError() # should be suppressed
async def test_exit_and_connection_was_broken(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(create_headers(), _processor=client_proc) request = DummyRequest(value='ping') await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = decode_metadata(server_proc.handler.headers) with pytest.raises(WriteError): async with mk_stream(server_h2_stream, request_metadata) as server_stream: server_stream.metadata = request_metadata await server_stream.recv_message() # simulate broken connection to_client_transport.__raise_on_write__(WriteError)
async def test_exit_and_connection_was_closed(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(create_headers(), _processor=client_proc) request = DummyRequest(value='ping') await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = decode_metadata(server_proc.handler.headers) async with mk_stream(server_h2_stream, request_metadata) as server_stream: await server_stream.recv_message() client_h2c.close_connection() to_server_transport.process(server_proc) raise ServerError() # should be suppressed
async def test_exit_and_stream_was_closed(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(create_headers(), _processor=client_proc) request = DummyRequest(value='ping') await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = decode_metadata(server_proc.handler.headers) async with mk_stream(server_h2_stream, request_metadata) as server_stream: await server_stream.recv_message() # simulating client closing stream await client_h2_stream.reset() to_server_transport.process(server_proc) # we should fail here on this attempt to send something await server_stream.send_message(DummyReply(value='pong'))
async def test_send_trailing_metadata_on_closed_stream(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(create_headers(), _processor=client_proc) request = DummyRequest(value='ping') await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = decode_metadata(server_proc.handler.headers) send_trailing_metadata_done = False async with mk_stream(server_h2_stream, request_metadata) as server_stream: await server_stream.send_trailing_metadata(status=Status.UNKNOWN) send_trailing_metadata_done = True assert send_trailing_metadata_done
async def test_exit_and_connection_was_broken(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) request = Request(method='POST', scheme='http', path='/', content_type='application/grpc+proto', authority='test.com') client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(request.to_headers(), _processor=client_proc) request = DummyRequest(value='ping') await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = decode_metadata(server_proc.handler.headers) with pytest.raises(WriteError): async with Stream(server_h2_stream, Cardinality.UNARY_UNARY, ProtoCodec(), DummyRequest, DummyReply, metadata=request_metadata) as server_stream: await server_stream.recv_message() # simulate broken connection to_client_transport.__raise_on_write__(WriteError)
async def test_exit_and_connection_was_broken(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) request = Request('POST', 'http', '/', authority='test.com') client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request(request.to_headers(), _processor=client_proc) request = SavoysRequest(kyler='cloth') await send_message(client_h2_stream, request, SavoysRequest, end=True) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream request_metadata = Metadata.from_headers(server_proc.handler.headers) with pytest.raises(WriteError): async with Stream(server_h2_stream, Cardinality.UNARY_UNARY, SavoysRequest, SavoysReply, metadata=request_metadata) as server_stream: await server_stream.recv_message() # simulate broken connection to_client_transport.__raise_on_write__(WriteError)
async def test_recv_data_larger_than_window_size(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_processor = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() request = Request(method='POST', scheme='http', path='/', content_type='application/grpc+proto', authority='test.com') await client_stream.send_request(request.to_headers(), _processor=client_processor) initial_window = server_h2c.local_settings.initial_window_size assert (client_h2c.local_flow_control_window( client_stream.id) == initial_window) # data should be bigger than window size data = b'0' * (initial_window + 1) size = len(data) # sending less than a full message await client_stream.send_data(data[:initial_window - 1]) # let server process it's events server_processor = EventsProcessor(DummyHandler(), server_conn) for event in to_server_transport.events(): server_processor.process(event) # checking window size was decreased assert client_h2c.local_flow_control_window(client_stream.id) == 1 # simulate that server is waiting for the size of a message and should # acknowledge that size as soon as it will be received server_stream, = server_processor.streams.values() recv_task = loop.create_task(server_stream.recv_data(size)) await asyncio.wait([recv_task], timeout=.01, loop=loop) assert server_stream.__buffer__._read_size == size assert server_stream.__buffer__._size == initial_window - 1 # check that server acknowledged received partial data assert client_h2c.local_flow_control_window(client_stream.id) > 1 # sending remaining data and recv_task should finish await client_stream.send_data(data[initial_window - 1:]) for event in to_server_transport.events(): server_processor.process(event) await asyncio.wait_for(recv_task, 0.01, loop=loop) assert server_stream.__buffer__._size == 0
async def test_client_reset( loop, caplog, handler, level, msg, exc_type, exc_text, config, ): caplog.set_level(logging.INFO) client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, config=config) server_conn = Connection(server_h2c, to_client_transport, config=config) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request( create_headers(path='/package.Service/Method'), _processor=client_proc, ) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream methods = { '/package.Service/Method': Handler( handler, Cardinality.UNARY_UNARY, DummyRequest, DummyReply, ) } task = loop.create_task( call_handler(methods, server_h2_stream, server_proc.handler.headers)) await asyncio.wait([task], timeout=0.001) await client_h2_stream.reset() to_server_transport.process(server_proc) await asyncio.wait_for(task, 0.1) record, = caplog.records assert record.name == 'grpclib.server' assert record.levelname == level assert msg in record.getMessage() if exc_type is not None: assert record.exc_info[0] is exc_type if exc_text is not None: assert exc_text in record.exc_text
async def test_stream_release(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_processor = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() server_processor = EventsProcessor(DummyHandler(), server_conn) request = Request(method='POST', scheme='http', path='/', content_type='application/grpc+proto', authority='test.com') assert not client_processor.streams client_release_stream = await client_stream.send_request( request.to_headers(), _processor=client_processor, ) assert client_release_stream and client_processor.streams # sending data and closing stream on the client-side msg = b'message' await client_stream.send_data(msg, end_stream=True) events1 = to_server_transport.process(server_processor) assert any(isinstance(e, StreamEnded) for e in events1), events1 # intentionally sending some stream-specific frame after stream was # half-closed client_h2c.increment_flow_control_window(10, stream_id=client_stream.id) client_conn.flush() events2 = to_server_transport.process(server_processor) assert any(isinstance(e, WindowUpdated) for e in events2), events2 server_stream, = server_processor.streams.values() await server_stream.recv_data(len(msg)) await server_stream.end() events3 = to_client_transport.process(client_processor) assert any(isinstance(e, StreamEnded) for e in events3), events3 # simulating request handler exit by releasing server-side stream server_processor.handler.release_stream() assert not server_processor.streams # simulating call exit by releasing client-side stream assert client_processor.streams client_release_stream() assert not client_processor.streams
async def test_stream_release(config): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, config=config) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, config=config) client_processor = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() server_processor = EventsProcessor(DummyHandler(), server_conn) assert not client_processor.streams client_release_stream = await client_stream.send_request( create_headers(), _processor=client_processor, ) assert client_release_stream and client_processor.streams # sending data and closing stream on the client-side msg = b'message' await client_stream.send_data(msg, end_stream=True) events1 = to_server_transport.process(server_processor) assert any(isinstance(e, StreamEnded) for e in events1), events1 # intentionally sending some stream-specific frame after stream was # half-closed client_h2c.increment_flow_control_window(10, stream_id=client_stream.id) client_conn.flush() events2 = to_server_transport.process(server_processor) assert any(isinstance(e, WindowUpdated) for e in events2), events2 server_stream, = server_processor.streams.values() await server_stream.recv_data(len(msg)) await server_stream.send_headers([(':status', '200')], end_stream=True) events3 = to_client_transport.process(client_processor) assert any(isinstance(e, StreamEnded) for e in events3), events3 # simulating request handler exit by releasing server-side stream server_processor.handler.release_stream() assert not server_processor.streams # simulating call exit by releasing client-side stream assert client_processor.streams client_release_stream() assert not client_processor.streams
async def test_recv_data_larger_than_window_size(loop, config): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, config=config) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, config=config) client_proc = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() await client_stream.send_request(create_headers(), _processor=client_proc) initial_window = server_h2c.local_settings.initial_window_size assert (client_h2c.local_flow_control_window( client_stream.id) == initial_window) # data should be bigger than window size data = b'0' * (initial_window + 1) size = len(data) # sending less than a full message await client_stream.send_data(data[:initial_window - 1]) # let server process it's events server_processor = EventsProcessor(DummyHandler(), server_conn) to_server_transport.process(server_processor) # checking window size was decreased assert client_h2c.local_flow_control_window(client_stream.id) == 1 # simulate that server is waiting for the size of a message and should # acknowledge that size as soon as it will be received server_stream, = server_processor.streams.values() recv_task = loop.create_task(server_stream.recv_data(size)) await asyncio.wait([recv_task], timeout=.01) assert server_stream.buffer._acked_size == initial_window - 1 # check that server acknowledged received partial data assert client_h2c.local_flow_control_window(client_stream.id) > 1 # sending remaining data and recv_task should finish await client_stream.send_data(data[initial_window - 1:]) to_server_transport.process(server_processor) await asyncio.wait_for(recv_task, 0.01) assert server_stream.buffer._acked_size == 0
async def test_client_reset(loop, caplog): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) server_conn = Connection(server_h2c, to_client_transport, loop=loop) server_proc = EventsProcessor(DummyHandler(), server_conn) client_proc = EventsProcessor(DummyHandler(), client_conn) client_h2_stream = client_conn.create_stream() await client_h2_stream.send_request( create_headers(path='/package.Service/Method'), _processor=client_proc, ) to_server_transport.process(server_proc) server_h2_stream = server_proc.handler.stream success = [] async def _method(_): try: await asyncio.sleep(1) except asyncio.CancelledError: success.append(True) raise methods = {'/package.Service/Method': Handler( _method, Cardinality.UNARY_UNARY, DummyRequest, DummyReply, )} task = loop.create_task( call_handler(methods, server_h2_stream, server_proc.handler.headers) ) await asyncio.wait([task], timeout=0.001) await client_h2_stream.reset() to_server_transport.process(server_proc) await asyncio.wait_for(task, 0.1, loop=loop) assert success == [True] assert 'Request was cancelled' in caplog.text
async def test_send_data_larger_than_frame_size(loop): client_h2c, server_h2c = create_connections() transport = TransportStub(server_h2c) conn = Connection(client_h2c, transport, loop=loop) stream = conn.create_stream() processor = EventsProcessor(DummyHandler(), conn) await stream.send_request(create_headers(), _processor=processor) await stream.send_data(b'0' * (client_h2c.max_outbound_frame_size + 1))
async def test_ping(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_processor = EventsProcessor(DummyHandler(), client_conn) server_processor = EventsProcessor(DummyHandler(), server_conn) client_h2c.ping(b'12345678') client_conn.flush() to_server_transport.process(server_processor) server_conn.flush() ping_ack, = to_client_transport.process(client_processor) assert isinstance(ping_ack, PingAcknowledged) assert ping_ack.ping_data == b'12345678'
async def test_send_headers_into_closed_stream(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_proc = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() server_processor = EventsProcessor(DummyHandler(), server_conn) await client_stream.send_request(create_headers(), _processor=client_proc) to_server_transport.process(server_processor) server_stream, = server_processor.streams.values() server_stream._h2_connection.streams.pop(server_stream.id) with pytest.raises(StreamClosedError): await server_stream.send_headers([(':status', '200')])
async def test_send_data_larger_than_frame_size(loop): client_h2c, server_h2c = create_connections() transport = TransportStub(server_h2c) conn = Connection(client_h2c, transport, loop=loop) stream = conn.create_stream() request = Request('POST', 'http', '/', content_type='application/grpc+proto', authority='test.com') processor = EventsProcessor(DummyHandler(), conn) await stream.send_request(request.to_headers(), _processor=processor) await stream.send_data(b'0' * (client_h2c.max_outbound_frame_size + 1))
async def test_negative_window_size(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_proc = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() await client_stream.send_request(create_headers(), _processor=client_proc) # data should be bigger than window size initial_window = server_h2c.local_settings.initial_window_size data = b'0' * (initial_window + 1) assert (client_h2c.local_flow_control_window( client_stream.id) == initial_window) # send_data should wait until settings/window updated send_task = loop.create_task(client_stream.send_data(data)) await asyncio.wait([send_task], timeout=0.01) assert client_h2c.local_flow_control_window(client_stream.id) == 0 # updating settings, this should decrease connection window size server_h2c.update_settings( {SettingCodes.INITIAL_WINDOW_SIZE: initial_window - 1}) server_conn.flush() to_client_transport.process(client_proc) # window is negative and client should wait assert client_h2c.local_flow_control_window(client_stream.id) == -1 await asyncio.wait([send_task], timeout=0.01) assert not send_task.done() # now `send_data` should succeed server_h2c.increment_flow_control_window(2, stream_id=client_stream.id) # INITIAL_WINDOW_SIZE not changes connection's window size, so it should be # incremented only by 1 server_h2c.increment_flow_control_window(1, stream_id=None) server_conn.flush() to_client_transport.process(client_proc) assert client_h2c.local_flow_control_window(client_stream.id) == 1 await asyncio.wait([send_task], timeout=0.01) assert send_task.result() is None
def __init__(self, *, loop): client_config = H2Configuration(client_side=True, header_encoding='utf-8') self.client_h2c = H2Connection(client_config) self.to_client_transport = TransportStub(self.client_h2c) self.client_h2c.initiate_connection() server_config = H2Configuration(client_side=False, header_encoding='utf-8') self.server_proto = H2Protocol(DummyHandler(), server_config, loop=loop) self.server_proto.connection_made(self.to_client_transport) # complete settings exchange and clear events buffer self.client_flush() self.to_client_transport.events()
async def test_initial_window_size_update(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_processor = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() request = Request(method='POST', scheme='http', path='/', content_type='application/grpc+proto', authority='test.com') await client_stream.send_request(request.to_headers(), _processor=client_processor) # data should be bigger than window size initial_window = server_h2c.local_settings.initial_window_size data = b'0' * (initial_window + 1) assert (client_h2c.local_flow_control_window( client_stream.id) == initial_window) # send_data should wait until settings/window updated send_task = loop.create_task(client_stream.send_data(data)) await asyncio.wait([send_task], timeout=0.01) assert client_h2c.local_flow_control_window(client_stream.id) == 0 # updating settings and window, this should increase stream window size server_h2c.update_settings( {SettingCodes.INITIAL_WINDOW_SIZE: initial_window + 1}) server_h2c.increment_flow_control_window(1, stream_id=None) server_conn.flush() to_client_transport.process(client_processor) assert client_h2c.local_flow_control_window(client_stream.id) == 1 await asyncio.wait([send_task], timeout=0.01) assert send_task.done()
async def test_release_stream_after_close(config): client_h2c, server_h2c = create_connections() to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, config=config) client_proc = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() release_stream = await client_stream.send_request(create_headers(), _processor=client_proc) # to trigger connection.ack client_stream.buffer.add(b'test', 4) # to trigger data send client_h2c.ping(b'00000000') client_proc.close('test') release_stream()
async def test_receive_goaway(config): wrapper = Wrapper() client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, config=config) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, config=config) client_proc = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream(wrapper=wrapper) await client_stream.send_request(create_headers(), _processor=client_proc) server_h2c.close_connection() server_conn.flush() to_client_transport.process(client_proc) with pytest.raises(StreamTerminatedError, match='Received GOAWAY frame'): with wrapper: pass
async def test_initial_window_size_update(loop): client_h2c, server_h2c = create_connections() to_client_transport = TransportStub(client_h2c) server_conn = Connection(server_h2c, to_client_transport, loop=loop) to_server_transport = TransportStub(server_h2c) client_conn = Connection(client_h2c, to_server_transport, loop=loop) client_proc = EventsProcessor(DummyHandler(), client_conn) client_stream = client_conn.create_stream() await client_stream.send_request(create_headers(), _processor=client_proc) # data should be bigger than window size initial_window = server_h2c.local_settings.initial_window_size data = b'0' * (initial_window + 1) assert (client_h2c.local_flow_control_window( client_stream.id) == initial_window) # send_data should wait until settings/window updated send_task = loop.create_task(client_stream.send_data(data)) await asyncio.wait([send_task], timeout=0.01) assert client_h2c.local_flow_control_window(client_stream.id) == 0 # updating settings and window, this should increase stream window size server_h2c.update_settings( {SettingCodes.INITIAL_WINDOW_SIZE: initial_window + 1}) server_h2c.increment_flow_control_window(1, stream_id=None) server_conn.flush() to_client_transport.process(client_proc) assert client_h2c.local_flow_control_window(client_stream.id) == 1 await asyncio.wait([send_task], timeout=0.01) assert send_task.result() is None