test_publish_muse_release_prune.py
python
sha256:fc04e4cae9e1774d6a21b65c45daeed0e6787eb581d13aa1b03bfe9384a34226
Merge branch 'fix/two-column-scroll-layout' into dev
Human
8 days ago
| 1 | """Phase 2 of MuseHub issue #128 -- deploy/publish_muse_release.sh must use |
| 2 | prune_releases.py (PEP 440 precedence) instead of sort -V's lexical |
| 3 | comparison, for both the S3 cleanup and the server (SSM) cleanup blocks. |
| 4 | |
| 5 | Source-level assertions, matching this repo's existing convention in |
| 6 | test_deployment.py for validating deploy scripts without executing real AWS |
| 7 | calls -- live verification against the actual staging instance/S3 bucket is |
| 8 | Phase 3 (PRUNE_10), a deliberate, human-directed action, not something a test |
| 9 | suite should trigger. |
| 10 | """ |
| 11 | from __future__ import annotations |
| 12 | |
| 13 | from pathlib import Path |
| 14 | |
| 15 | _ROOT = Path(__file__).resolve().parents[1] |
| 16 | _PUBLISH_SH = _ROOT / "deploy" / "publish_muse_release.sh" |
| 17 | _SRC = _PUBLISH_SH.read_text() |
| 18 | |
| 19 | |
| 20 | def _executable_lines(src: str) -> str: |
| 21 | """Strip full-line comments -- isolates actual bash code from prose that |
| 22 | may legitimately mention "sort -V" while explaining why it was removed.""" |
| 23 | return "\n".join( |
| 24 | line for line in src.splitlines() if not line.strip().startswith("#") |
| 25 | ) |
| 26 | |
| 27 | |
| 28 | _CODE = _executable_lines(_SRC) |
| 29 | |
| 30 | |
| 31 | class TestPruneReleasesWiredIntoPublishScript: |
| 32 | def test_PRUNE_06_sort_dash_v_removed_entirely(self) -> None: |
| 33 | """sort -V's lexical comparison must not execute anywhere in the script. |
| 34 | |
| 35 | Explanatory comments are allowed to mention "sort -V" by name (e.g. |
| 36 | documenting why it was removed) -- this checks executable code only. |
| 37 | """ |
| 38 | assert "sort -V" not in _CODE |
| 39 | |
| 40 | def test_PRUNE_06b_s3_cleanup_calls_prune_releases_py(self) -> None: |
| 41 | """S3 cleanup must pipe candidate filenames through prune_releases.py.""" |
| 42 | assert "prune_releases.py" in _SRC |
| 43 | assert '--keep "$KEEP_RELEASES"' in _SRC |
| 44 | |
| 45 | def test_PRUNE_06c_s3_cleanup_still_greps_muse_tarball_pattern(self) -> None: |
| 46 | """The existing muse-*.tar.gz filter must survive the rewrite -- |
| 47 | prune_releases.py raises on unparseable names, so anything that |
| 48 | isn't a muse release tarball must never reach it.""" |
| 49 | assert "grep '^muse-.*\\.tar\\.gz$'" in _SRC |
| 50 | |
| 51 | def test_PRUNE_07_server_cleanup_has_no_sort_in_remote_command(self) -> None: |
| 52 | """The remote SSM command string must never invoke sort or awk-based |
| 53 | version comparison -- only prune_releases.py (run locally) decides |
| 54 | what's stale; the remote host receives an explicit rm list. |
| 55 | |
| 56 | Checks executable code only (comments may legitimately say "the |
| 57 | remote shell never sorts" while explaining the design).""" |
| 58 | # Isolate the server-cleanup section (list + rm), not the whole file, |
| 59 | # so an unrelated "sort" elsewhere in the script wouldn't false-pass. |
| 60 | start = _CODE.index("LIST_CMD_ID=") |
| 61 | end = _CODE.index("HTTP=$(curl") |
| 62 | server_section = _CODE[start:end] |
| 63 | assert "sort" not in server_section |
| 64 | assert "awk" not in server_section |
| 65 | |
| 66 | def test_PRUNE_07b_server_cleanup_computes_stale_set_locally(self) -> None: |
| 67 | """The stale set for the server must be computed via a local |
| 68 | prune_releases.py call against the SSM-fetched file listing, not |
| 69 | inside the remote SSM command string.""" |
| 70 | start = _CODE.index("LIST_CMD_ID=") |
| 71 | end = _CODE.index("HTTP=$(curl") |
| 72 | server_section = _CODE[start:end] |
| 73 | assert "prune_releases.py" in server_section |
| 74 | assert 'REMOTE_FILES' in server_section |
| 75 | |
| 76 | def test_PRUNE_07c_server_rm_command_targets_explicit_filenames(self) -> None: |
| 77 | """The rm sent to the remote host must be an explicit filename list, |
| 78 | not a re-derived sort/keep-N pipeline.""" |
| 79 | start = _CODE.index("LIST_CMD_ID=") |
| 80 | end = _CODE.index("HTTP=$(curl") |
| 81 | server_section = _CODE[start:end] |
| 82 | assert "rm -v" in server_section |
| 83 | |
| 84 | def test_script_dir_used_for_prune_releases_reference(self) -> None: |
| 85 | """prune_releases.py must be referenced via $SCRIPT_DIR, not a bare |
| 86 | relative path -- the script must work regardless of the caller's cwd.""" |
| 87 | assert '$SCRIPT_DIR/prune_releases.py' in _SRC |
| 88 | |
| 89 | def test_syntax_is_valid_bash(self) -> None: |
| 90 | """The script must still parse as valid bash after the rewrite.""" |
| 91 | import subprocess |
| 92 | |
| 93 | result = subprocess.run( |
| 94 | ["bash", "-n", str(_PUBLISH_SH)], |
| 95 | capture_output=True, |
| 96 | text=True, |
| 97 | ) |
| 98 | assert result.returncode == 0, result.stderr |
File History
1 commit
sha256:fc04e4cae9e1774d6a21b65c45daeed0e6787eb581d13aa1b03bfe9384a34226
Merge branch 'fix/two-column-scroll-layout' into dev
Human
8 days ago