mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-13 15:51:39 +00:00
bd6f77e093
Tighten v5-to-v6 upgrade safety, release installability, provider MSP mode handling, AI cost accounting, metrics flushing, and frontend guardrails for the v6.0.0 GA candidate.
152 lines
6.4 KiB
Python
152 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Unit tests for shared release-promotion metadata resolution."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
import unittest
|
|
|
|
import resolve_release_promotion as resolver
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
class ResolveReleasePromotionTest(unittest.TestCase):
|
|
def test_dev_prerelease_uses_prerelease_path(self) -> None:
|
|
metadata = resolver.resolve_metadata(
|
|
version="6.0.0-dev",
|
|
promoted_from_tag_input="",
|
|
rollback_version_input="5.1.14",
|
|
ga_date_input="",
|
|
v5_eos_date_input="",
|
|
hotfix_exception=False,
|
|
hotfix_reason_input="",
|
|
release_notes_input="",
|
|
tag_exists_fn=lambda tag: tag == "v5.1.14",
|
|
)
|
|
self.assertEqual(metadata["rollback_tag"], "v5.1.14")
|
|
self.assertEqual(metadata["promoted_from_tag"], "")
|
|
self.assertEqual(metadata["soak_hours"], "")
|
|
|
|
def test_prerelease_requires_explicit_stable_rollback(self) -> None:
|
|
metadata = resolver.resolve_metadata(
|
|
version="6.0.0-rc.2",
|
|
promoted_from_tag_input="",
|
|
rollback_version_input="5.1.14",
|
|
ga_date_input="",
|
|
v5_eos_date_input="",
|
|
hotfix_exception=False,
|
|
hotfix_reason_input="",
|
|
release_notes_input="",
|
|
tag_exists_fn=lambda tag: tag == "v5.1.14",
|
|
)
|
|
self.assertEqual(metadata["rollback_tag"], "v5.1.14")
|
|
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v5.1.14")
|
|
self.assertEqual(metadata["promoted_from_tag"], "")
|
|
self.assertEqual(metadata["soak_hours"], "")
|
|
|
|
def test_stable_requires_matching_promoted_rc_and_soak(self) -> None:
|
|
metadata = resolver.resolve_metadata(
|
|
version="6.0.0",
|
|
promoted_from_tag_input="6.0.0-rc.2",
|
|
rollback_version_input="5.1.14",
|
|
ga_date_input="2026-03-20",
|
|
v5_eos_date_input="2026-06-18",
|
|
hotfix_exception=False,
|
|
hotfix_reason_input="",
|
|
release_notes_input="maintenance-only support 2026-03-20 2026-06-18",
|
|
tag_exists_fn=lambda tag: tag in {"v6.0.0-rc.2", "v5.1.14"},
|
|
tag_commit_fn=lambda tag: "abc123",
|
|
head_descends_from_fn=lambda commit: commit == "abc123",
|
|
tag_created_unix_fn=lambda tag: 100,
|
|
now_unix_fn=lambda: 100 + (73 * 3600),
|
|
)
|
|
self.assertEqual(metadata["promoted_from_tag"], "v6.0.0-rc.2")
|
|
self.assertEqual(metadata["soak_hours"], "73")
|
|
|
|
def test_stable_requires_release_notes_notice_when_supplied(self) -> None:
|
|
with self.assertRaisesRegex(
|
|
ValueError,
|
|
"release_notes must include the Pulse v5 maintenance-only support notice",
|
|
):
|
|
resolver.resolve_metadata(
|
|
version="6.0.0",
|
|
promoted_from_tag_input="6.0.0-rc.2",
|
|
rollback_version_input="5.1.14",
|
|
ga_date_input="2026-03-20",
|
|
v5_eos_date_input="2026-06-18",
|
|
hotfix_exception=False,
|
|
hotfix_reason_input="",
|
|
release_notes_input="missing notice 2026-03-20 2026-06-18",
|
|
tag_exists_fn=lambda tag: True,
|
|
tag_commit_fn=lambda tag: "abc123",
|
|
head_descends_from_fn=lambda commit: True,
|
|
tag_created_unix_fn=lambda tag: 100,
|
|
now_unix_fn=lambda: 100 + (73 * 3600),
|
|
)
|
|
|
|
def test_current_stable_v6_packet_resolves_with_publish_dates(self) -> None:
|
|
self.assertEqual((REPO_ROOT / "VERSION").read_text(encoding="utf-8").strip(), "6.0.0")
|
|
release_notes = (REPO_ROOT / "docs/releases/RELEASE_NOTES_v6.md").read_text(encoding="utf-8")
|
|
metadata = resolver.resolve_metadata(
|
|
version="6.0.0",
|
|
promoted_from_tag_input="v6.0.0-rc.6",
|
|
rollback_version_input="v5.1.34",
|
|
ga_date_input="2026-06-04",
|
|
v5_eos_date_input="2026-09-02",
|
|
hotfix_exception=False,
|
|
hotfix_reason_input="",
|
|
release_notes_input=release_notes,
|
|
tag_exists_fn=lambda tag: tag in {"v6.0.0-rc.6", "v5.1.34"},
|
|
tag_commit_fn=lambda tag: "rc6-commit",
|
|
head_descends_from_fn=lambda commit: commit == "rc6-commit",
|
|
tag_created_unix_fn=lambda tag: 100,
|
|
now_unix_fn=lambda: 100 + (163 * 3600),
|
|
)
|
|
|
|
self.assertEqual(metadata["promoted_from_tag"], "v6.0.0-rc.6")
|
|
self.assertEqual(metadata["rollback_tag"], "v5.1.34")
|
|
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v5.1.34")
|
|
self.assertEqual(metadata["ga_date"], "2026-06-04")
|
|
self.assertEqual(metadata["v5_eos_date"], "2026-09-02")
|
|
|
|
def test_stable_hotfix_requires_reason(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "hotfix_reason is required"):
|
|
resolver.resolve_metadata(
|
|
version="6.0.1",
|
|
promoted_from_tag_input="6.0.1-rc.1",
|
|
rollback_version_input="6.0.0",
|
|
ga_date_input="",
|
|
v5_eos_date_input="",
|
|
hotfix_exception=True,
|
|
hotfix_reason_input="",
|
|
release_notes_input="",
|
|
tag_exists_fn=lambda tag: True,
|
|
tag_commit_fn=lambda tag: "abc123",
|
|
head_descends_from_fn=lambda commit: True,
|
|
tag_created_unix_fn=lambda tag: 100,
|
|
now_unix_fn=lambda: 100 + (2 * 3600),
|
|
)
|
|
|
|
def test_stable_rejects_short_soak_without_hotfix(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "hours of prerelease soak"):
|
|
resolver.resolve_metadata(
|
|
version="6.0.1",
|
|
promoted_from_tag_input="6.0.1-rc.1",
|
|
rollback_version_input="6.0.0",
|
|
ga_date_input="",
|
|
v5_eos_date_input="",
|
|
hotfix_exception=False,
|
|
hotfix_reason_input="",
|
|
release_notes_input="",
|
|
tag_exists_fn=lambda tag: True,
|
|
tag_commit_fn=lambda tag: "abc123",
|
|
head_descends_from_fn=lambda commit: True,
|
|
tag_created_unix_fn=lambda tag: 100,
|
|
now_unix_fn=lambda: 100 + (2 * 3600),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|