From 1b64d16da9b433dc247fe51fb5e400bdd13441ef Mon Sep 17 00:00:00 2001 From: Sean McLellan Date: Tue, 3 Feb 2026 19:51:39 -0500 Subject: [PATCH 1/2] ci: add pytest-timeout and job timeout to diagnose Python 3.11 hang Python 3.11 CI jobs hang indefinitely during pytest while 3.12/3.13 complete in ~80 seconds. Add: - pytest-timeout (30s per test) to identify which test hangs - 10-minute job timeout to prevent multi-hour CI runs - Verbose pytest output in CI for better diagnostics Co-Authored-By: Claude Opus 4.5 --- .github/workflows/test.yml | 3 ++- pyproject.toml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 466b93f..0cab52a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,6 +8,7 @@ on: jobs: test: runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: python-version: ["3.11", "3.12", "3.13"] @@ -20,4 +21,4 @@ jobs: - run: ruff check src/ tests/ - run: ruff format --check src/ tests/ - run: mypy src/ - - run: pytest + - run: pytest -v --timeout=30 diff --git a/pyproject.toml b/pyproject.toml index 1695ff7..1ee16d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ dev = [ "pytest-httpx>=0.34", "pytest-xdist>=3.0", "pytest-cov>=5.0", + "pytest-timeout>=2.3", "ruff>=0.8", "mypy>=1.13", "mypy-protobuf>=3.6", @@ -88,6 +89,7 @@ plugins = ["pydantic.mypy"] testpaths = ["tests"] asyncio_mode = "auto" addopts = "-n auto -m 'not e2e'" +timeout = 30 markers = [ "e2e: End-to-end smoke tests against the live Tesla Fleet API (requires TESLA_ACCESS_TOKEN)", ] From c7186da0eaa5de2d317c2dbd1e22164d3c010a6f Mon Sep 17 00:00:00 2001 From: Sean McLellan Date: Tue, 3 Feb 2026 20:14:39 -0500 Subject: [PATCH 2/2] fix: avoid Textual run_test() in queue overflow test for Python 3.11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test_queue_overflow_drops_silently test deadlocks on Python 3.11 because Textual's ContextVar handling + asyncio event loop scheduling differs from 3.12+. The test only validates that push_frame silently drops frames when the queue is full — it doesn't need the full Textual app lifecycle. Remove app.run_test() wrapper to fix the 3.11 hang. Co-Authored-By: Claude Opus 4.5 --- tests/telemetry/test_tui.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/telemetry/test_tui.py b/tests/telemetry/test_tui.py index 6614c1d..20522e4 100644 --- a/tests/telemetry/test_tui.py +++ b/tests/telemetry/test_tui.py @@ -310,14 +310,15 @@ async def test_unknown_field_goes_to_diagnostics(self) -> None: @pytest.mark.asyncio async def test_queue_overflow_drops_silently(self) -> None: + # Test the overflow behavior directly without Textual's run_test(), + # which deadlocks on Python 3.11 due to ContextVar + event loop + # scheduling differences between 3.11 and 3.12+. app = TelemetryTUI(vin=VIN) - async with app.run_test(): - # Fill the queue. - for i in range(110): - await app.push_frame(_frame(("BatteryLevel", 8, 80 - i, "int"))) + for i in range(110): + await app.push_frame(_frame(("BatteryLevel", 8, 80 - i, "int"))) - # No exception should be raised — overflow is silent. - assert app._queue.qsize() <= 100 + # No exception should be raised — overflow is silent. + assert app._queue.qsize() <= 100 @pytest.mark.asyncio async def test_server_info_setters(self) -> None: