def test_coroutine_cancelled_waitingforbody(container, transport): with unittest.mock.patch("asyncio.create_task") as mock: protocol = aioweb.protocol.HttpProtocol(container=container, loop=unittest.mock.Mock()) protocol.connection_made(transport) coro = mock.call_args.args[0] # # Invoke the worker loop. The loop should then wait on the queue # coro.send(None) # # Simulate data to make sure that the protocol creates a parser # request = b'''GET / HTTP/1.1 Host: example.com Content-Length: 3 X'''.replace(b'\n', b'\r\n') protocol.data_received(request) # # Now we should have written something into the queue. If we now # resume the coroutine, it should proceed into our handler and wait # for the body # future = coro.send(None) # # Throw a CancelledError # raised = False try: coro.throw(asyncio.exceptions.CancelledError()) except asyncio.exceptions.CancelledError: raised = True assert raised
def test_handler_returntypemismatch(container, transport): with unittest.mock.patch("asyncio.create_task") as mock: protocol = aioweb.protocol.HttpProtocol(container=container, loop=unittest.mock.Mock()) protocol.connection_made(transport) coro = mock.call_args.args[0] # # Ask the handler to return None # container._no_response = True # # Simulate data # request = b'''GET / HTTP/1.1 Host: example.com Content-Length: 3 XYZ'''.replace(b'\n', b'\r\n') protocol.data_received(request) # # We now have added a request object to the queue. Invoke the # worker loop which should proceed right into our handler # coro.send(None) assert container._request is not None
def test_transport_fails(container, transport): with unittest.mock.patch("asyncio.create_task") as mock: protocol = aioweb.protocol.HttpProtocol(container=container, loop=unittest.mock.Mock()) protocol.connection_made(transport) coro = mock.call_args.args[0] # # Ask the transport to raise an error # transport.fail_next() # # Simulate data to make sure that the protocol creates a parser # request = b'''GET / HTTP/1.1 Host: example.com Content-Length: 3 XYZ'''.replace(b'\n', b'\r\n') protocol.data_received(request) # # We now have added a request object to the queue. Invoke the # worker loop which should proceed right into our handler but # ignore the error # coro.send(None) assert container._request is not None
def test_transport_is_closing(transport): with unittest.mock.patch("asyncio.create_task") as mock: protocol = aioweb.protocol.HttpProtocol(container=None, loop=unittest.mock.Mock()) protocol.connection_made(transport) coro = mock.call_args.args[0] # # Close transport # transport.close() # # Simulate data to make sure that the protocol creates a parser # request = b'''GET / HTTP/1.1 Host: example.com Content-Length: 3 XYZ'''.replace(b'\n', b'\r\n') protocol.data_received(request) # # We now have added a request object to the queue. Invoke the # worker loop. This should return as the transport is already closed # raised = False try: coro.send(None) except StopIteration: raised = True assert raised
def test_full_request_lifecycle_handler_baseexception(transport, container): protocol = aioweb.protocol.HttpProtocol(container=container) with unittest.mock.patch("asyncio.create_task") as mock: protocol.connection_made(transport) coro = mock.call_args.args[0] # # When we now start our coroutine, it should suspend and wait # coro.send(None) # # Feed some data # request = b'''GET / HTTP/1.1 Host: example.com Content-Length: 3 XYZ''' protocol.data_received(request.replace(b'\n', b'\r\n')) # # When we now call send on the coroutine to simulate that the event # loop reschedules it, it should invoke our handler function. We instruct # the dummy handler to raise an exception # container.set_exception(BaseException()) coro.send(None) # # Make sure that the handler has been called # assert container._request is not None # # Verify some attributes of the request object # request = container._request assert isinstance(request, aioweb.request.Request) headers = request.headers() assert headers is not None assert isinstance(headers, dict) assert "Host" in headers assert headers["Host"] == b"example.com" assert request.http_version() == "1.1" # # Verify that we have written back something into the transport # assert len(transport._data) > 0 # # Now let us try to parse the response data # parser_helper = ParserHelper() parser = httptools.HttpResponseParser(parser_helper) parser.feed_data(transport._data) # # If we get to this point, this is a valid HTTP response # assert parser.get_status_code() == 500 # # Finally check that the transport is not closed # assert not transport._is_closing
def test_on_headers_complete(): with unittest.mock.patch( "aioweb.protocol.httptools.HttpRequestParser") as mock: with unittest.mock.patch("aioweb.protocol.asyncio.Queue") as Queue: protocol = aioweb.protocol.HttpProtocol(container=None, loop=unittest.mock.Mock()) # # Simulate data to make sure that the protocol creates a parser # protocol.data_received(b"X") protocol.on_header(b"Host", b"127.0.0.1") protocol.on_headers_complete() queue = Queue.return_value # # Verify the state # assert protocol.get_state() == aioweb.protocol.ConnectionState.BODY # # Check that we have added something to the queue # queue.put_nowait.assert_called()
def test_full_request_lifecycle_http11(transport, container): protocol = aioweb.protocol.HttpProtocol(container=container) with unittest.mock.patch("asyncio.create_task") as mock: protocol.connection_made(transport) coro = mock.call_args.args[0] # # When we now start our coroutine, it should suspend and wait # coro.send(None) # # Feed some data and complete the headers # request = b'''GET / HTTP/1.1 Host: example.com Content-Length: 3 X''' protocol.data_received(request.replace(b'\n', b'\r\n')) assert protocol.get_state() == aioweb.protocol.ConnectionState.BODY # # When we now call send on the coroutine to simulate that the event # loop reschedules it, it should invoke our handler function # coro.send(None) # # Make sure that the handler has been called # assert container._request is not None # # Verify some attributes of the request object # request = container._request assert isinstance(request, aioweb.request.Request) headers = request.headers() assert headers is not None assert isinstance(headers, dict) assert "Host" in headers assert headers["Host"] == b"example.com" assert request.http_version() == "1.1" # # Get the future to wait for completion of the body # future = request.body().send(None) # # In our case, the body should not be complete yet # assert not future.done() # # complete it # request = b'YZ' protocol.data_received(request) assert protocol.get_state() == aioweb.protocol.ConnectionState.PENDING # # At this point, our future should be complete # body = future.result() assert body == b"XYZ" # # Verify that we have written back something into the transport # assert len(transport._data) > 0 # # Now let us try to parse the response data # parser_helper = ParserHelper() parser = httptools.HttpResponseParser(parser_helper) parser.feed_data(transport._data) # # If we get to this point, this is a valid HTTP response # assert parser.get_status_code() == 200 assert parser_helper._body == b"abc" # # Finally check that the transport is not closed # assert not transport._is_closing
def test_pipelining(transport, container): protocol = aioweb.protocol.HttpProtocol(container=container) with unittest.mock.patch("asyncio.create_task") as mock: protocol.connection_made(transport) coro = mock.call_args.args[0] # # Feed a first complete record # request = b'''GET / HTTP/1.1 Host: example1.com Content-Length: 3 XYZ''' protocol.data_received(request.replace(b'\n', b'\r\n')) assert protocol.get_state() == aioweb.protocol.ConnectionState.PENDING # # Now feed a second record # request = b'''GET / HTTP/1.1 Host: example2.com Content-Length: 3 123''' protocol.data_received(request.replace(b'\n', b'\r\n')) assert protocol.get_state() == aioweb.protocol.ConnectionState.PENDING # # Now simulate the event loop and run the coroutine for the first time # coro.send(None) # # This should again block on the queue, but only after the two records # have been received. Thus we should have invoked our handler twice # assert container._request_count == 2 # # Get the first request # request = container._requests[0] assert isinstance(request, aioweb.request.Request) # # this should be the first request # assert request.headers()['Host'] == b"example1.com" # # check content of first response # assert container._replies[0] == b"XYZ" # # Now check the second request # request = container._requests[1] assert isinstance(request, aioweb.request.Request) assert request.headers()['Host'] == b"example2.com" assert container._replies[1] == b"123" # # Now we check that two responses have been written into # the transport. We get them from the transport and send them # through our parser # parser_helper = ParserHelper() parser = httptools.HttpResponseParser(parser_helper) parser.feed_data(transport._messages[0]) assert parser.get_status_code() == 200 assert bytes(parser_helper._body) == b"XYZ" parser_helper = ParserHelper() parser = httptools.HttpResponseParser(parser_helper) parser.feed_data(transport._messages[1]) assert parser.get_status_code() == 200 assert bytes(parser_helper._body) == b"123"