import json as stdjson from collections import namedtuple from pathlib import Path import pytest from sanic_testing.reusable import ReusableClient from sanic import json, text from sanic.app import Sanic from tests.client import RawClient parent_dir = Path(__file__).parent localhost_dir = parent_dir / "certs/localhost" PORT = 1234 @pytest.fixture def test_app(app: Sanic): app.config.KEEP_ALIVE_TIMEOUT = 1 @app.get("/") async def base_handler(request): return text("111122223333444455556666777788889999") @app.post("/upload", stream=True) async def upload_handler(request): data = [part.decode("utf-8") async for part in request.stream] return json(data) return app @pytest.fixture def runner(test_app): client = ReusableClient(test_app, port=PORT) client.run() yield client client.stop() @pytest.fixture def client(runner): client = namedtuple("Client", ("raw", "send", "recv")) raw = RawClient(runner.host, runner.port) runner._run(raw.connect()) def send(msg): nonlocal runner nonlocal raw runner._run(raw.send(msg)) def recv(**kwargs): nonlocal runner nonlocal raw method = raw.recv_until if "until" in kwargs else raw.recv return runner._run(method(**kwargs)) yield client(raw, send, recv) runner._run(raw.close()) def test_full_message(client): client.send( """ GET / HTTP/1.1 host: localhost:7777 """ ) response = client.recv() assert len(response) == 151 assert b"200 OK" in response def test_transfer_chunked(client): client.send( """ POST /upload HTTP/1.1 transfer-encoding: chunked """ ) client.send(b"3\r\nfoo\r\n") client.send(b"3\r\nbar\r\n") client.send(b"0\r\n\r\n") response = client.recv() _, body = response.rsplit(b"\r\n\r\n", 1) data = stdjson.loads(body) assert data == ["foo", "bar"]