@@ -2324,3 +2324,41 @@ async def handler(request: web.Request) -> web.Response:
23242324 # Make 2nd request which will hit the race condition.
23252325 async with client .get ("/" ) as resp :
23262326 assert resp .status == 200
2327+
2328+
2329+ async def test_keepalive_expires_on_time (aiohttp_client : AiohttpClient ) -> None :
2330+ """Test that the keepalive handle expires on time."""
2331+
2332+ async def handler (request : web .Request ) -> web .Response :
2333+ body = await request .read ()
2334+ assert b"" == body
2335+ return web .Response (body = b"OK" )
2336+
2337+ app = web .Application ()
2338+ app .router .add_route ("GET" , "/" , handler )
2339+
2340+ connector = aiohttp .TCPConnector (limit = 1 )
2341+ client = await aiohttp_client (app , connector = connector )
2342+
2343+ loop = asyncio .get_running_loop ()
2344+ now = loop .time ()
2345+
2346+ # Patch loop time so we can control when the keepalive timeout is processed
2347+ with mock .patch .object (loop , "time" ) as loop_time_mock :
2348+ loop_time_mock .return_value = now
2349+ resp1 = await client .get ("/" )
2350+ await resp1 .read ()
2351+ request_handler = client .server .handler .connections [0 ]
2352+
2353+ # Ensure the keep alive handle is set
2354+ assert request_handler ._keepalive_handle is not None
2355+
2356+ # Set the loop time to exactly the keepalive timeout
2357+ loop_time_mock .return_value = request_handler ._next_keepalive_close_time
2358+
2359+ # sleep twice to ensure the keep alive timeout is processed
2360+ await asyncio .sleep (0 )
2361+ await asyncio .sleep (0 )
2362+
2363+ # Ensure the keep alive handle expires
2364+ assert request_handler ._keepalive_handle is None
0 commit comments