Files
RedBear-OS/local/scripts/tests/test_audit_patch_idempotency.py
T
vasilito ffbe098ef8 config: add tlc to redbear-mini and redbear-full; create recipe symlink
TLC (Twilight Commander) was missing from both ISO configs. Added
tlc = {} to [packages] in redbear-mini.toml and redbear-full.toml.
Created missing symlink: recipes/tui/tlc -> ../../local/recipes/tui/tlc.
2026-06-19 11:47:25 +03:00

104 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Smoke tests for audit-patch-idempotency.py.
Run with:
python3 -m unittest local/scripts/tests/test_audit_patch_idempotency.py
"""
import re
import sys
import unittest
from pathlib import Path
SCRIPTS_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(SCRIPTS_DIR))
import importlib.util # noqa: E402
_spec = importlib.util.spec_from_file_location(
"api", SCRIPTS_DIR / "audit-patch-idempotency.py"
)
assert _spec is not None and _spec.loader is not None
api = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(api)
class TestCollectPatches(unittest.TestCase):
"""The patch collector walks local/patches/<component>/NN-*.patch."""
def test_collect_real_patches(self):
# On the live tree, this should find at least 10 patches.
patches = list(api.collect_patches())
self.assertGreater(len(patches), 0)
# Every patch is a 2-tuple (component, Path).
for comp, p in patches:
self.assertIsInstance(comp, str)
self.assertTrue(p.exists())
def test_collect_filter_by_component(self):
# Should find the 3 libdrm patches.
patches = list(api.collect_patches(component_filter="libdrm"))
for _, name in patches:
self.assertIn("libdrm", str(name))
def test_collect_nonexistent_component(self):
patches = list(api.collect_patches(component_filter="does-not-exist-xyz"))
self.assertEqual(patches, [])
class TestPatchNameValidation(unittest.TestCase):
"""The regex accepts files matching NN-name.patch."""
def test_valid_patch_names(self):
# The collector uses PATCH_NAME_RE — verify it accepts real names.
names = [
"01-foo.patch", "02-bar.patch", "99-trailing-numbers.patch",
"10-multi-word-name-with-dashes.patch",
]
for n in names:
self.assertTrue(api.PATCH_NAME_RE.match(n),
f"should accept {n!r}")
def test_invalid_patch_names(self):
for n in ["foo.patch", "01-foo", "01-.patch", "foo-01-bar.patch"]:
self.assertFalse(api.PATCH_NAME_RE.match(n),
f"should reject {n!r}")
class TestJSONSchemaHonesty(unittest.TestCase):
"""--no-fetch must produce JSON with skipped entries and a clear message."""
def test_no_fetch_json_shape(self):
import json
import subprocess
proc = subprocess.run(
["python3", str(SCRIPTS_DIR / "audit-patch-idempotency.py"),
"--no-fetch", "--json"],
capture_output=True, text=True,
)
# With --no-fetch, every entry is skipped -> exit 2 (CI-safe).
self.assertEqual(proc.returncode, 2)
data = json.loads(proc.stdout)
self.assertIn("patches", data)
self.assertIn("total", data)
self.assertIn("errors", data)
self.assertIn("skipped", data)
# Every entry must be status=skipped.
for entry in data["patches"]:
self.assertEqual(entry["status"], "skipped")
self.assertEqual(data["skipped"], data["total"])
def test_no_fetch_text_honest_about_skipping(self):
import subprocess
proc = subprocess.run(
["python3", str(SCRIPTS_DIR / "audit-patch-idempotency.py"),
"--no-fetch"],
capture_output=True, text=True,
)
# Must NOT say "All N patches are idempotent" when none were
# actually audited.
self.assertIn("SKIPPED", proc.stdout)
self.assertIn("No audit was performed", proc.stdout)
if __name__ == "__main__":
unittest.main()