From 1b460d35085f35cc54e3284be3f6299b33a60509 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 8 Jun 2023 20:44:44 +0200 Subject: [PATCH 01/17] Wait for client on `test_connection_lost_before_handshake_complete` --- tests/protocols/test_websocket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 22afeffad..5cd9bce4c 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -750,7 +750,7 @@ async def websocket_session(uri): await asyncio.sleep(0.1) send_accept_task.set() - task.cancel() + await task assert response is not None assert response.status_code == 500, response.text assert response.text == "Internal Server Error" From d245cdf986c1d4432bfddaa16ccfae79fbb8da3f Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 8 Jun 2023 20:56:02 +0200 Subject: [PATCH 02/17] Add asyncio.event --- tests/protocols/test_websocket.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 5cd9bce4c..7c8239bf6 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -712,6 +712,7 @@ async def test_connection_lost_before_handshake_complete( ws_protocol_cls, http_protocol_cls, unused_tcp_port: int ): send_accept_task = asyncio.Event() + response_received = asyncio.Event() disconnect_message = {} async def app(scope, receive, send): @@ -735,6 +736,7 @@ async def websocket_session(uri): "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==", }, ) + response_received.set() config = Config( app=app, @@ -750,7 +752,7 @@ async def websocket_session(uri): await asyncio.sleep(0.1) send_accept_task.set() - await task + await response_received.wait() assert response is not None assert response.status_code == 500, response.text assert response.text == "Internal Server Error" From 8abe5ddb1a8846c772f83f043768f8055d0b1f88 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 8 Jun 2023 21:00:47 +0200 Subject: [PATCH 03/17] Remove task variable --- tests/protocols/test_websocket.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 7c8239bf6..83d7685f8 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -746,9 +746,7 @@ async def websocket_session(uri): port=unused_tcp_port, ) async with run_server(config): - task = asyncio.create_task( - websocket_session(f"ws://127.0.0.1:{unused_tcp_port}") - ) + asyncio.create_task(websocket_session(f"ws://127.0.0.1:{unused_tcp_port}")) await asyncio.sleep(0.1) send_accept_task.set() From 5864e98ef95e7709acb9c8efecdff2b3b9461b92 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 08:53:10 +0200 Subject: [PATCH 04/17] Hold a reference to the task --- tests/protocols/test_websocket.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 83d7685f8..5d04bf6f5 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -746,7 +746,7 @@ async def websocket_session(uri): port=unused_tcp_port, ) async with run_server(config): - asyncio.create_task(websocket_session(f"ws://127.0.0.1:{unused_tcp_port}")) + task = asyncio.create_task(websocket_session(f"ws://127.0.0.1:{unused_tcp_port}")) # noqa: E501 await asyncio.sleep(0.1) send_accept_task.set() @@ -755,6 +755,7 @@ async def websocket_session(uri): assert response.status_code == 500, response.text assert response.text == "Internal Server Error" assert disconnect_message == {"type": "websocket.disconnect", "code": 1006} + await task @pytest.mark.anyio From 35699d246b2d69374f4a3fffb2585f1ac7de665c Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 08:54:23 +0200 Subject: [PATCH 05/17] Fix linter --- tests/protocols/test_websocket.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 5d04bf6f5..7177f318e 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -746,7 +746,9 @@ async def websocket_session(uri): port=unused_tcp_port, ) async with run_server(config): - task = asyncio.create_task(websocket_session(f"ws://127.0.0.1:{unused_tcp_port}")) # noqa: E501 + task = asyncio.create_task( + websocket_session(f"ws://127.0.0.1:{unused_tcp_port}") + ) await asyncio.sleep(0.1) send_accept_task.set() From b43f6b7fce42cb462ef8d07d3097f2eb4783ecff Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 09:09:47 +0200 Subject: [PATCH 06/17] Cancel instead of wait --- tests/protocols/test_websocket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 7177f318e..e85dff464 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -757,7 +757,7 @@ async def websocket_session(uri): assert response.status_code == 500, response.text assert response.text == "Internal Server Error" assert disconnect_message == {"type": "websocket.disconnect", "code": 1006} - await task + task.cancel() @pytest.mark.anyio From 507d27d11cb3642c0afbb479b94c25c363ed0d3a Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 09:56:43 +0200 Subject: [PATCH 07/17] Debug tests --- scripts/test | 2 +- tests/protocols/test_websocket.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/test b/scripts/test index ed2bdd01a..70c24d84d 100755 --- a/scripts/test +++ b/scripts/test @@ -11,7 +11,7 @@ if [ -z $GITHUB_ACTIONS ]; then scripts/check fi -${PREFIX}coverage run --debug config -m pytest "$@" +${PREFIX}coverage run --debug config -m pytest "$@" -s if [ -z $GITHUB_ACTIONS ]; then scripts/coverage diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index e85dff464..9711fc48a 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -727,6 +727,7 @@ async def app(scope, receive, send): async def websocket_session(uri): nonlocal response async with httpx.AsyncClient() as client: + print("Sending request") response = await client.get( f"http://127.0.0.1:{unused_tcp_port}", headers={ @@ -736,6 +737,7 @@ async def websocket_session(uri): "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==", }, ) + print("Response received") response_received.set() config = Config( @@ -746,12 +748,16 @@ async def websocket_session(uri): port=unused_tcp_port, ) async with run_server(config): + print("Server created") task = asyncio.create_task( websocket_session(f"ws://127.0.0.1:{unused_tcp_port}") ) + print("Task created") await asyncio.sleep(0.1) + print("Slept") send_accept_task.set() + print("Server shutdown") await response_received.wait() assert response is not None assert response.status_code == 500, response.text From 158080ed022edba0e8531dc16c8ac27a50ae1894 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 10:08:06 +0200 Subject: [PATCH 08/17] Debug tests --- pyproject.toml | 3 +++ tests/test_auto_detection.py | 2 +- uvicorn/middleware/wsgi.py | 2 +- uvicorn/supervisors/basereload.py | 12 ++++++------ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bf76ab36b..9f869b036 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,6 +111,9 @@ exclude_lines = [ "raise NotImplementedError", ] +[tool.coverage.coverage_conditional_plugin.omit] +"uvicorn/loops/uvloop.py" = "sys_platform == 'win32'" + [tool.coverage.coverage_conditional_plugin.rules] py-win32 = "sys_platform == 'win32'" py-not-win32 = "sys_platform != 'win32'" diff --git a/tests/test_auto_detection.py b/tests/test_auto_detection.py index 3ea452de3..c5531e72d 100644 --- a/tests/test_auto_detection.py +++ b/tests/test_auto_detection.py @@ -11,7 +11,7 @@ try: importlib.import_module("uvloop") - expected_loop = "uvloop" + expected_loop = "uvloop" # pragma: py-win32 except ImportError: # pragma: no cover expected_loop = "asyncio" diff --git a/uvicorn/middleware/wsgi.py b/uvicorn/middleware/wsgi.py index b87984488..381eca68e 100644 --- a/uvicorn/middleware/wsgi.py +++ b/uvicorn/middleware/wsgi.py @@ -199,5 +199,5 @@ def wsgi(self, environ: Environ, start_response: StartResponse) -> None: try: from a2wsgi import WSGIMiddleware -except ModuleNotFoundError: +except ModuleNotFoundError: # pragma: no cover WSGIMiddleware = _WSGIMiddleware # type: ignore[misc, assignment] diff --git a/uvicorn/supervisors/basereload.py b/uvicorn/supervisors/basereload.py index 0c1dc25ad..bcd5a5a8c 100644 --- a/uvicorn/supervisors/basereload.py +++ b/uvicorn/supervisors/basereload.py @@ -41,9 +41,9 @@ def signal_handler(self, sig: int, frame: Optional[FrameType]) -> None: A signal handler that is registered with the parent process. """ if sys.platform == "win32" and self.is_restarting: - self.is_restarting = False # pragma: py-not-win32 + self.is_restarting = False # pragma: py-win32 else: - self.should_exit.set() # pragma: py-win32 + self.should_exit.set() # pragma: py-not-win32 def run(self) -> None: self.startup() @@ -85,11 +85,11 @@ def startup(self) -> None: self.process.start() def restart(self) -> None: - if sys.platform == "win32": # pragma: py-not-win32 + if sys.platform == "win32": # pragma: py-win32 self.is_restarting = True assert self.process.pid is not None os.kill(self.process.pid, signal.CTRL_C_EVENT) - else: # pragma: py-win32 + else: # pragma: py-not-win32 self.process.terminate() self.process.join() @@ -100,9 +100,9 @@ def restart(self) -> None: def shutdown(self) -> None: if sys.platform == "win32": - self.should_exit.set() # pragma: py-not-win32 + self.should_exit.set() # pragma: py-win32 else: - self.process.terminate() # pragma: py-win32 + self.process.terminate() # pragma: py-not-win32 self.process.join() for sock in self.sockets: From 27cad4c37b9f197cc3d9bff313e2db570c52c90d Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 10:14:05 +0200 Subject: [PATCH 09/17] Debug tests --- tests/test_auto_detection.py | 2 +- uvicorn/supervisors/basereload.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_auto_detection.py b/tests/test_auto_detection.py index c5531e72d..e4d55cbf2 100644 --- a/tests/test_auto_detection.py +++ b/tests/test_auto_detection.py @@ -11,7 +11,7 @@ try: importlib.import_module("uvloop") - expected_loop = "uvloop" # pragma: py-win32 + expected_loop = "uvloop" # pragma: py-not-win32 except ImportError: # pragma: no cover expected_loop = "asyncio" diff --git a/uvicorn/supervisors/basereload.py b/uvicorn/supervisors/basereload.py index bcd5a5a8c..0c1dc25ad 100644 --- a/uvicorn/supervisors/basereload.py +++ b/uvicorn/supervisors/basereload.py @@ -41,9 +41,9 @@ def signal_handler(self, sig: int, frame: Optional[FrameType]) -> None: A signal handler that is registered with the parent process. """ if sys.platform == "win32" and self.is_restarting: - self.is_restarting = False # pragma: py-win32 + self.is_restarting = False # pragma: py-not-win32 else: - self.should_exit.set() # pragma: py-not-win32 + self.should_exit.set() # pragma: py-win32 def run(self) -> None: self.startup() @@ -85,11 +85,11 @@ def startup(self) -> None: self.process.start() def restart(self) -> None: - if sys.platform == "win32": # pragma: py-win32 + if sys.platform == "win32": # pragma: py-not-win32 self.is_restarting = True assert self.process.pid is not None os.kill(self.process.pid, signal.CTRL_C_EVENT) - else: # pragma: py-not-win32 + else: # pragma: py-win32 self.process.terminate() self.process.join() @@ -100,9 +100,9 @@ def restart(self) -> None: def shutdown(self) -> None: if sys.platform == "win32": - self.should_exit.set() # pragma: py-win32 + self.should_exit.set() # pragma: py-not-win32 else: - self.process.terminate() # pragma: py-not-win32 + self.process.terminate() # pragma: py-win32 self.process.join() for sock in self.sockets: From b241f31a34d71699a6df810b03e080f16284fd92 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 10:42:19 +0200 Subject: [PATCH 10/17] Debug tests --- tests/protocols/test_websocket.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 9711fc48a..d9da4629c 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -739,6 +739,7 @@ async def websocket_session(uri): ) print("Response received") response_received.set() + print("After response received") config = Config( app=app, From baec6c4d91eb31279e3ddc075d42b79a347cf521 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Jun 2023 12:54:53 +0200 Subject: [PATCH 11/17] more --- tests/protocols/test_websocket.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index d9da4629c..ec325b52e 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -760,6 +760,7 @@ async def websocket_session(uri): print("Server shutdown") await response_received.wait() + print("Wait... Is it getting here?") assert response is not None assert response.status_code == 500, response.text assert response.text == "Internal Server Error" From 6887835fb397c3a6f200734293a7f138a1f1465f Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 09:59:08 +0200 Subject: [PATCH 12/17] Change the location of the set response received --- tests/protocols/test_websocket.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index ec325b52e..2006c0f96 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -727,7 +727,6 @@ async def app(scope, receive, send): async def websocket_session(uri): nonlocal response async with httpx.AsyncClient() as client: - print("Sending request") response = await client.get( f"http://127.0.0.1:{unused_tcp_port}", headers={ @@ -737,9 +736,7 @@ async def websocket_session(uri): "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==", }, ) - print("Response received") - response_received.set() - print("After response received") + response_received.set() config = Config( app=app, @@ -749,18 +746,13 @@ async def websocket_session(uri): port=unused_tcp_port, ) async with run_server(config): - print("Server created") task = asyncio.create_task( websocket_session(f"ws://127.0.0.1:{unused_tcp_port}") ) - print("Task created") await asyncio.sleep(0.1) - print("Slept") send_accept_task.set() - print("Server shutdown") await response_received.wait() - print("Wait... Is it getting here?") assert response is not None assert response.status_code == 500, response.text assert response.text == "Internal Server Error" From 54658554da2de75f03e3357d690e3865cea1006f Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 10:31:46 +0200 Subject: [PATCH 13/17] Add another await --- tests/protocols/test_websocket.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 2006c0f96..e1def08a6 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -719,14 +719,18 @@ async def app(scope, receive, send): nonlocal disconnect_message message = await receive() if message["type"] == "websocket.connect": + print("3") await send_accept_task.wait() + print("6") disconnect_message = await receive() response: typing.Optional[httpx.Response] = None async def websocket_session(uri): nonlocal response + print("2") async with httpx.AsyncClient() as client: + print("2.5") response = await client.get( f"http://127.0.0.1:{unused_tcp_port}", headers={ @@ -736,7 +740,7 @@ async def websocket_session(uri): "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==", }, ) - response_received.set() + print("8") config = Config( app=app, @@ -746,18 +750,22 @@ async def websocket_session(uri): port=unused_tcp_port, ) async with run_server(config): + print("0") task = asyncio.create_task( websocket_session(f"ws://127.0.0.1:{unused_tcp_port}") ) + print("1") await asyncio.sleep(0.1) + print("4") send_accept_task.set() + print("5") + await asyncio.sleep(0.1) + print("7") - await response_received.wait() assert response is not None assert response.status_code == 500, response.text assert response.text == "Internal Server Error" assert disconnect_message == {"type": "websocket.disconnect", "code": 1006} - task.cancel() @pytest.mark.anyio From ca0165886796c779dc6d35ab474961d321851102 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 10:36:54 +0200 Subject: [PATCH 14/17] await task --- tests/protocols/test_websocket.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index e1def08a6..686f0136d 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -766,6 +766,7 @@ async def websocket_session(uri): assert response.status_code == 500, response.text assert response.text == "Internal Server Error" assert disconnect_message == {"type": "websocket.disconnect", "code": 1006} + await task @pytest.mark.anyio From 8dba04988a0ab035164d81c237b6919c39004ef5 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 10:37:08 +0200 Subject: [PATCH 15/17] remove event --- tests/protocols/test_websocket.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index 686f0136d..a1f6183a7 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -712,7 +712,6 @@ async def test_connection_lost_before_handshake_complete( ws_protocol_cls, http_protocol_cls, unused_tcp_port: int ): send_accept_task = asyncio.Event() - response_received = asyncio.Event() disconnect_message = {} async def app(scope, receive, send): From d3505d66b0231e821bb805fe6e9197af785c62cd Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 11:13:36 +0200 Subject: [PATCH 16/17] remove print --- tests/protocols/test_websocket.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index a1f6183a7..b1e5d03d5 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -718,16 +718,13 @@ async def app(scope, receive, send): nonlocal disconnect_message message = await receive() if message["type"] == "websocket.connect": - print("3") await send_accept_task.wait() - print("6") disconnect_message = await receive() response: typing.Optional[httpx.Response] = None async def websocket_session(uri): nonlocal response - print("2") async with httpx.AsyncClient() as client: print("2.5") response = await client.get( @@ -739,7 +736,6 @@ async def websocket_session(uri): "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==", }, ) - print("8") config = Config( app=app, @@ -749,17 +745,12 @@ async def websocket_session(uri): port=unused_tcp_port, ) async with run_server(config): - print("0") task = asyncio.create_task( websocket_session(f"ws://127.0.0.1:{unused_tcp_port}") ) - print("1") await asyncio.sleep(0.1) - print("4") send_accept_task.set() - print("5") await asyncio.sleep(0.1) - print("7") assert response is not None assert response.status_code == 500, response.text From 3fb818d57aa3609182234a2a5ec1b0a175a5eaf7 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 03:26:12 -0600 Subject: [PATCH 17/17] Apply suggestions from code review --- scripts/test | 2 +- tests/protocols/test_websocket.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/test b/scripts/test index 70c24d84d..ed2bdd01a 100755 --- a/scripts/test +++ b/scripts/test @@ -11,7 +11,7 @@ if [ -z $GITHUB_ACTIONS ]; then scripts/check fi -${PREFIX}coverage run --debug config -m pytest "$@" -s +${PREFIX}coverage run --debug config -m pytest "$@" if [ -z $GITHUB_ACTIONS ]; then scripts/coverage diff --git a/tests/protocols/test_websocket.py b/tests/protocols/test_websocket.py index b1e5d03d5..d6988e8f5 100644 --- a/tests/protocols/test_websocket.py +++ b/tests/protocols/test_websocket.py @@ -726,7 +726,6 @@ async def app(scope, receive, send): async def websocket_session(uri): nonlocal response async with httpx.AsyncClient() as client: - print("2.5") response = await client.get( f"http://127.0.0.1:{unused_tcp_port}", headers={