test: de-flake query_stream early-break test

The _no_sleep autouse fixture patches time.sleep on the shared time module
object, so the SlowResponse pacing (`import time; time.sleep(0.002)`) was a
no-op — the background thread raced to drain all 1000 chunks before the
consumer's early break propagated, failing `assert not drained_all.is_set()`
intermittently. Capture the real sleep at import (before the fixture patches)
and pace with it, restoring the 2s drain vs ms-teardown margin the test needs.
Production stop logic was correct; only the test's pacing was broken.
This commit is contained in:
mountain 2026-07-09 20:09:23 +08:00
parent 4c7d1088ba
commit 72f623ad5d

View file

@ -1,6 +1,7 @@
import asyncio import asyncio
import io import io
import json import json
import time
import pytest import pytest
@ -8,6 +9,12 @@ import pageindex.backend.cloud as cloud_mod
from pageindex.backend.cloud import CloudBackend, API_BASE from pageindex.backend.cloud import CloudBackend, API_BASE
from pageindex.errors import CloudAPIError, DocumentNotFoundError from pageindex.errors import CloudAPIError, DocumentNotFoundError
# Real sleep captured at import, before the _no_sleep autouse fixture patches
# time.sleep on the shared module object. Tests that need genuine pacing (e.g.
# to let a consumer break before a background thread drains a stream) must use
# this, since _no_sleep would otherwise no-op an `import time; time.sleep(...)`.
_REAL_SLEEP = time.sleep
def test_cloud_backend_init(): def test_cloud_backend_init():
backend = CloudBackend(api_key="pi-test") backend = CloudBackend(api_key="pi-test")
@ -243,7 +250,6 @@ def test_query_stream_early_break_stops_background_thread(monkeypatch):
"""Consumer breaking early must signal the SSE thread to stop, not let it """Consumer breaking early must signal the SSE thread to stop, not let it
drain the whole stream in the background.""" drain the whole stream in the background."""
import threading import threading
import time as _real_time # autouse fixture stubs cloud_mod.time.sleep, not this
backend = CloudBackend(api_key="pi-test") backend = CloudBackend(api_key="pi-test")
drained_all = threading.Event() drained_all = threading.Event()
@ -253,7 +259,11 @@ def test_query_stream_early_break_stops_background_thread(monkeypatch):
def iter_lines(self, decode_unicode=True): def iter_lines(self, decode_unicode=True):
for i in range(1000): for i in range(1000):
yield _sse("text", f"chunk{i} ") yield _sse("text", f"chunk{i} ")
_real_time.sleep(0.002) # pace so the consumer reliably breaks first # _REAL_SLEEP, not time.sleep: the _no_sleep autouse fixture
# patches the shared time module, so time.sleep here would be a
# no-op and the thread would race to drain all 1000 chunks
# before the consumer's early break propagates -> flaky.
_REAL_SLEEP(0.002) # pace so the consumer reliably breaks first
drained_all.set() # only reached if the thread was NOT stopped drained_all.set() # only reached if the thread was NOT stopped
def close(self): def close(self):
pass pass