From 6799a0d1e696f7dfaf3f0e5fb2970282ba05e256 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 22 Nov 2023 20:14:34 +0100 Subject: [PATCH] Fix ClientResponse.close releasing the connection instead of closing (#7869) --- CHANGES/7869.bugfix | 1 + aiohttp/client_reqrep.py | 4 +- tests/test_client_functional.py | 497 +++++++++++++++++--------------- 3 files changed, 264 insertions(+), 238 deletions(-) create mode 100644 CHANGES/7869.bugfix diff --git a/CHANGES/7869.bugfix b/CHANGES/7869.bugfix new file mode 100644 index 00000000000..23282fc3bb4 --- /dev/null +++ b/CHANGES/7869.bugfix @@ -0,0 +1 @@ +Fix ClientResponse.close releasing the connection instead of closing diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 4cea7466d8d..0ab84743658 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -1033,7 +1033,9 @@ def close(self) -> None: return self._cleanup_writer() - self._release_connection() + if self._connection is not None: + self._connection.close() + self._connection = None def release(self) -> Any: if not self._released: diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index c5379e74a4b..4f0d594cb1f 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -1,3 +1,4 @@ +# type: ignore # HTTP client functional tests against aiohttp.web server import asyncio @@ -19,6 +20,7 @@ from aiohttp import Fingerprint, ServerFingerprintMismatch, hdrs, web from aiohttp.abc import AbstractResolver from aiohttp.client_exceptions import TooManyRedirects +from aiohttp.pytest_plugin import AiohttpClient, TestClient from aiohttp.test_utils import unused_port @@ -28,11 +30,11 @@ def here(): @pytest.fixture -def fname(here): +def fname(here: Any): return here / "conftest.py" -async def test_keepalive_two_requests_success(aiohttp_client) -> None: +async def test_keepalive_two_requests_success(aiohttp_client: Any) -> None: async def handler(request): body = await request.read() assert b"" == body @@ -52,7 +54,7 @@ async def handler(request): assert 1 == len(client._session.connector._conns) -async def test_keepalive_after_head_requests_success(aiohttp_client) -> None: +async def test_keepalive_after_head_requests_success(aiohttp_client: Any) -> None: async def handler(request): body = await request.read() assert b"" == body @@ -172,7 +174,7 @@ async def handler(request): assert 1 == len(client._session.connector._conns) -async def test_keepalive_server_force_close_connection(aiohttp_client) -> None: +async def test_keepalive_server_force_close_connection(aiohttp_client: Any) -> None: async def handler(request): body = await request.read() assert b"" == body @@ -194,7 +196,7 @@ async def handler(request): assert 0 == len(client._session.connector._conns) -async def test_release_early(aiohttp_client) -> None: +async def test_release_early(aiohttp_client: Any) -> None: async def handler(request): await request.read() return web.Response(body=b"OK") @@ -209,7 +211,7 @@ async def handler(request): assert 1 == len(client._session.connector._conns) -async def test_HTTP_304(aiohttp_client) -> None: +async def test_HTTP_304(aiohttp_client: Any) -> None: async def handler(request): body = await request.read() assert b"" == body @@ -279,7 +281,7 @@ async def data_gen(): assert len(conns) == 2 -async def test_HTTP_304_WITH_BODY(aiohttp_client) -> None: +async def test_HTTP_304_WITH_BODY(aiohttp_client: Any) -> None: async def handler(request): body = await request.read() assert b"" == body @@ -295,7 +297,7 @@ async def handler(request): assert content == b"" -async def test_auto_header_user_agent(aiohttp_client) -> None: +async def test_auto_header_user_agent(aiohttp_client: Any) -> None: async def handler(request): assert "aiohttp" in request.headers["user-agent"] return web.Response() @@ -308,7 +310,7 @@ async def handler(request): assert 200 == resp.status -async def test_skip_auto_headers_user_agent(aiohttp_client) -> None: +async def test_skip_auto_headers_user_agent(aiohttp_client: Any) -> None: async def handler(request): assert hdrs.USER_AGENT not in request.headers return web.Response() @@ -321,7 +323,7 @@ async def handler(request): assert 200 == resp.status -async def test_skip_default_auto_headers_user_agent(aiohttp_client) -> None: +async def test_skip_default_auto_headers_user_agent(aiohttp_client: Any) -> None: async def handler(request): assert hdrs.USER_AGENT not in request.headers return web.Response() @@ -334,7 +336,7 @@ async def handler(request): assert 200 == resp.status -async def test_skip_auto_headers_content_type(aiohttp_client) -> None: +async def test_skip_auto_headers_content_type(aiohttp_client: Any) -> None: async def handler(request): assert hdrs.CONTENT_TYPE not in request.headers return web.Response() @@ -347,7 +349,7 @@ async def handler(request): assert 200 == resp.status -async def test_post_data_bytesio(aiohttp_client) -> None: +async def test_post_data_bytesio(aiohttp_client: Any) -> None: data = b"some buffer" async def handler(request): @@ -365,14 +367,13 @@ async def handler(request): assert 200 == resp.status -async def test_post_data_with_bytesio_file(aiohttp_client) -> None: +async def test_post_data_with_bytesio_file(aiohttp_client: Any) -> None: data = b"some buffer" async def handler(request): post_data = await request.post() assert ["file"] == list(post_data.keys()) assert data == post_data["file"].file.read() - post_data["file"].file.close() # aiohttp < 4 doesn't autoclose files return web.Response() app = web.Application() @@ -384,7 +385,7 @@ async def handler(request): assert 200 == resp.status -async def test_post_data_stringio(aiohttp_client) -> None: +async def test_post_data_stringio(aiohttp_client: Any) -> None: data = "some buffer" async def handler(request): @@ -402,7 +403,7 @@ async def handler(request): assert 200 == resp.status -async def test_post_data_textio_encoding(aiohttp_client) -> None: +async def test_post_data_textio_encoding(aiohttp_client: Any) -> None: data = "текст" async def handler(request): @@ -421,10 +422,7 @@ async def handler(request): async def test_ssl_client( - aiohttp_server, - ssl_ctx, - aiohttp_client, - client_ssl_ctx, + aiohttp_server: Any, ssl_ctx: Any, aiohttp_client: Any, client_ssl_ctx: Any ) -> None: connector = aiohttp.TCPConnector(ssl=client_ssl_ctx) @@ -443,10 +441,10 @@ async def handler(request): async def test_tcp_connector_fingerprint_ok( - aiohttp_server, - aiohttp_client, - ssl_ctx, - tls_certificate_fingerprint_sha256, + aiohttp_server: Any, + aiohttp_client: Any, + ssl_ctx: Any, + tls_certificate_fingerprint_sha256: Any, ): tls_fingerprint = Fingerprint(tls_certificate_fingerprint_sha256) @@ -464,10 +462,10 @@ async def handler(request): async def test_tcp_connector_fingerprint_fail( - aiohttp_server, - aiohttp_client, - ssl_ctx, - tls_certificate_fingerprint_sha256, + aiohttp_server: Any, + aiohttp_client: Any, + ssl_ctx: Any, + tls_certificate_fingerprint_sha256: Any, ): async def handler(request): return web.Response(text="Test message") @@ -488,9 +486,7 @@ async def handler(request): assert exc.got == tls_certificate_fingerprint_sha256 -async def test_format_task_get(aiohttp_server) -> None: - loop = asyncio.get_event_loop() - +async def test_format_task_get(aiohttp_server: Any) -> None: async def handler(request): return web.Response(body=b"OK") @@ -498,14 +494,14 @@ async def handler(request): app.router.add_route("GET", "/", handler) server = await aiohttp_server(app) client = aiohttp.ClientSession() - task = loop.create_task(client.get(server.make_url("/"))) + task = asyncio.create_task(client.get(server.make_url("/"))) assert f"{task}".startswith(" None: +async def test_str_params(aiohttp_client: Any) -> None: async def handler(request): assert "q=t est" in request.rel_url.query_string return web.Response() @@ -518,7 +514,7 @@ async def handler(request): assert 200 == resp.status -async def test_drop_params_on_redirect(aiohttp_client) -> None: +async def test_drop_params_on_redirect(aiohttp_client: Any) -> None: async def handler_redirect(request): return web.Response(status=301, headers={"Location": "/ok?a=redirect"}) @@ -535,7 +531,7 @@ async def handler_ok(request): assert resp.status == 200 -async def test_drop_fragment_on_redirect(aiohttp_client) -> None: +async def test_drop_fragment_on_redirect(aiohttp_client: Any) -> None: async def handler_redirect(request): return web.Response(status=301, headers={"Location": "/ok#fragment"}) @@ -552,7 +548,7 @@ async def handler_ok(request): assert resp.url.path == "/ok" -async def test_drop_fragment(aiohttp_client) -> None: +async def test_drop_fragment(aiohttp_client: Any) -> None: async def handler_ok(request): return web.Response(status=200) @@ -565,7 +561,7 @@ async def handler_ok(request): assert resp.url.path == "/ok" -async def test_history(aiohttp_client) -> None: +async def test_history(aiohttp_client: Any) -> None: async def handler_redirect(request): return web.Response(status=301, headers={"Location": "/ok"}) @@ -587,7 +583,7 @@ async def handler_ok(request): assert resp_redirect.status == 200 -async def test_keepalive_closed_by_server(aiohttp_client) -> None: +async def test_keepalive_closed_by_server(aiohttp_client: Any) -> None: async def handler(request): body = await request.read() assert b"" == body @@ -611,7 +607,7 @@ async def handler(request): assert 0 == len(client._session.connector._conns) -async def test_wait_for(aiohttp_client) -> None: +async def test_wait_for(aiohttp_client: Any) -> None: async def handler(request): return web.Response(body=b"OK") @@ -625,7 +621,7 @@ async def handler(request): assert txt == "OK" -async def test_raw_headers(aiohttp_client) -> None: +async def test_raw_headers(aiohttp_client: Any) -> None: async def handler(request): return web.Response() @@ -644,7 +640,7 @@ async def handler(request): ) -async def test_host_header_first(aiohttp_client) -> None: +async def test_host_header_first(aiohttp_client: Any) -> None: async def handler(request): assert list(request.headers)[0] == hdrs.HOST return web.Response() @@ -656,7 +652,7 @@ async def handler(request): assert resp.status == 200 -async def test_empty_header_values(aiohttp_client) -> None: +async def test_empty_header_values(aiohttp_client: Any) -> None: async def handler(request): resp = web.Response() resp.headers["X-Empty"] = "" @@ -677,7 +673,7 @@ async def handler(request): ) -async def test_204_with_gzipped_content_encoding(aiohttp_client) -> None: +async def test_204_with_gzipped_content_encoding(aiohttp_client: Any) -> None: async def handler(request): resp = web.StreamResponse(status=204) resp.content_length = 0 @@ -696,7 +692,7 @@ async def handler(request): assert resp.closed -async def test_timeout_on_reading_headers(aiohttp_client, mocker) -> None: +async def test_timeout_on_reading_headers(aiohttp_client: Any, mocker: Any) -> None: async def handler(request): resp = web.StreamResponse() await asyncio.sleep(0.1) @@ -708,10 +704,12 @@ async def handler(request): client = await aiohttp_client(app) with pytest.raises(asyncio.TimeoutError): - await client.get("/", timeout=0.01) + await client.get("/", timeout=aiohttp.ClientTimeout(total=0.01)) -async def test_timeout_on_conn_reading_headers(aiohttp_client, mocker) -> None: +async def test_timeout_on_conn_reading_headers( + aiohttp_client: Any, mocker: Any +) -> None: # tests case where user did not set a connection timeout async def handler(request): @@ -727,10 +725,12 @@ async def handler(request): client = await aiohttp_client(app, connector=conn) with pytest.raises(asyncio.TimeoutError): - await client.get("/", timeout=0.01) + await client.get("/", timeout=aiohttp.ClientTimeout(total=0.01)) -async def test_timeout_on_session_read_timeout(aiohttp_client, mocker) -> None: +async def test_timeout_on_session_read_timeout( + aiohttp_client: Any, mocker: Any +) -> None: async def handler(request): resp = web.StreamResponse() await asyncio.sleep(0.1) @@ -749,7 +749,7 @@ async def handler(request): await client.get("/") -async def test_read_timeout_between_chunks(aiohttp_client, mocker) -> None: +async def test_read_timeout_between_chunks(aiohttp_client: Any, mocker: Any) -> None: async def handler(request): resp = aiohttp.web.StreamResponse() await resp.prepare(request) @@ -773,7 +773,7 @@ async def handler(request): assert res == b"data\n" * 4 -async def test_read_timeout_on_reading_chunks(aiohttp_client, mocker) -> None: +async def test_read_timeout_on_reading_chunks(aiohttp_client: Any, mocker: Any) -> None: async def handler(request): resp = aiohttp.web.StreamResponse() await resp.prepare(request) @@ -795,7 +795,7 @@ async def handler(request): await resp.content.read() -async def test_read_timeout_on_write(aiohttp_client) -> None: +async def test_read_timeout_on_write(aiohttp_client: Any) -> None: async def gen_payload() -> AsyncIterator[str]: # Delay writing to ensure read timeout isn't triggered before writing completes. await asyncio.sleep(0.5) @@ -814,7 +814,7 @@ async def handler(request: web.Request) -> web.Response: assert result == b"foo" -async def test_timeout_on_reading_data(aiohttp_client, mocker) -> None: +async def test_timeout_on_reading_data(aiohttp_client: Any, mocker: Any) -> None: loop = asyncio.get_event_loop() fut = loop.create_future() @@ -830,14 +830,14 @@ async def handler(request): app.router.add_route("GET", "/", handler) client = await aiohttp_client(app) - resp = await client.get("/", timeout=1) + resp = await client.get("/", timeout=aiohttp.ClientTimeout(1)) await fut with pytest.raises(asyncio.TimeoutError): await resp.read() -async def test_timeout_none(aiohttp_client, mocker) -> None: +async def test_timeout_none(aiohttp_client: Any, mocker: Any) -> None: async def handler(request): resp = web.StreamResponse() await resp.prepare(request) @@ -851,7 +851,7 @@ async def handler(request): assert resp.status == 200 -async def test_readline_error_on_conn_close(aiohttp_client) -> None: +async def test_readline_error_on_conn_close(aiohttp_client: Any) -> None: loop = asyncio.get_event_loop() async def handler(request): @@ -892,7 +892,7 @@ def do_release(): await session.close() -async def test_no_error_on_conn_close_if_eof(aiohttp_client) -> None: +async def test_no_error_on_conn_close_if_eof(aiohttp_client: Any) -> None: async def handler(request): resp_ = web.StreamResponse() await resp_.prepare(request) @@ -920,7 +920,7 @@ async def handler(request): await session.close() -async def test_error_not_overwrote_on_conn_close(aiohttp_client) -> None: +async def test_error_not_overwrote_on_conn_close(aiohttp_client: Any) -> None: async def handler(request): resp_ = web.StreamResponse() await resp_.prepare(request) @@ -941,7 +941,7 @@ async def handler(request): assert isinstance(resp.content.exception(), ValueError) -async def test_HTTP_200_OK_METHOD(aiohttp_client) -> None: +async def test_HTTP_200_OK_METHOD(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -966,7 +966,7 @@ async def handler(request): assert meth.upper() == content -async def test_HTTP_200_OK_METHOD_connector(aiohttp_client) -> None: +async def test_HTTP_200_OK_METHOD_connector(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -993,7 +993,7 @@ async def handler(request): assert meth.upper() == content -async def test_HTTP_302_REDIRECT_GET(aiohttp_client) -> None: +async def test_HTTP_302_REDIRECT_GET(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -1010,7 +1010,7 @@ async def redirect(request): assert 1 == len(resp.history) -async def test_HTTP_302_REDIRECT_HEAD(aiohttp_client) -> None: +async def test_HTTP_302_REDIRECT_HEAD(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -1030,7 +1030,7 @@ async def redirect(request): assert resp.method == "HEAD" -async def test_HTTP_302_REDIRECT_NON_HTTP(aiohttp_client) -> None: +async def test_HTTP_302_REDIRECT_NON_HTTP(aiohttp_client: Any) -> None: async def redirect(request): raise web.HTTPFound(location="ftp://127.0.0.1/test/") @@ -1042,7 +1042,7 @@ async def redirect(request): await client.get("/redirect") -async def test_HTTP_302_REDIRECT_POST(aiohttp_client) -> None: +async def test_HTTP_302_REDIRECT_POST(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -1062,7 +1062,9 @@ async def redirect(request): resp.close() -async def test_HTTP_302_REDIRECT_POST_with_content_length_hdr(aiohttp_client) -> None: +async def test_HTTP_302_REDIRECT_POST_with_content_length_hdr( + aiohttp_client: Any, +) -> None: async def handler(request): return web.Response(text=request.method) @@ -1086,7 +1088,7 @@ async def redirect(request): resp.close() -async def test_HTTP_307_REDIRECT_POST(aiohttp_client) -> None: +async def test_HTTP_307_REDIRECT_POST(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -1107,7 +1109,7 @@ async def redirect(request): resp.close() -async def test_HTTP_308_PERMANENT_REDIRECT_POST(aiohttp_client) -> None: +async def test_HTTP_308_PERMANENT_REDIRECT_POST(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -1128,7 +1130,7 @@ async def redirect(request): resp.close() -async def test_HTTP_302_max_redirects(aiohttp_client) -> None: +async def test_HTTP_302_max_redirects(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -1151,7 +1153,7 @@ async def redirect(request): assert ctx.value.request_info.method == "GET" -async def test_HTTP_200_GET_WITH_PARAMS(aiohttp_client) -> None: +async def test_HTTP_200_GET_WITH_PARAMS(aiohttp_client: Any) -> None: async def handler(request): return web.Response( text="&".join(k + "=" + v for k, v in request.query.items()) @@ -1168,7 +1170,7 @@ async def handler(request): resp.close() -async def test_HTTP_200_GET_WITH_MultiDict_PARAMS(aiohttp_client) -> None: +async def test_HTTP_200_GET_WITH_MultiDict_PARAMS(aiohttp_client: Any) -> None: async def handler(request): return web.Response( text="&".join(k + "=" + v for k, v in request.query.items()) @@ -1185,7 +1187,7 @@ async def handler(request): resp.close() -async def test_HTTP_200_GET_WITH_MIXED_PARAMS(aiohttp_client) -> None: +async def test_HTTP_200_GET_WITH_MIXED_PARAMS(aiohttp_client: Any) -> None: async def handler(request): return web.Response( text="&".join(k + "=" + v for k, v in request.query.items()) @@ -1202,7 +1204,7 @@ async def handler(request): resp.close() -async def test_POST_DATA(aiohttp_client) -> None: +async def test_POST_DATA(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() return web.json_response(dict(data)) @@ -1218,7 +1220,7 @@ async def handler(request): resp.close() -async def test_POST_DATA_with_explicit_formdata(aiohttp_client) -> None: +async def test_POST_DATA_with_explicit_formdata(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() return web.json_response(dict(data)) @@ -1237,7 +1239,7 @@ async def handler(request): resp.close() -async def test_POST_DATA_with_charset(aiohttp_client) -> None: +async def test_POST_DATA_with_charset(aiohttp_client: Any) -> None: async def handler(request): mp = await request.multipart() part = await mp.next() @@ -1258,7 +1260,7 @@ async def handler(request): resp.close() -async def test_POST_DATA_formdats_with_charset(aiohttp_client) -> None: +async def test_POST_DATA_formdats_with_charset(aiohttp_client: Any) -> None: async def handler(request): mp = await request.post() assert "name" in mp @@ -1278,7 +1280,7 @@ async def handler(request): resp.close() -async def test_POST_DATA_with_charset_post(aiohttp_client) -> None: +async def test_POST_DATA_with_charset_post(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() return web.Response(text=data["name"]) @@ -1297,7 +1299,7 @@ async def handler(request): resp.close() -async def test_POST_DATA_with_context_transfer_encoding(aiohttp_client) -> None: +async def test_POST_DATA_with_context_transfer_encoding(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() assert data["name"] == "text" @@ -1317,7 +1319,9 @@ async def handler(request): resp.close() -async def test_POST_DATA_with_content_type_context_transfer_encoding(aiohttp_client): +async def test_POST_DATA_with_content_type_context_transfer_encoding( + aiohttp_client: Any, +): async def handler(request): data = await request.post() assert data["name"] == "text" @@ -1339,7 +1343,7 @@ async def handler(request): resp.close() -async def test_POST_MultiDict(aiohttp_client) -> None: +async def test_POST_MultiDict(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() assert data == MultiDict([("q", "test1"), ("q", "test2")]) @@ -1355,7 +1359,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_DATA_DEFLATE(aiohttp_client) -> None: +async def test_POST_DATA_DEFLATE(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() return web.json_response(dict(data)) @@ -1371,7 +1375,7 @@ async def handler(request): resp.close() -async def test_POST_FILES(aiohttp_client, fname) -> None: +async def test_POST_FILES(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.post() assert data["some"].filename == fname.name @@ -1395,7 +1399,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_DEFLATE(aiohttp_client, fname) -> None: +async def test_POST_FILES_DEFLATE(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.post() assert data["some"].filename == fname.name @@ -1417,7 +1421,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_bytes(aiohttp_client) -> None: +async def test_POST_bytes(aiohttp_client: Any) -> None: body = b"0" * 12345 async def handler(request): @@ -1433,7 +1437,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_bytes_too_large(aiohttp_client) -> None: +async def test_POST_bytes_too_large(aiohttp_client: Any) -> None: body = b"0" * (2**20 + 1) async def handler(request): @@ -1452,7 +1456,7 @@ async def handler(request): resp.close() -async def test_POST_FILES_STR(aiohttp_client, fname) -> None: +async def test_POST_FILES_STR(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.post() with fname.open("rb") as f: @@ -1470,7 +1474,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_STR_SIMPLE(aiohttp_client, fname) -> None: +async def test_POST_FILES_STR_SIMPLE(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.read() with fname.open("rb") as f: @@ -1487,7 +1491,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_LIST(aiohttp_client, fname) -> None: +async def test_POST_FILES_LIST(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.post() assert fname.name == data["some"].filename @@ -1506,7 +1510,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_CT(aiohttp_client, fname) -> None: +async def test_POST_FILES_CT(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.post() assert fname.name == data["some"].filename @@ -1528,7 +1532,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_SINGLE(aiohttp_client, fname) -> None: +async def test_POST_FILES_SINGLE(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.text() with fname.open("rb") as f: @@ -1554,7 +1558,9 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_SINGLE_content_disposition(aiohttp_client, fname) -> None: +async def test_POST_FILES_SINGLE_content_disposition( + aiohttp_client: Any, fname: Any +) -> None: async def handler(request): data = await request.text() with fname.open("rb") as f: @@ -1584,7 +1590,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_SINGLE_BINARY(aiohttp_client, fname) -> None: +async def test_POST_FILES_SINGLE_BINARY(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.read() with fname.open("rb") as f: @@ -1609,7 +1615,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_IO(aiohttp_client) -> None: +async def test_POST_FILES_IO(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() assert b"data" == data["unknown"].file.read() @@ -1627,7 +1633,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_IO_WITH_PARAMS(aiohttp_client) -> None: +async def test_POST_FILES_IO_WITH_PARAMS(aiohttp_client: Any) -> None: async def handler(request): data = await request.post() assert data["test"] == "true" @@ -1651,7 +1657,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_FILES_WITH_DATA(aiohttp_client, fname) -> None: +async def test_POST_FILES_WITH_DATA(aiohttp_client: Any, fname: Any) -> None: async def handler(request): data = await request.post() assert data["test"] == "true" @@ -1676,7 +1682,7 @@ async def handler(request): assert 200 == resp.status -async def test_POST_STREAM_DATA(aiohttp_client, fname) -> None: +async def test_POST_STREAM_DATA(aiohttp_client: Any, fname: Any) -> None: async def handler(request): assert request.content_type == "application/octet-stream" content = await request.read() @@ -1694,57 +1700,20 @@ async def handler(request): with fname.open("rb") as f: data_size = len(f.read()) - with pytest.warns(DeprecationWarning): - - @aiohttp.streamer - async def stream(writer, fname): - with fname.open("rb") as f: - data = f.read(100) - while data: - await writer.write(data) - data = f.read(100) - - async with client.post( - "/", data=stream(fname), headers={"Content-Length": str(data_size)} - ) as resp: - assert 200 == resp.status - - -async def test_POST_STREAM_DATA_no_params(aiohttp_client, fname) -> None: - async def handler(request): - assert request.content_type == "application/octet-stream" - content = await request.read() + async def gen(fname): with fname.open("rb") as f: - expected = f.read() - assert request.content_length == len(expected) - assert content == expected - - return web.Response() - - app = web.Application() - app.router.add_post("/", handler) - client = await aiohttp_client(app) - - with fname.open("rb") as f: - data_size = len(f.read()) - - with pytest.warns(DeprecationWarning): - - @aiohttp.streamer - async def stream(writer): - with fname.open("rb") as f: + data = f.read(100) + while data: + yield data data = f.read(100) - while data: - await writer.write(data) - data = f.read(100) async with client.post( - "/", data=stream, headers={"Content-Length": str(data_size)} + "/", data=gen(fname), headers={"Content-Length": str(data_size)} ) as resp: assert 200 == resp.status -async def test_json(aiohttp_client) -> None: +async def test_json(aiohttp_client: Any) -> None: async def handler(request): assert request.content_type == "application/json" data = await request.json() @@ -1764,7 +1733,7 @@ async def handler(request): await client.post("/", data="some data", json={"some": "data"}) -async def test_json_custom(aiohttp_client) -> None: +async def test_json_custom(aiohttp_client: Any) -> None: async def handler(request): assert request.content_type == "application/json" data = await request.json() @@ -1792,7 +1761,7 @@ def dumps(obj): await client.post("/", data="some data", json={"some": "data"}) -async def test_expect_continue(aiohttp_client) -> None: +async def test_expect_continue(aiohttp_client: Any) -> None: expect_called = False async def handler(request): @@ -1816,7 +1785,7 @@ async def expect_handler(request): assert expect_called -async def test_encoding_deflate(aiohttp_client) -> None: +async def test_encoding_deflate(aiohttp_client: Any) -> None: async def handler(request): resp = web.Response(text="text") resp.enable_chunked_encoding() @@ -1834,7 +1803,7 @@ async def handler(request): resp.close() -async def test_encoding_deflate_nochunk(aiohttp_client) -> None: +async def test_encoding_deflate_nochunk(aiohttp_client: Any) -> None: async def handler(request): resp = web.Response(text="text") resp.enable_compression(web.ContentCoding.deflate) @@ -1851,7 +1820,7 @@ async def handler(request): resp.close() -async def test_encoding_gzip(aiohttp_client) -> None: +async def test_encoding_gzip(aiohttp_client: Any) -> None: async def handler(request): resp = web.Response(text="text") resp.enable_chunked_encoding() @@ -1869,7 +1838,7 @@ async def handler(request): resp.close() -async def test_encoding_gzip_write_by_chunks(aiohttp_client) -> None: +async def test_encoding_gzip_write_by_chunks(aiohttp_client: Any) -> None: async def handler(request): resp = web.StreamResponse() resp.enable_compression(web.ContentCoding.gzip) @@ -1889,7 +1858,7 @@ async def handler(request): resp.close() -async def test_encoding_gzip_nochunk(aiohttp_client) -> None: +async def test_encoding_gzip_nochunk(aiohttp_client: Any) -> None: async def handler(request): resp = web.Response(text="text") resp.enable_compression(web.ContentCoding.gzip) @@ -1906,7 +1875,7 @@ async def handler(request): resp.close() -async def test_bad_payload_compression(aiohttp_client) -> None: +async def test_bad_payload_compression(aiohttp_client: Any) -> None: async def handler(request): resp = web.Response(text="text") resp.headers["Content-Encoding"] = "gzip" @@ -1925,7 +1894,7 @@ async def handler(request): resp.close() -async def test_bad_payload_chunked_encoding(aiohttp_client) -> None: +async def test_bad_payload_chunked_encoding(aiohttp_client: Any) -> None: async def handler(request): resp = web.StreamResponse() resp.force_close() @@ -2044,7 +2013,7 @@ async def handler(request): resp.close() -async def test_payload_content_length_by_chunks(aiohttp_client) -> None: +async def test_payload_content_length_by_chunks(aiohttp_client: Any) -> None: async def handler(request): resp = web.StreamResponse(headers={"content-length": "2"}) await resp.prepare(request) @@ -2063,7 +2032,7 @@ async def handler(request): resp.close() -async def test_chunked(aiohttp_client) -> None: +async def test_chunked(aiohttp_client: Any) -> None: async def handler(request): resp = web.Response(text="text") resp.enable_chunked_encoding() @@ -2081,7 +2050,7 @@ async def handler(request): resp.close() -async def test_shortcuts(aiohttp_client) -> None: +async def test_shortcuts(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -2108,7 +2077,7 @@ async def handler(request): assert meth.upper() == content -async def test_cookies(aiohttp_client) -> None: +async def test_cookies(aiohttp_client: Any) -> None: async def handler(request): assert request.cookies.keys() == {"test1", "test3"} assert request.cookies["test1"] == "123" @@ -2126,7 +2095,7 @@ async def handler(request): assert 200 == resp.status -async def test_cookies_per_request(aiohttp_client) -> None: +async def test_cookies_per_request(aiohttp_client: Any) -> None: async def handler(request): assert request.cookies.keys() == {"test1", "test3", "test4", "test6"} assert request.cookies["test1"] == "123" @@ -2149,7 +2118,7 @@ async def handler(request): assert 200 == resp.status -async def test_cookies_redirect(aiohttp_client) -> None: +async def test_cookies_redirect(aiohttp_client: Any) -> None: async def redirect1(request): ret = web.Response(status=301, headers={"Location": "/redirect2"}) ret.set_cookie("c", "1") @@ -2175,7 +2144,7 @@ async def handler(request): assert 200 == resp.status -async def test_cookies_on_empty_session_jar(aiohttp_client) -> None: +async def test_cookies_on_empty_session_jar(aiohttp_client: Any) -> None: async def handler(request): assert "custom-cookie" in request.cookies assert request.cookies["custom-cookie"] == "abc" @@ -2189,7 +2158,7 @@ async def handler(request): assert 200 == resp.status -async def test_morsel_with_attributes(aiohttp_client) -> None: +async def test_morsel_with_attributes(aiohttp_client: Any) -> None: # A comment from original test: # # No cookie attribute should pass here @@ -2218,7 +2187,7 @@ async def handler(request): assert 200 == resp.status -async def test_set_cookies(aiohttp_client) -> None: +async def test_set_cookies(aiohttp_client: Any) -> None: async def handler(request): ret = web.Response() ret.set_cookie("c1", "cookie1") @@ -2244,7 +2213,7 @@ async def handler(request): m_log.warning.assert_called_with("Can not load response cookies: %s", mock.ANY) -async def test_set_cookies_expired(aiohttp_client) -> None: +async def test_set_cookies_expired(aiohttp_client: Any) -> None: async def handler(request): ret = web.Response() ret.set_cookie("c1", "cookie1") @@ -2265,7 +2234,7 @@ async def handler(request): assert cookie_names == {"c1", "c2"} -async def test_set_cookies_max_age(aiohttp_client) -> None: +async def test_set_cookies_max_age(aiohttp_client: Any) -> None: async def handler(request): ret = web.Response() ret.set_cookie("c1", "cookie1") @@ -2286,7 +2255,7 @@ async def handler(request): assert cookie_names == {"c1", "c2"} -async def test_set_cookies_max_age_overflow(aiohttp_client) -> None: +async def test_set_cookies_max_age_overflow(aiohttp_client: Any) -> None: async def handler(request): ret = web.Response() ret.headers.add( @@ -2325,7 +2294,7 @@ async def test_request_conn_error() -> None: @pytest.mark.xfail -async def test_broken_connection(aiohttp_client) -> None: +async def test_broken_connection(aiohttp_client: Any) -> None: async def handler(request): request.transport.close() return web.Response(text="answer" * 1000) @@ -2338,7 +2307,7 @@ async def handler(request): await client.get("/") -async def test_broken_connection_2(aiohttp_client) -> None: +async def test_broken_connection_2(aiohttp_client: Any) -> None: async def handler(request): resp = web.StreamResponse(headers={"content-length": "1000"}) await resp.prepare(request) @@ -2356,7 +2325,7 @@ async def handler(request): resp.close() -async def test_custom_headers(aiohttp_client) -> None: +async def test_custom_headers(aiohttp_client: Any) -> None: async def handler(request): assert request.headers["x-api-key"] == "foo" return web.Response() @@ -2371,7 +2340,7 @@ async def handler(request): assert resp.status == 200 -async def test_redirect_to_absolute_url(aiohttp_client) -> None: +async def test_redirect_to_absolute_url(aiohttp_client: Any) -> None: async def handler(request): return web.Response(text=request.method) @@ -2387,7 +2356,7 @@ async def redirect(request): assert 200 == resp.status -async def test_redirect_without_location_header(aiohttp_client) -> None: +async def test_redirect_without_location_header(aiohttp_client: Any) -> None: body = b"redirect" async def handler_redirect(request): @@ -2402,18 +2371,6 @@ async def handler_redirect(request): assert data == body -async def test_chunked_deprecated(aiohttp_client) -> None: - async def handler_redirect(request): - return web.Response(status=301) - - app = web.Application() - app.router.add_route("GET", "/redirect", handler_redirect) - client = await aiohttp_client(app) - - with pytest.warns(DeprecationWarning): - await client.post("/", chunked=1024) - - @pytest.mark.parametrize( ("status", "expected_ok"), ( @@ -2425,7 +2382,9 @@ async def handler_redirect(request): (500, False), ), ) -async def test_ok_from_status(aiohttp_client, status, expected_ok) -> None: +async def test_ok_from_status( + aiohttp_client: Any, status: Any, expected_ok: Any +) -> None: async def handler(request): return web.Response(status=status, body=b"") @@ -2436,43 +2395,43 @@ async def handler(request): assert resp.ok is expected_ok -async def test_raise_for_status(aiohttp_client) -> None: - async def handler_redirect(request): +async def test_raise_for_status(aiohttp_client: Any) -> None: + async def handler(request): raise web.HTTPBadRequest() app = web.Application() - app.router.add_route("GET", "/", handler_redirect) + app.router.add_route("GET", "/", handler) client = await aiohttp_client(app, raise_for_status=True) with pytest.raises(aiohttp.ClientResponseError): await client.get("/") -async def test_raise_for_status_per_request(aiohttp_client) -> None: - async def handler_redirect(request): +async def test_raise_for_status_per_request(aiohttp_client: Any) -> None: + async def handler(request): raise web.HTTPBadRequest() app = web.Application() - app.router.add_route("GET", "/", handler_redirect) + app.router.add_route("GET", "/", handler) client = await aiohttp_client(app) with pytest.raises(aiohttp.ClientResponseError): await client.get("/", raise_for_status=True) -async def test_raise_for_status_disable_per_request(aiohttp_client) -> None: - async def handler_redirect(request): +async def test_raise_for_status_disable_per_request(aiohttp_client: Any) -> None: + async def handler(request): raise web.HTTPBadRequest() app = web.Application() - app.router.add_route("GET", "/", handler_redirect) + app.router.add_route("GET", "/", handler) client = await aiohttp_client(app, raise_for_status=True) async with client.get("/", raise_for_status=False) as resp: assert 400 == resp.status -async def test_request_raise_for_status_default(aiohttp_server) -> None: +async def test_request_raise_for_status_default(aiohttp_server: Any) -> None: async def handler(request): raise web.HTTPBadRequest() @@ -2484,7 +2443,7 @@ async def handler(request): assert resp.status == 400 -async def test_request_raise_for_status_disabled(aiohttp_server) -> None: +async def test_request_raise_for_status_disabled(aiohttp_server: Any) -> None: async def handler(request): raise web.HTTPBadRequest() @@ -2497,7 +2456,7 @@ async def handler(request): assert resp.status == 400 -async def test_request_raise_for_status_enabled(aiohttp_server) -> None: +async def test_request_raise_for_status_enabled(aiohttp_server: Any) -> None: async def handler(request): raise web.HTTPBadRequest() @@ -2511,7 +2470,7 @@ async def handler(request): assert False, "never executed" # pragma: no cover -async def test_session_raise_for_status_coro(aiohttp_client) -> None: +async def test_session_raise_for_status_coro(aiohttp_client: Any) -> None: async def handle(request): return web.Response(text="ok") @@ -2535,7 +2494,7 @@ async def custom_r4s(response): assert raise_for_status_called == 1 # custom_r4s not called again -async def test_request_raise_for_status_coro(aiohttp_client) -> None: +async def test_request_raise_for_status_coro(aiohttp_client: Any) -> None: async def handle(request): return web.Response(text="ok") @@ -2580,8 +2539,10 @@ async def test_creds_in_auth_and_url() -> None: @pytest.fixture -def create_server_for_url_and_handler(aiohttp_server, tls_certificate_authority): - def create(url, srv): +def create_server_for_url_and_handler( + aiohttp_server: Any, tls_certificate_authority: Any +): + def create(url: URL, srv: Any): app = web.Application() app.router.add_route("GET", url.path, srv) @@ -2599,11 +2560,15 @@ def create(url, srv): @pytest.mark.parametrize( - ["url_from", "url_to"], + ["url_from", "url_to", "is_drop_header_expected"], [ - ["http://host1.com/path1", "http://host2.com/path2"], - ["http://host1.com/path1", "https://host1.com/path1"], - ["https://host1.com/path1", "http://host1.com/path2"], + [ + "http://host1.com/path1", + "http://host2.com/path2", + True, + ], + ["http://host1.com/path1", "https://host1.com/path1", False], + ["https://host1.com/path1", "http://host1.com/path2", True], ], ids=( "entirely different hosts", @@ -2612,9 +2577,10 @@ def create(url, srv): ), ) async def test_drop_auth_on_redirect_to_other_host( - create_server_for_url_and_handler, - url_from, - url_to, + create_server_for_url_and_handler: Any, + url_from: str, + url_to: str, + is_drop_header_expected: bool, ) -> None: url_from, url_to = URL(url_from), URL(url_to) @@ -2625,7 +2591,10 @@ async def srv_from(request): async def srv_to(request): assert request.host == url_to.host - assert "Authorization" not in request.headers, "Header wasn't dropped" + if is_drop_header_expected: + assert "Authorization" not in request.headers, "Header wasn't dropped" + else: + assert "Authorization" in request.headers, "Header was dropped" return web.Response() server_from = await create_server_for_url_and_handler(url_from, srv_from) @@ -2691,7 +2660,7 @@ async def test_session_close_awaitable() -> None: assert session.closed -async def test_close_resp_on_error_async_with_session(aiohttp_server) -> None: +async def test_close_resp_on_error_async_with_session(aiohttp_server: Any) -> None: async def handler(request): resp = web.StreamResponse(headers={"content-length": "100"}) await resp.prepare(request) @@ -2711,7 +2680,7 @@ async def handler(request): assert len(session._connector._conns) == 0 -async def test_release_resp_on_normal_exit_from_cm(aiohttp_server) -> None: +async def test_release_resp_on_normal_exit_from_cm(aiohttp_server: Any) -> None: async def handler(request): return web.Response() @@ -2726,7 +2695,7 @@ async def handler(request): assert len(session._connector._conns) == 1 -async def test_non_close_detached_session_on_error_cm(aiohttp_server) -> None: +async def test_non_close_detached_session_on_error_cm(aiohttp_server: Any) -> None: async def handler(request): resp = web.StreamResponse(headers={"content-length": "100"}) await resp.prepare(request) @@ -2768,7 +2737,7 @@ async def close(self): assert session.closed -async def test_aiohttp_request_context_manager(aiohttp_server) -> None: +async def test_aiohttp_request_context_manager(aiohttp_server: Any) -> None: async def handler(request): return web.Response() @@ -2782,7 +2751,7 @@ async def handler(request): async def test_aiohttp_request_ctx_manager_close_sess_on_error( - ssl_ctx, aiohttp_server + ssl_ctx: Any, aiohttp_server: Any ) -> None: async def handler(request): return web.Response() @@ -2801,13 +2770,32 @@ async def handler(request): async def test_aiohttp_request_ctx_manager_not_found() -> None: - with pytest.raises(aiohttp.ClientConnectionError): async with aiohttp.request("GET", "http://wrong-dns-name.com"): assert False, "never executed" # pragma: no cover -async def test_yield_from_in_session_request(aiohttp_client) -> None: +async def test_aiohttp_request_coroutine(aiohttp_server: Any) -> None: + async def handler(request): + return web.Response() + + app = web.Application() + app.router.add_get("/", handler) + server = await aiohttp_server(app) + + not_an_awaitable = aiohttp.request("GET", server.make_url("/")) + with pytest.raises( + TypeError, + match="^object _SessionRequestContextManager " + "can't be used in 'await' expression$", + ): + await not_an_awaitable + + await not_an_awaitable._coro # coroutine 'ClientSession._request' was never awaited + await server.close() + + +async def test_yield_from_in_session_request(aiohttp_client: Any) -> None: # a test for backward compatibility with yield from syntax async def handler(request): return web.Response() @@ -2820,7 +2808,7 @@ async def handler(request): assert resp.status == 200 -async def test_close_context_manager(aiohttp_client) -> None: +async def test_close_context_manager(aiohttp_client: Any) -> None: # a test for backward compatibility with yield from syntax async def handler(request): return web.Response() @@ -2834,7 +2822,7 @@ async def handler(request): assert not ctx._coro.cr_running -async def test_session_auth(aiohttp_client) -> None: +async def test_session_auth(aiohttp_client: Any) -> None: async def handler(request): return web.json_response({"headers": dict(request.headers)}) @@ -2849,7 +2837,7 @@ async def handler(request): assert content["headers"]["Authorization"] == "Basic bG9naW46cGFzcw==" -async def test_session_auth_override(aiohttp_client) -> None: +async def test_session_auth_override(aiohttp_client: Any) -> None: async def handler(request): return web.json_response({"headers": dict(request.headers)}) @@ -2865,7 +2853,7 @@ async def handler(request): assert val == "Basic b3RoZXJfbG9naW46cGFzcw==" -async def test_session_auth_header_conflict(aiohttp_client) -> None: +async def test_session_auth_header_conflict(aiohttp_client: Any) -> None: async def handler(request): return web.Response() @@ -2878,7 +2866,7 @@ async def handler(request): await client.get("/", headers=headers) -async def test_session_headers(aiohttp_client) -> None: +async def test_session_headers(aiohttp_client: Any) -> None: async def handler(request): return web.json_response({"headers": dict(request.headers)}) @@ -2893,7 +2881,7 @@ async def handler(request): assert content["headers"]["X-Real-IP"] == "192.168.0.1" -async def test_session_headers_merge(aiohttp_client) -> None: +async def test_session_headers_merge(aiohttp_client: Any) -> None: async def handler(request): return web.json_response({"headers": dict(request.headers)}) @@ -2911,7 +2899,7 @@ async def handler(request): assert content["headers"]["X-Sent-By"] == "aiohttp" -async def test_multidict_headers(aiohttp_client) -> None: +async def test_multidict_headers(aiohttp_client: Any) -> None: async def handler(request): assert await request.read() == data return web.Response() @@ -2929,7 +2917,7 @@ async def handler(request): assert r.status == 200 -async def test_request_conn_closed(aiohttp_client) -> None: +async def test_request_conn_closed(aiohttp_client: Any) -> None: async def handler(request): request.transport.close() return web.Response() @@ -2945,7 +2933,7 @@ async def handler(request): assert str(excinfo.value) != "" -async def test_dont_close_explicit_connector(aiohttp_client) -> None: +async def test_dont_close_explicit_connector(aiohttp_client: Any) -> None: async def handler(request): return web.Response() @@ -3042,7 +3030,9 @@ def connection_lost(self, exc): await server.wait_closed() -async def test_error_in_performing_request(ssl_ctx, aiohttp_client, aiohttp_server): +async def test_error_in_performing_request( + ssl_ctx: Any, aiohttp_client: Any, aiohttp_server: Any +): async def handler(request): return web.Response() @@ -3069,7 +3059,7 @@ def exception_handler(loop, context): await client.get("/") -async def test_await_after_cancelling(aiohttp_client) -> None: +async def test_await_after_cancelling(aiohttp_client: Any) -> None: loop = asyncio.get_event_loop() async def handler(request): @@ -3103,7 +3093,7 @@ async def canceller(): await asyncio.gather(fetch1(), fetch2(), canceller()) -async def test_async_payload_generator(aiohttp_client) -> None: +async def test_async_payload_generator(aiohttp_client: Any) -> None: async def handler(request): data = await request.read() assert data == b"1234567890" * 100 @@ -3122,7 +3112,7 @@ async def gen(): assert resp.status == 200 -async def test_read_from_closed_response(aiohttp_client) -> None: +async def test_read_from_closed_response(aiohttp_client: Any) -> None: async def handler(request): return web.Response(body=b"data") @@ -3138,7 +3128,7 @@ async def handler(request): await resp.read() -async def test_read_from_closed_response2(aiohttp_client) -> None: +async def test_read_from_closed_response2(aiohttp_client: Any) -> None: async def handler(request): return web.Response(body=b"data") @@ -3155,7 +3145,7 @@ async def handler(request): await resp.read() -async def test_read_from_closed_content(aiohttp_client) -> None: +async def test_read_from_closed_content(aiohttp_client: Any) -> None: async def handler(request): return web.Response(body=b"data") @@ -3171,7 +3161,7 @@ async def handler(request): await resp.content.readline() -async def test_read_timeout(aiohttp_client) -> None: +async def test_read_timeout(aiohttp_client: Any) -> None: async def handler(request): await asyncio.sleep(5) return web.Response() @@ -3186,7 +3176,40 @@ async def handler(request): await client.get("/") -async def test_read_timeout_on_prepared_response(aiohttp_client) -> None: +async def test_read_timeout_closes_connection(aiohttp_client: AiohttpClient) -> None: + request_count = 0 + + async def handler(request): + nonlocal request_count + request_count += 1 + if request_count < 3: + await asyncio.sleep(0.5) + return web.Response(body=f"request:{request_count}") + + app = web.Application() + app.add_routes([web.get("/", handler)]) + + timeout = aiohttp.ClientTimeout(total=0.1) + client: TestClient = await aiohttp_client(app, timeout=timeout) + with pytest.raises(asyncio.TimeoutError): + await client.get("/") + + # Make sure its really closed + assert not client.session.connector._conns + + with pytest.raises(asyncio.TimeoutError): + await client.get("/") + + # Make sure its really closed + assert not client.session.connector._conns + result = await client.get("/") + assert await result.read() == b"request:3" + + # Make sure its not closed + assert client.session.connector._conns + + +async def test_read_timeout_on_prepared_response(aiohttp_client: Any) -> None: async def handler(request): resp = aiohttp.web.StreamResponse() await resp.prepare(request) @@ -3205,7 +3228,7 @@ async def handler(request): await resp.read() -async def test_timeout_with_full_buffer(aiohttp_client) -> None: +async def test_timeout_with_full_buffer(aiohttp_client: Any) -> None: async def handler(request): """Server response that never ends and always has more data available.""" resp = web.StreamResponse() @@ -3229,7 +3252,7 @@ async def request(client): await asyncio.wait_for(request(client), 1) -async def test_read_bufsize_session_default(aiohttp_client) -> None: +async def test_read_bufsize_session_default(aiohttp_client: Any) -> None: async def handler(request): return web.Response(body=b"1234567") @@ -3242,7 +3265,7 @@ async def handler(request): assert resp.content.get_read_buffer_limits() == (2, 4) -async def test_read_bufsize_explicit(aiohttp_client) -> None: +async def test_read_bufsize_explicit(aiohttp_client: Any) -> None: async def handler(request): return web.Response(body=b"1234567") @@ -3255,7 +3278,7 @@ async def handler(request): assert resp.content.get_read_buffer_limits() == (4, 8) -async def test_http_empty_data_text(aiohttp_client) -> None: +async def test_http_empty_data_text(aiohttp_client: Any) -> None: async def handler(request): data = await request.read() ret = "ok" if data == b"" else "fail" @@ -3274,7 +3297,7 @@ async def handler(request): assert resp.headers["Content-Type"] == "text/plain; charset=utf-8" -async def test_max_field_size_session_default(aiohttp_client) -> None: +async def test_max_field_size_session_default(aiohttp_client: Any) -> None: async def handler(request): return web.Response(headers={"Custom": "x" * 8190}) @@ -3287,7 +3310,7 @@ async def handler(request): assert resp.headers["Custom"] == "x" * 8190 -async def test_max_field_size_session_default_fail(aiohttp_client) -> None: +async def test_max_field_size_session_default_fail(aiohttp_client: Any) -> None: async def handler(request): return web.Response(headers={"Custom": "x" * 8191}) @@ -3299,7 +3322,7 @@ async def handler(request): await client.get("/") -async def test_max_field_size_session_explicit(aiohttp_client) -> None: +async def test_max_field_size_session_explicit(aiohttp_client: Any) -> None: async def handler(request): return web.Response(headers={"Custom": "x" * 8191}) @@ -3312,7 +3335,7 @@ async def handler(request): assert resp.headers["Custom"] == "x" * 8191 -async def test_max_field_size_request_explicit(aiohttp_client) -> None: +async def test_max_field_size_request_explicit(aiohttp_client: Any) -> None: async def handler(request): return web.Response(headers={"Custom": "x" * 8191}) @@ -3325,7 +3348,7 @@ async def handler(request): assert resp.headers["Custom"] == "x" * 8191 -async def test_max_line_size_session_default(aiohttp_client) -> None: +async def test_max_line_size_session_default(aiohttp_client: Any) -> None: async def handler(request): return web.Response(status=200, reason="x" * 8190) @@ -3338,7 +3361,7 @@ async def handler(request): assert resp.reason == "x" * 8190 -async def test_max_line_size_session_default_fail(aiohttp_client) -> None: +async def test_max_line_size_session_default_fail(aiohttp_client: Any) -> None: async def handler(request): return web.Response(status=200, reason="x" * 8192) @@ -3350,7 +3373,7 @@ async def handler(request): await client.get("/") -async def test_max_line_size_session_explicit(aiohttp_client) -> None: +async def test_max_line_size_session_explicit(aiohttp_client: Any) -> None: async def handler(request): return web.Response(status=200, reason="x" * 8191) @@ -3363,7 +3386,7 @@ async def handler(request): assert resp.reason == "x" * 8191 -async def test_max_line_size_request_explicit(aiohttp_client) -> None: +async def test_max_line_size_request_explicit(aiohttp_client: Any) -> None: async def handler(request): return web.Response(status=200, reason="x" * 8191) @@ -3377,7 +3400,7 @@ async def handler(request): @pytest.mark.xfail(raises=asyncio.TimeoutError, reason="#7599") -async def test_rejected_upload(aiohttp_client, tmp_path) -> None: +async def test_rejected_upload(aiohttp_client: Any, tmp_path: Any) -> None: async def ok_handler(request): return web.Response()