From f36dad7b23249e3f067b0557a0a2c8b6bc6ca24f Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Tue, 7 Jul 2026 04:09:15 +0000 Subject: [PATCH] test(tls): drain full stdout for the TLS-fallback assertion (flake fix) test_tls_startup_failure_fallback_to_http read only the first 2000 bytes of server stdout to assert 'TLS setup failed'. When the test interpreter lacks optional deps (requests/websockets), startup emits a burst of plugin/tool import warnings + the startup-config banner BEFORE the TLS line, pushing the marker past the 2000-byte window -> spurious failure. Drain all currently-available stdout (5s deadline, short-circuit on the marker) instead of a single fixed-size read. Verified failing->passing in a fresh venv without the optional deps. Test-only; distinct from the agent-package-isolation flake cause already fixed in the same test. --- CHANGELOG.md | 2 ++ tests/test_tls_support.py | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9480330db..aa50883a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ ### Internal +- **Hardened `test_tls_support::test_tls_startup_failure_fallback_to_http` against stdout-preamble noise.** The test asserted the server prints "TLS setup failed" by reading only the first 2000 bytes of its stdout. When the test interpreter lacks optional deps (`requests`/`websockets`), startup emits a burst of plugin/tool import warnings plus the startup-config banner *before* the TLS line, pushing the marker past that fixed window → spurious failure (distinct from the agent-package-isolation cause fixed separately below). It now drains all currently-available stdout (bounded by a 5s deadline, short-circuiting once the marker is seen) instead of a single fixed-size read. Verified failing→passing in a fresh venv without the optional deps. Test-only. + - **Fixed the last 2 chronic local full-suite test-isolation flakes.** `test_tls_support::test_tls_startup_failure_fallback_to_http` and `test_v050259_sessiondb_fd_leak::test_session_db_close_is_idempotent` failed only in a full local suite run (they skip on CI, where the agent package isn't co-located). Root cause was the same "simulate agent package unavailable" antipattern shipped-fixed for the profile cluster: `test_custom_provider_prefix_collisions` clobbered `sys.modules['agent']` at collection time (never restored), and several helpers emptied real package `__path__` lists in place. Fixed at the source — the collection-time shim is now guarded on `importlib.util.find_spec` (only installed when the real package is genuinely absent), the in-place `__path__` mutations use `monkeypatch.setattr(..., raising=False)`, and `test_issue1574`'s fake-agent helper restores the env/`sys.path` it mutates. Full local suite now 0 failed (was 2); `test_title_aux_routing` unaffected. Test-only. ### Fixed diff --git a/tests/test_tls_support.py b/tests/test_tls_support.py index e3f28d6df..3aa54ff6b 100644 --- a/tests/test_tls_support.py +++ b/tests/test_tls_support.py @@ -295,14 +295,29 @@ class TestTLSEndToEnd(unittest.TestCase): self._proc = _start_and_wait( use_ssl=False, cert="/nonexistent/cert.pem", key="/nonexistent/key.pem", ) - # Confirm TLS warning was printed - import fcntl + # Confirm the TLS warning was printed. Drain ALL currently-available + # stdout, not just the first N bytes: startup can emit an unbounded + # amount of unrelated preamble first (optional-dep plugin/tool import + # warnings when the test venv lacks `requests`/`websockets`, the startup + # config banner, the state-dir hint, etc.), which can push the + # "TLS setup failed" line well past any fixed-size single read and make + # this test flaky depending on how noisy the environment is. os.set_blocking(self._proc.stdout.fileno(), False) output = "" - try: - output = self._proc.stdout.read(2000) or "" - except BlockingIOError: - output = "" + deadline = time.time() + 5 + while time.time() < deadline: + try: + chunk = self._proc.stdout.read(65536) + except BlockingIOError: + chunk = None + if chunk: + output += chunk + if "TLS setup failed" in output: + break + else: + if "TLS setup failed" in output: + break + time.sleep(0.05) self.assertIn("TLS setup failed", output)