| from pathlib import Path |
|
|
| from app import _events_from_job_logs |
|
|
|
|
| def test_job_log_event_parser_handles_prefix_suffix_and_ansi(): |
| logs = """ |
| 2026-06-02T10:00:00Z stdout: \x1b[32m{"ts":"2026-06-02T10:00:00+00:00","step":"bootstrap","status":"success","message":"ok"}\x1b[0m |
| INFO prefix {"ts":"2026-06-02T10:01:00+00:00","step":"pi_run","status":"running","message":"Pi"} trailing text |
| """ |
| events = _events_from_job_logs(logs) |
| assert [e["step"] for e in events] == ["bootstrap", "pi_run"] |
|
|
|
|
| def test_progress_endpoint_fetches_deeper_job_log_window(): |
| app = Path("app.py").read_text(encoding="utf-8") |
| assert "max_lines=1000" in app |
| assert "JSONDecoder().raw_decode" not in app |
| assert "decoder.raw_decode" in app |
| assert "ANSI_RE" in app |
|
|
|
|
| def test_frontend_progress_is_monotonic_per_run(): |
| js = Path("web/static/progress.js").read_text(encoding="utf-8") |
| assert "const progressStability" in js |
| assert "function stabilizeProgressPayload" in js |
| assert "Math.max(rawProgress,progressStability.progress)" in js |
| assert "timelineFurthestIndex" in js |
| assert "resetProgressStability(runId)" in Path("web/static/app.js").read_text(encoding="utf-8") |
|
|
|
|
| def test_light_poll_cannot_reset_timeline_signature_to_earlier_steps(): |
| js = Path("web/static/progress.js").read_text(encoding="utf-8") |
| assert "rawIndex>=progressStability.furthestIndex" in js |
| assert "cloneTimeline(progressStability.timeline)" in js |
|
|
|
|
| def test_app_version_v67(): |
| assert '"version": "v70-progress-resume-events-latency"' in Path("app.py").read_text(encoding="utf-8") |
|
|