diff --git a/tests/conftest.py b/tests/conftest.py index 292fdadf2..d6d60233c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -195,8 +195,8 @@ def _serve_test_static(): return "text/css" return super().guess_type(path) - class _Server(socketserver.TCPServer): - allow_reuse_address = True + class _Server(socketserver.ThreadingTCPServer): + allow_reuse_address = daemon_threads = True requested = int(os.environ.get("ODYSSEUS_TEST_STATIC_PORT") or 0) if not 0 <= requested <= 65535: @@ -214,6 +214,8 @@ def _serve_test_static(): previous_origin = os.environ.get("ODYSSEUS_TEST_STATIC_ORIGIN") os.environ["ODYSSEUS_TEST_STATIC_ORIGIN"] = origin + # One thread per connection: Chromium can hold a speculative connection + # open without a request, which stalled serial service for ~30s. thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() try: diff --git a/tests/test_static_test_server.py b/tests/test_static_test_server.py index f55546e9b..7e5bfaad4 100644 --- a/tests/test_static_test_server.py +++ b/tests/test_static_test_server.py @@ -7,7 +7,9 @@ running its own suite took the whole session down with it. import os import re +import socket import urllib.request +from urllib.parse import urlsplit from pathlib import Path @@ -31,8 +33,12 @@ def test_static_origin_does_not_reuse_the_application_port() -> None: def test_static_server_serves_this_worktree() -> None: origin = os.environ["ODYSSEUS_TEST_STATIC_ORIGIN"] + address = urlsplit(origin) - with urllib.request.urlopen(f"{origin}/static/js/documentStats.js", timeout=5) as r: + # Chromium may open a speculative connection and never send a request; + # that must not stall the requests queued behind it. + with socket.create_connection((address.hostname, address.port), timeout=5), \ + urllib.request.urlopen(f"{origin}/static/js/documentStats.js", timeout=5) as r: assert r.status == 200 assert r.headers.get_content_type() == "application/javascript"