Merge pull request #482 from razzant/fix-services-test-race
Some checks failed
CI / quick-test (push) Waiting to run
CI / full-test (macos-latest) (push) Waiting to run
CI / full-test (ubuntu-latest) (push) Waiting to run
CI / full-test (windows-latest) (push) Waiting to run
CI / betterleaks-platform-smoke (macos-latest) (push) Waiting to run
CI / betterleaks-platform-smoke (ubuntu-latest) (push) Waiting to run
CI / betterleaks-platform-smoke (windows-latest) (push) Waiting to run
CI / integration-test (push) Waiting to run
CI / skill-smoke (macos-latest) (push) Waiting to run
CI / skill-smoke (ubuntu-latest) (push) Waiting to run
CI / skill-smoke (windows-latest) (push) Waiting to run
CI / marker-guards (push) Waiting to run
CI / ui-smoke (push) Waiting to run
CI / docker-ui-smoke (push) Waiting to run
CI / docker-portable-test (push) Waiting to run
CI / release-preflight (push) Blocked by required conditions
CI / build (dmg, macos-latest, macos-arm64, syft_1.50.0_darwin_arm64.tar.gz, syft, e32fdb9d47823fa633748a1efca2528fd77c37469ea93c9e40ab835da44e4cce) (push) Blocked by required conditions
CI / build (tar.gz, ubuntu-latest, linux-x86_64, syft_1.50.0_linux_amd64.tar.gz, syft, bf7b29ff57f06da30918266a0e1c2885a8f99784798d1bdb1628886aa015d788) (push) Blocked by required conditions
CI / build (zip, windows-latest, windows-x64, syft_1.50.0_windows_amd64.zip, syft.exe, 815ee6973ec5dff6a671d7f41b0e78835a8c45b91d5a39f4743ea1cee833d3be) (push) Blocked by required conditions
CI / vendor-package-smoke (push) Blocked by required conditions
CI / release (push) Blocked by required conditions
Claudexor platform gate (API keys — subscription auth NOT covered) / fixture · macos-latest · exact managed runtime, fake harness, no model (push) Waiting to run
Claudexor platform gate (API keys — subscription auth NOT covered) / fixture · ubuntu-latest · exact managed runtime, fake harness, no model (push) Waiting to run
Claudexor platform gate (API keys — subscription auth NOT covered) / fixture · windows-latest · exact managed runtime, fake harness, no model (push) Waiting to run
Claudexor platform gate (API keys — subscription auth NOT covered) / live · macos-latest · claude · API key only, subscription NOT covered (push) Waiting to run
Claudexor platform gate (API keys — subscription auth NOT covered) / live · ubuntu-latest · claude · API key only, subscription NOT covered (push) Waiting to run
Claudexor platform gate (API keys — subscription auth NOT covered) / live · windows-latest · claude · API key only, subscription NOT covered (push) Waiting to run
Claudexor platform gate (API keys — subscription auth NOT covered) / live · macos-latest · codex · API key only, subscription NOT covered (push) Waiting to run
Submit Claudexor dependency / Submit managed runtime snapshot (push) Has been cancelled

test: wait for observable service-log state instead of racing the child
This commit is contained in:
Anton Razzhigaev 2026-09-01 22:06:11 +03:00 • committed by GitHub
commit f3fbfdbbd1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -11,6 +11,30 @@ from ouroboros.tools.registry import ToolRegistry
from ouroboros.tools.services import archive_task_service_logs, prune_service_logs
def _wait_for_service_log(drive, task_id, name, predicate, timeout_sec=15.0):
"""Wait until the service's live log satisfies ``predicate``.
The start_service readiness contract without a stdout marker is "process
alive == ready" — it never waits for output. These suites assert on log
CONTENT, so they must wait for the observable condition themselves: on a
slow CI runner the child's first write can land well after start_service
returns (a latent race exposed when the guard path got faster), and the
assertions below are about redaction/finalization, never about timing.
"""
log_path = drive / "services" / task_id / name
deadline = time.time() + timeout_sec
while time.time() < deadline:
try:
if predicate(log_path.read_bytes() if log_path.exists() else b""):
return
except OSError:
pass
time.sleep(0.1)
raise AssertionError(
f"service log {log_path} did not satisfy the wait predicate within {timeout_sec}s"
)
def _force_advanced_runtime(monkeypatch):
from ouroboros import config as cfg
@ -80,6 +104,7 @@ def test_service_logs_redact_secret_assignments(tmp_path, monkeypatch):
"readiness": {"timeout_sec": 1},
})
assert json.loads(start)["state"] in {"running", "exited"}
_wait_for_service_log(drive, "task-1", "secretlog.log", lambda b: b"OPENAI_API_KEY=" in b)
logs = json.loads(registry.execute("service_logs", {"name": "secretlog", "tail": 500}))
registry.execute("stop_service", {"name": "secretlog"})
@ -537,6 +562,7 @@ def test_stop_service_retains_live_log_when_full_blob_omitted(tmp_path, monkeypa
"cmd": [sys.executable, "-c", "print('x' * 100, flush=True)"],
"readiness": {"timeout_sec": 1},
})
_wait_for_service_log(drive, "task-oversize", "oversize.log", lambda b: len(b) > 100)
stopped = json.loads(registry.execute("stop_service", {"name": "oversize"}))
finalization = stopped["log_finalization"]
@ -846,6 +872,7 @@ def test_service_outputs_register_artifacts_on_stop(tmp_path, monkeypatch):
"readiness": {"timeout_sec": 1},
})
assert "LIGHT_MODE_BLOCKED" not in start
_wait_for_service_log(drive, "task-service-output", "artifact_service.log", lambda b: b"READY" in b)
stopped = json.loads(registry.execute("stop_service", {"name": "artifact_service"}))