test_cli_workspace.py
python
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
1 day ago
| 1 | """Integration tests for ok workspace CLI (§MR.10 integration).""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | import json |
| 6 | from pathlib import Path |
| 7 | |
| 8 | from tests.fixtures.workspace import build_two_repo_constellation |
| 9 | from tests.support import run_cli |
| 10 | from tools.workspace.types import EXIT_WORKSPACE_RELAY |
| 11 | |
| 12 | |
| 13 | def test_workspace_status_json_basenames(tmp_path: Path) -> None: |
| 14 | fx = build_two_repo_constellation(tmp_path) |
| 15 | code = run_cli(["workspace", "status", "--json"], cwd=fx["scooling"]) |
| 16 | assert code == 0 |
| 17 | # run_cli may not capture stdout — use main with capsys style via subprocess helper |
| 18 | from tests.support import run_shim |
| 19 | |
| 20 | result = run_shim("ok", ["workspace", "status", "--json"], cwd=fx["scooling"]) |
| 21 | assert result.exit_code == 0 |
| 22 | payload = json.loads(result.stdout) |
| 23 | assert payload["authoritative_handover"] |
| 24 | bases = {m["id"]: m["handover_basename"] for m in payload["members"]} |
| 25 | assert bases["scooling"] == "SCOOLING-OVERSEER-HANDOVER.md" |
| 26 | assert bases["knowtation"] == "KNOWTATION-OVERSEER-HANDOVER.md" |
| 27 | assert bases["scooling"] != bases["knowtation"] |
| 28 | |
| 29 | |
| 30 | def test_check_next_exit_codes(tmp_path: Path) -> None: |
| 31 | from tests.support import run_shim |
| 32 | |
| 33 | good = build_two_repo_constellation(tmp_path / "g") |
| 34 | bad = build_two_repo_constellation(tmp_path / "b", stale_relay=True) |
| 35 | assert run_shim("ok", ["workspace", "check-next"], cwd=good["scooling"]).exit_code == 0 |
| 36 | assert ( |
| 37 | run_shim("ok", ["workspace", "check-next"], cwd=bad["scooling"]).exit_code |
| 38 | == EXIT_WORKSPACE_RELAY |
| 39 | ) |
| 40 | |
| 41 | |
| 42 | def test_status_workspace_does_not_imply_ok_on_green_single_repo(tmp_path: Path) -> None: |
| 43 | """S9: single-repo status green must not imply workspace.ok when relay stale.""" |
| 44 | from tests.support import run_shim, seed_git_repo |
| 45 | from cli.version_lock import write_version_lock |
| 46 | from cli.footprint import resolve_footprint |
| 47 | from adapters.config import load_config |
| 48 | |
| 49 | fx = build_two_repo_constellation(tmp_path, stale_relay=True) |
| 50 | seed_git_repo(fx["scooling"]) |
| 51 | # Minimal lock so status can run without config error |
| 52 | cfg = load_config(fx["scooling"] / ".overseer" / "config.yaml") |
| 53 | # status without --workspace should not force workspace failure into overall claim |
| 54 | plain = run_shim("ok", ["status", "--json"], cwd=fx["scooling"]) |
| 55 | assert plain.exit_code == 0 |
| 56 | plain_payload = json.loads(plain.stdout) |
| 57 | assert "workspace" not in plain_payload or plain_payload.get("workspace") is None |
| 58 | |
| 59 | ws = run_shim("ok", ["status", "--workspace", "--json"], cwd=fx["scooling"]) |
| 60 | ws_payload = json.loads(ws.stdout) |
| 61 | assert ws_payload["workspace"]["ok"] is False |
| 62 | # Without --exit-code, process exit stays 0 even when workspace.ok false |
| 63 | assert ws.exit_code == 0 |
| 64 | |
| 65 | ws_exit = run_shim( |
| 66 | "ok", ["status", "--workspace", "--exit-code", "--json"], cwd=fx["scooling"] |
| 67 | ) |
| 68 | payload = json.loads(ws_exit.stdout) |
| 69 | assert payload["workspace"]["ok"] is False |
| 70 | # Precedence 2 > 6 > 35 > 3 > 0 — lock/substrate may win over 35 on bare fixtures |
| 71 | assert ws_exit.exit_code in {2, 6, 35} |
| 72 | |
| 73 | |
| 74 | def test_doctor_board_name_violation(tmp_path: Path) -> None: |
| 75 | from tests.support import run_shim |
| 76 | |
| 77 | fx = build_two_repo_constellation(tmp_path, bare_names_on_relay=True) |
| 78 | result = run_shim("ok", ["workspace", "doctor", "--json"], cwd=fx["scooling"]) |
| 79 | assert result.exit_code == 0 |
| 80 | payload = json.loads(result.stdout) |
| 81 | codes = [f["code"] for f in payload["findings"]] |
| 82 | assert "board_name_violation" in codes |
| 83 | |
| 84 | |
| 85 | def test_muse_only_member_skips_git(tmp_path: Path) -> None: |
| 86 | from tools.workspace.doctor import run_doctor |
| 87 | from adapters.config import load_config |
| 88 | |
| 89 | fx = build_two_repo_constellation(tmp_path, with_musehub=True) |
| 90 | cfg = load_config(fx["scooling"] / ".overseer" / "config.yaml") |
| 91 | report = run_doctor(cfg, fx["scooling"], invoke_git=True) |
| 92 | codes = [f.code for f in report.findings] |
| 93 | assert "muse_only_skip_git" in codes |
| 94 | |
| 95 | |
| 96 | def test_check_next_not_configured_is_config_exit(tmp_path: Path) -> None: |
| 97 | from tests.support import run_cli, write_config |
| 98 | |
| 99 | write_config(tmp_path, "config-git-only.yaml") |
| 100 | (tmp_path / "docs").mkdir(exist_ok=True) |
| 101 | code = run_cli(["workspace", "check-next"], cwd=tmp_path) |
| 102 | assert code == 2 |
File History
1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
1 day ago