async def test_start_stop(): async def server_handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): assert await reader.readuntil(b"\r\n\r\n" ) == b"GET /hello HTTP/1.1\r\n\r\n" writer.write(b"HTTP/1.1 204 No Content\r\n\r\n") await writer.drain() writer.close() ps = Proxyserver() with taddons.context(ps) as tctx: state = HelperAddon() tctx.master.addons.add(state) async with tcp_server(server_handler) as addr: tctx.configure(ps, listen_host="127.0.0.1", listen_port=0) assert not ps.server ps.running() await tctx.master.await_log("Proxy server listening", level="info") assert ps.server proxy_addr = ps.server.sockets[0].getsockname()[:2] reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://{addr[0]}:{addr[1]}/hello HTTP/1.1\r\n\r\n" writer.write(req.encode()) assert await reader.readuntil( b"\r\n\r\n") == b"HTTP/1.1 204 No Content\r\n\r\n" tctx.configure(ps, server=False) await tctx.master.await_log("Stopping server", level="info") assert not ps.server assert state.flows assert state.flows[0].request.path == "/hello" assert state.flows[0].response.status_code == 204
async def test_asgi_full(): ps = Proxyserver() addons = [ asgiapp.WSGIApp(tapp, "testapp", 80), asgiapp.ASGIApp(errapp, "errapp", 80), asgiapp.ASGIApp(noresponseapp, "noresponseapp", 80), ] with taddons.context(ps, *addons) as tctx: tctx.master.addons.add(next_layer.NextLayer()) tctx.configure(ps, listen_host="127.0.0.1", listen_port=0) ps.running() await tctx.master.await_log("Proxy server listening", level="info") proxy_addr = ps.server.sockets[0].getsockname()[:2] reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://testapp:80/ HTTP/1.1\r\n\r\n" writer.write(req.encode()) header = await reader.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 200 OK") body = await reader.readuntil(b"testapp") assert body == b"testapp" reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://testapp:80/parameters?param1=1¶m2=2 HTTP/1.1\r\n\r\n" writer.write(req.encode()) header = await reader.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 200 OK") body = await reader.readuntil(b"}") assert body == b'{"param1": "1", "param2": "2"}' reader, writer = await asyncio.open_connection(*proxy_addr) req = f"POST http://testapp:80/requestbody HTTP/1.1\r\nContent-Length: 6\r\n\r\nHello!" writer.write(req.encode()) header = await reader.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 200 OK") body = await reader.readuntil(b"}") assert body == b'{"body": "Hello!"}' reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://errapp:80/?foo=bar HTTP/1.1\r\n\r\n" writer.write(req.encode()) header = await reader.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 500") body = await reader.readuntil(b"ASGI Error") assert body == b"ASGI Error" reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://noresponseapp:80/ HTTP/1.1\r\n\r\n" writer.write(req.encode()) header = await reader.readuntil(b"\r\n\r\n") assert header.startswith(b"HTTP/1.1 500") body = await reader.readuntil(b"ASGI Error") assert body == b"ASGI Error"
async def test_warn_no_nextlayer(): """ Test that we log an error if the proxy server is started without NextLayer addon. That is a mean trap to fall into when writing end-to-end tests. """ ps = Proxyserver() with taddons.context(ps) as tctx: tctx.configure(ps, listen_host="127.0.0.1", listen_port=0) ps.running() assert await tctx.master.await_log("Proxy server listening at", level="info") assert tctx.master.has_log("Warning: Running proxyserver without nextlayer addon!", level="warn") await ps.shutdown_server()
async def test_start_stop(): async def server_handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): assert await reader.readuntil(b"\r\n\r\n" ) == b"GET /hello HTTP/1.1\r\n\r\n" writer.write(b"HTTP/1.1 204 No Content\r\n\r\n") await writer.drain() writer.close() ps = Proxyserver() with taddons.context(ps) as tctx: state = HelperAddon() tctx.master.addons.add(state) async with tcp_server(server_handler) as addr: tctx.configure(ps, listen_host="127.0.0.1", listen_port=0) assert not ps.server ps.running() await tctx.master.await_log("Proxy server listening", level="info") assert ps.server proxy_addr = ps.server.sockets[0].getsockname()[:2] reader, writer = await asyncio.open_connection(*proxy_addr) req = f"GET http://{addr[0]}:{addr[1]}/hello HTTP/1.1\r\n\r\n" writer.write(req.encode()) assert await reader.readuntil( b"\r\n\r\n") == b"HTTP/1.1 204 No Content\r\n\r\n" assert repr(ps) == "ProxyServer(running, 1 active conns)" tctx.configure(ps, server=False) await tctx.master.await_log("Stopping server", level="info") assert not ps.server assert state.flows assert state.flows[0].request.path == "/hello" assert state.flows[0].response.status_code == 204 # Waiting here until everything is really torn down... takes some effort. conn_handler = list(ps._connections.values())[0] client_handler = conn_handler.transports[ conn_handler.client].handler writer.close() await writer.wait_closed() try: await client_handler except asyncio.CancelledError: pass for _ in range(5): # Get all other scheduled coroutines to run. await asyncio.sleep(0) assert repr(ps) == "ProxyServer(stopped, 0 active conns)"
@pytest.mark.asyncio async def test_inject(): async def server_handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): while s := await reader.read(1): writer.write(s.upper()) ps = Proxyserver() with taddons.context(ps) as tctx: state = HelperAddon() tctx.master.addons.add(state) async with tcp_server(server_handler) as addr: tctx.configure(ps, listen_host="127.0.0.1", listen_port=0) ps.running() await tctx.master.await_log("Proxy server listening", level="info") proxy_addr = ps.server.sockets[0].getsockname()[:2] reader, writer = await asyncio.open_connection(*proxy_addr) req = f"CONNECT {addr[0]}:{addr[1]} HTTP/1.1\r\n\r\n" writer.write(req.encode()) assert await reader.readuntil( b"\r\n\r\n") == b"HTTP/1.1 200 Connection established\r\n\r\n" writer.write(b"a") assert await reader.read(1) == b"A" ps.inject_tcp(state.flows[0], False, "b") assert await reader.read(1) == b"B" ps.inject_tcp(state.flows[0], True, "c") assert await reader.read(1) == b"c"