test_land_closeout_stress.py python
81 lines 2.9 KB
Raw
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