22import time
33from http import HTTPStatus
44from typing import NoReturn
5- from wsgiref .simple_server import WSGIServer , make_server
65
76import pytest
7+ import uvicorn
88from httpx import (
99 ASGITransport ,
1010 AsyncClient ,
@@ -320,31 +320,41 @@ async def make_hat(self, request, ctx):
320320
321321# To exercise timeouts, can't use mock transports
322322@pytest .fixture (scope = "module" )
323- def sync_timeout_server ():
324- class SleepingHaberdasherSync ( HaberdasherSync ):
323+ def timeout_server ():
324+ class SleepingHaberdasher ( Haberdasher ):
325325 def make_hat (self , request , ctx ) -> NoReturn :
326326 time .sleep (10 )
327327 raise AssertionError ("Should be timedout already" )
328328
329- app = HaberdasherWSGIApplication (SleepingHaberdasherSync ())
329+ app = HaberdasherASGIApplication (SleepingHaberdasher ())
330+ config = uvicorn .Config (
331+ app , port = 0 , log_level = "critical" , timeout_graceful_shutdown = 0
332+ )
333+ server = uvicorn .Server (config )
334+ # Since we want to target the server from sync clients as well as async,
335+ # it's best to use a sync fixture with the server on a background thread.
336+ thread = threading .Thread (target = server .run )
337+ thread .daemon = True
338+ thread .start ()
339+
340+ for _ in range (50 ):
341+ if server .started :
342+ break
343+ time .sleep (0.1 )
344+ assert server .started
345+
346+ port = server .servers [0 ].sockets [0 ].getsockname ()[1 ]
347+
348+ yield f"http://localhost:{ port } "
330349
331- with make_server ("" , 0 , app ) as httpd :
332- thread = threading .Thread (target = httpd .serve_forever )
333- thread .daemon = True
334- thread .start ()
335- try :
336- yield httpd
337- finally :
338- # Don't wait for sleeping server to shutdown cleanly for this
339- # test, we don't care anyways.
340- pass
350+ server .should_exit = True
341351
342352
343353@pytest .mark .parametrize (
344- ("client_timeout_ms" , "call_timeout_ms" ), [(1 , None ), (None , 1 )]
354+ ("client_timeout_ms" , "call_timeout_ms" ), [(50 , None ), (None , 50 )]
345355)
346356def test_sync_client_timeout (
347- client_timeout_ms , call_timeout_ms , sync_timeout_server : WSGIServer
357+ client_timeout_ms , call_timeout_ms , timeout_server : str
348358) -> None :
349359 recorded_timeout_header = ""
350360
@@ -365,25 +375,23 @@ def modify_timeout_header(request: Request) -> None:
365375 event_hooks = {"request" : [modify_timeout_header ]},
366376 ) as session ,
367377 HaberdasherClientSync (
368- f"http://localhost:{ sync_timeout_server .server_port } " ,
369- timeout_ms = client_timeout_ms ,
370- session = session ,
378+ timeout_server , timeout_ms = client_timeout_ms , session = session
371379 ) as client ,
372380 pytest .raises (ConnectError ) as exc_info ,
373381 ):
374382 client .make_hat (request = Size (inches = 10 ), timeout_ms = call_timeout_ms )
375383
376384 assert exc_info .value .code == Code .DEADLINE_EXCEEDED
377385 assert exc_info .value .message == "Request timed out"
378- assert recorded_timeout_header == "1 "
386+ assert recorded_timeout_header == "50 "
379387
380388
381389@pytest .mark .asyncio
382390@pytest .mark .parametrize (
383- ("client_timeout_ms" , "call_timeout_ms" ), [(1 , None ), (None , 1 )]
391+ ("client_timeout_ms" , "call_timeout_ms" ), [(50 , None ), (None , 50 )]
384392)
385393async def test_async_client_timeout (
386- client_timeout_ms , call_timeout_ms , sync_timeout_server : WSGIServer
394+ client_timeout_ms , call_timeout_ms , timeout_server : str
387395) -> None :
388396 recorded_timeout_header = ""
389397
@@ -398,14 +406,12 @@ async def modify_timeout_header(request: Request) -> None:
398406 timeout = Timeout (None ), event_hooks = {"request" : [modify_timeout_header ]}
399407 ) as session ,
400408 HaberdasherClient (
401- f"http://localhost:{ sync_timeout_server .server_port } " ,
402- timeout_ms = client_timeout_ms ,
403- session = session ,
409+ timeout_server , timeout_ms = client_timeout_ms , session = session
404410 ) as client ,
405411 ):
406412 with pytest .raises (ConnectError ) as exc_info :
407413 await client .make_hat (request = Size (inches = 10 ), timeout_ms = call_timeout_ms )
408414
409415 assert exc_info .value .code == Code .DEADLINE_EXCEEDED
410416 assert exc_info .value .message == "Request timed out"
411- assert recorded_timeout_header == "1 "
417+ assert recorded_timeout_header == "50 "
0 commit comments