test_land_closeout_stress.py
python
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
12 hours ago
| 1 | """Stress: land-closeout on large handover/roadmap stays bounded (§PMHF.10 stress).""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | import time |
| 6 | from pathlib import Path |
| 7 | from unittest.mock import MagicMock |
| 8 | |
| 9 | from adapters.runner import RecordingRunner |
| 10 | from adapters.types import AnchorResult, HeadResult, StatusResult |
| 11 | from tests.support import land_handover_text, load_fixture_config, seed_land_repo |
| 12 | from tools.land_closeout import check_land_closeout |
| 13 | |
| 14 | |
| 15 | def _adapter(tip: str = "cafebabe") -> MagicMock: |
| 16 | adapter = MagicMock() |
| 17 | adapter.status.return_value = StatusResult( |
| 18 | regime="git-only", dirty=False, branch="main", muse_dirty=None, git_dirty=False |
| 19 | ) |
| 20 | adapter.read_head.return_value = HeadResult(sha=tip, kind="git") |
| 21 | adapter.read_canonical_anchor.return_value = AnchorResult( |
| 22 | anchor_sha=tip, source="origin/main" |
| 23 | ) |
| 24 | return adapter |
| 25 | |
| 26 | |
| 27 | def _large_roadmap(rows: int = 250) -> str: |
| 28 | lines = [ |
| 29 | "# Roadmap — stress fixture", |
| 30 | "", |
| 31 | "## Build queue", |
| 32 | "", |
| 33 | "| Phase | Model | Status | Deliverable |", |
| 34 | "| --- | --- | --- | --- |", |
| 35 | ] |
| 36 | for index in range(rows): |
| 37 | # Historical DONE land rows for other slices must not conflict. |
| 38 | lines.append( |
| 39 | f"| **SLICE{index} → main** | Operator + Auto | **DONE** | landed slice {index} |" |
| 40 | ) |
| 41 | lines.append("| **PMHF → main** | Operator + Auto | **TODO** | Land PMHF |") |
| 42 | lines.extend(["", "## Definition of Done", "", "- Tests green"]) |
| 43 | return "\n".join(lines) + "\n" |
| 44 | |
| 45 | |
| 46 | def test_large_queue_and_handover_bounded_and_no_gh(tmp_path: Path) -> None: |
| 47 | padding = "\n".join(f"- historical change log line {i}" for i in range(2000)) |
| 48 | handover = land_handover_text("cafebabe") + "\n" + padding + "\n" |
| 49 | seed_land_repo( |
| 50 | tmp_path, |
| 51 | handover_text=handover, |
| 52 | roadmap_text=_large_roadmap(), |
| 53 | ) |
| 54 | config = load_fixture_config(tmp_path, "config-git-only.yaml") |
| 55 | runner = RecordingRunner(responses={}, calls=[]) |
| 56 | |
| 57 | start = time.monotonic() |
| 58 | report = check_land_closeout( |
| 59 | config, |
| 60 | tmp_path, |
| 61 | adapter=_adapter(), |
| 62 | runner=runner, |
| 63 | probe_merged_pr=False, |
| 64 | ) |
| 65 | elapsed = time.monotonic() - start |
| 66 | |
| 67 | assert elapsed < 2.0 # parse + freshness compose stays bounded |
| 68 | assert report.state == "land_a_in_progress" # 250 other-slice DONE rows: no conflict |
| 69 | assert not any(call[0].startswith("gh") for call in runner.calls) |
| 70 | |
| 71 | |
| 72 | def test_large_queue_conflict_still_detected(tmp_path: Path) -> None: |
| 73 | roadmap = _large_roadmap().replace( |
| 74 | "| **PMHF → main** | Operator + Auto | **TODO** | Land PMHF |", |
| 75 | "| **PMHF → main** | Operator + Auto | **DONE** | Land PMHF |", |
| 76 | ) |
| 77 | seed_land_repo(tmp_path, roadmap_text=roadmap) |
| 78 | config = load_fixture_config(tmp_path, "config-git-only.yaml") |
| 79 | report = check_land_closeout(config, tmp_path, adapter=_adapter()) |
| 80 | assert report.state == "unreadable" |
| 81 | assert "land_phase_conflicts_queue_done" in report.message |
File History
1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
12 hours ago