157 lines
4.3 KiB
Python
157 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from scripts.generate_history import load_release_statuses, release_history
|
|
from scripts.release_lib import ReleaseToolError
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import tempfile
|
|
|
|
|
|
def gitea_release(tag: str, *, prerelease: bool) -> dict[str, object]:
|
|
return {
|
|
"id": 42,
|
|
"tag_name": tag,
|
|
"name": f"Release {tag}",
|
|
"draft": False,
|
|
"prerelease": prerelease,
|
|
"published_at": "2026-09-08T12:00:00Z",
|
|
"html_url": f"https://gitea.example.test/owner/project/releases/tag/{tag}",
|
|
"assets": [
|
|
{
|
|
"name": "manifest.json",
|
|
"browser_download_url": (
|
|
f"https://gitea.example.test/owner/project/releases/download/"
|
|
f"{tag}/manifest.json"
|
|
),
|
|
},
|
|
{
|
|
"name": "manifest.json.sig",
|
|
"browser_download_url": (
|
|
f"https://gitea.example.test/owner/project/releases/download/"
|
|
f"{tag}/manifest.json.sig"
|
|
),
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
class ReleaseHistoryTests(unittest.TestCase):
|
|
def test_history_uses_only_installable_immutable_releases(self) -> None:
|
|
stable = gitea_release("v1.8.0", prerelease=False)
|
|
beta = gitea_release("v1.9.0-beta.2", prerelease=True)
|
|
wrong_flag = gitea_release("v2.0.0-beta.1", prerelease=False)
|
|
draft = gitea_release("v2.0.0", prerelease=False)
|
|
draft["draft"] = True
|
|
|
|
history = release_history(
|
|
[stable, wrong_flag, draft, beta],
|
|
"2026-09-08T12:01:00Z",
|
|
)
|
|
|
|
releases = history["releases"]
|
|
assert isinstance(releases, list)
|
|
self.assertEqual(
|
|
[release["version"] for release in releases],
|
|
["1.9.0-beta.2", "1.8.0"],
|
|
)
|
|
self.assertEqual(releases[0]["channel"], "prerelease")
|
|
self.assertEqual(releases[1]["channel"], "stable")
|
|
self.assertTrue(releases[0]["manifest_url"].endswith("/manifest.json"))
|
|
|
|
def test_history_rejects_an_invalid_generation_timestamp(self) -> None:
|
|
with self.assertRaisesRegex(ReleaseToolError, "timestamp"):
|
|
release_history([], "today")
|
|
|
|
def test_history_applies_signed_release_status_overrides(self) -> None:
|
|
history = release_history(
|
|
[gitea_release("v1.9.0-beta.2", prerelease=True)],
|
|
"2026-09-08T12:01:00Z",
|
|
{"v1.9.0-beta.2": "withdrawn"},
|
|
)
|
|
|
|
releases = history["releases"]
|
|
assert isinstance(releases, list)
|
|
self.assertEqual(releases[0]["status"], "withdrawn")
|
|
self.assertEqual(
|
|
releases[0]["compatibility"],
|
|
{"config_schema": 1, "minimum_config_schema": 1},
|
|
)
|
|
|
|
def test_history_supports_explicit_config_compatibility(self) -> None:
|
|
history = release_history(
|
|
[gitea_release("v2.0.0", prerelease=False)],
|
|
"2026-09-08T12:01:00Z",
|
|
{
|
|
"v2.0.0": {
|
|
"status": "active",
|
|
"config_schema": 3,
|
|
"minimum_config_schema": 2,
|
|
}
|
|
},
|
|
)
|
|
|
|
releases = history["releases"]
|
|
assert isinstance(releases, list)
|
|
self.assertEqual(
|
|
releases[0]["compatibility"],
|
|
{"config_schema": 3, "minimum_config_schema": 2},
|
|
)
|
|
|
|
def test_status_file_rejects_unknown_fields_and_unsafe_schema_ranges(self) -> None:
|
|
with tempfile.TemporaryDirectory() as temporary:
|
|
path = Path(temporary) / "statuses.json"
|
|
path.write_text(
|
|
json.dumps(
|
|
{
|
|
"schema": 1,
|
|
"releases": {
|
|
"v2.0.0": {
|
|
"status": "active",
|
|
"config_schema": 1,
|
|
"minimum_config_schema": 2,
|
|
}
|
|
},
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
with self.assertRaisesRegex(ReleaseToolError, "exceeds"):
|
|
load_release_statuses(path)
|
|
path.write_text(
|
|
'{"schema":1,"releases":{"v2.0.0":{"status":"active","note":"x"}}}',
|
|
encoding="utf-8",
|
|
)
|
|
with self.assertRaisesRegex(ReleaseToolError, "unknown"):
|
|
load_release_statuses(path)
|
|
|
|
def test_history_rejects_an_unknown_status(self) -> None:
|
|
with self.assertRaisesRegex(ReleaseToolError, "invalid status"):
|
|
release_history(
|
|
[gitea_release("v1.8.0", prerelease=False)],
|
|
"2026-09-08T12:01:00Z",
|
|
{"v1.8.0": "broken"},
|
|
)
|
|
|
|
def test_history_rejects_status_override_for_a_missing_release(self) -> None:
|
|
with self.assertRaisesRegex(ReleaseToolError, "do not match"):
|
|
release_history(
|
|
[gitea_release("v1.8.0", prerelease=False)],
|
|
"2026-09-08T12:01:00Z",
|
|
{"v1.9.0-beta.1": "withdrawn"},
|
|
)
|
|
|
|
def test_history_rejects_duplicate_release_tags(self) -> None:
|
|
release = gitea_release("v1.8.0", prerelease=False)
|
|
with self.assertRaisesRegex(ReleaseToolError, "duplicate"):
|
|
release_history(
|
|
[release, dict(release)],
|
|
"2026-09-08T12:01:00Z",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|