diff options
Diffstat (limited to 'tests/test_update_kernel_cachyos.py')
| -rw-r--r-- | tests/test_update_kernel_cachyos.py | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/tests/test_update_kernel_cachyos.py b/tests/test_update_kernel_cachyos.py new file mode 100644 index 0000000..052f8ae --- /dev/null +++ b/tests/test_update_kernel_cachyos.py @@ -0,0 +1,177 @@ +import importlib.util +import io +import json +import tarfile +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +SCRIPTS = Path(__file__).resolve().parents[1] / "scripts" + + +def load(name, filename): + spec = importlib.util.spec_from_file_location(name, SCRIPTS / filename) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +updater = load("update_kernel_cachyos", "update-kernel-cachyos.py") +checker = load("check_versions_revisions", "check-versions.py") +TEMPLATE = '''MY_RELEASE="${PV}-1" +SLOT="0" +src_unpack() { + case ${archive} in + "${MY_KERNEL}") expected=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ;; + "${MY_HEADERS}") expected=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ;; + esac +} +''' + + +class KernelUpdates(unittest.TestCase): + def setUp(self): + self.temporary = tempfile.TemporaryDirectory() + self.addCleanup(self.temporary.cleanup) + self.root = Path(self.temporary.name) + self.package = self.root / "packages/sys-kernel/kernel-cachyos" + self.package.mkdir(parents=True) + self.recipe("7.2.9", TEMPLATE) + + def recipe(self, version, text): + path = self.package / f"kernel-cachyos-{version}.exheres-0" + path.write_text(text) + return path + + def run_update(self, version, error=None): + def download(url, destination): + if error == "download" and "headers" in url: + raise updater.UpdateError("no matching headers") + destination.write_bytes(b"archive") + return "a" * 64 if "headers" not in url else "b" * 64 + + def inspect(_archive, name, _release): + if error == "inspect" and name == "linux-cachyos-headers": + raise updater.UpdateError("mismatched headers") + + with patch.object(updater, "latest_aur_release", return_value=version), \ + patch.object(updater, "download", side_effect=download), \ + patch.object(updater, "inspect_archive", side_effect=inspect): + updater.update(self.root) + + def names(self): + return sorted(path.name for path in self.package.iterdir()) + + def test_same_pv_replaces_previous_recipe(self): + self.run_update("7.2.9-2") + self.assertEqual(self.names(), ["kernel-cachyos-7.2.9-r1.exheres-0"]) + revised = (self.package / "kernel-cachyos-7.2.9-r1.exheres-0").read_text() + self.assertIn('MY_RELEASE="${PV}-2"', revised) + self.assertIn('SLOT="0"', revised) + self.assertIn("a" * 64, revised) + self.assertIn("b" * 64, revised) + found, problems = checker.recipes(self.root) + self.assertEqual(problems, []) + self.assertEqual(found["sys-kernel/kernel-cachyos"], "7.2.9-r1") + self.assertEqual(checker.kernel_release(self.root, "7.2.9-r1"), "7.2.9-2") + + def test_next_pkgrel_and_new_version(self): + self.run_update("7.2.9-2") + self.run_update("7.2.9-3") + self.assertEqual(self.names(), ["kernel-cachyos-7.2.9-r2.exheres-0"]) + self.run_update("7.3.0-1") + self.assertEqual(self.names(), ["kernel-cachyos-7.3.0.exheres-0"]) + + def test_noop_and_failure_preserve_recipes(self): + before = self.names() + self.run_update("7.2.9-1") + self.assertEqual(self.names(), before) + for version, error in (("7.2.9-3", None), ("7.2.9-2", "download"), ("7.2.9-2", "inspect")): + with self.subTest(version=version, error=error), self.assertRaises(updater.UpdateError): + self.run_update(version, error) + self.assertEqual(self.names(), before) + + def test_duplicate_and_legacy_slot_are_rejected(self): + old = self.recipe("7.2.8", TEMPLATE) + found, problems = checker.recipes(self.root) + self.assertIn("keep only one kernel-cachyos recipe", problems) + self.assertIn("sys-kernel/kernel-cachyos", found) + with patch.object(updater, "latest_aur_release") as aur, self.assertRaises(updater.UpdateError): + updater.update(self.root) + aur.assert_not_called() + old.unlink() + current = self.package / "kernel-cachyos-7.2.9.exheres-0" + current.write_text(TEMPLATE.replace('SLOT="0"', 'SLOT="${PV}"')) + with patch.object(updater, "latest_aur_release") as aur, self.assertRaises(updater.UpdateError): + updater.update(self.root) + aur.assert_not_called() + self.assertEqual(self.names(), ["kernel-cachyos-7.2.9.exheres-0"]) + + def test_bad_aur_response_preserves_recipes(self): + before = self.names() + for status in (403, 429): + with self.subTest(status=status): + from urllib.error import HTTPError + with patch.object(updater.urllib.request, "urlopen", side_effect=HTTPError(updater.AUR_URL, status, "blocked", {}, None)): + with self.assertRaises(updater.UpdateError): + updater.update(self.root) + self.assertEqual(self.names(), before) + + def test_aur_payload(self): + payload = json.dumps({"resultcount": 1, "results": [{"Name": "linux-cachyos", "Version": "7.2.9-2"}]}).encode() + with patch.object(updater.urllib.request, "urlopen", return_value=io.BytesIO(payload)): + self.assertEqual(updater.latest_aur_release(), "7.2.9-2") + + def test_archive_metadata_and_paths(self): + def archive(name, unsafe=False): + path = self.root / f"{name}.tar.zst" + module = "usr/lib/modules/7.2.9-2-cachyos" + items = { + ".PKGINFO": f"pkgname = {name}\npkgver = 7.2.9-2\narch = x86_64_v3\n".encode(), + } + if name == "linux-cachyos": + items.update({f"{module}/vmlinuz": b"kernel", f"{module}/kernel/example.ko.zst": b"module"}) + else: + items.update({f"{module}/build/{part}": b"header" for part in (".config", "Module.symvers", "System.map")}) + items[f"{module}/vdso/vdso64.so"] = b"vdso" + if unsafe: + items["../outside"] = b"bad" + raw = io.BytesIO() + with tarfile.open(fileobj=raw, mode="w") as tar: + for item, data in items.items(): + info = tarfile.TarInfo(item) + info.size = len(data) + tar.addfile(info, io.BytesIO(data)) + import subprocess + path.write_bytes(subprocess.run(["zstd", "-cq"], input=raw.getvalue(), stdout=subprocess.PIPE, check=True).stdout) + return path + + updater.inspect_archive(archive("linux-cachyos"), "linux-cachyos", "7.2.9-2") + updater.inspect_archive(archive("linux-cachyos-headers"), "linux-cachyos-headers", "7.2.9-2") + with self.assertRaises(updater.UpdateError): + updater.inspect_archive(archive("linux-cachyos", unsafe=True), "linux-cachyos", "7.2.9-2") + with self.assertRaises(updater.UpdateError): + updater.inspect_archive(archive("linux-cachyos"), "linux-cachyos", "7.2.9-3") + + def test_directory_cannot_stand_in_for_required_file(self): + archive = self.root / "invalid.tar.zst" + module = "usr/lib/modules/7.2.9-2-cachyos" + raw = io.BytesIO() + with tarfile.open(fileobj=raw, mode="w") as tar: + metadata = b"pkgname = linux-cachyos\npkgver = 7.2.9-2\narch = x86_64_v3\n" + info = tarfile.TarInfo(".PKGINFO") + info.size = len(metadata) + tar.addfile(info, io.BytesIO(metadata)) + for name in (f"{module}/vmlinuz", f"{module}/kernel/example"): + info = tarfile.TarInfo(name) + info.type = tarfile.DIRTYPE + tar.addfile(info) + import subprocess + archive.write_bytes(subprocess.run(["zstd", "-cq"], input=raw.getvalue(), stdout=subprocess.PIPE, check=True).stdout) + with self.assertRaises(updater.UpdateError): + updater.inspect_archive(archive, "linux-cachyos", "7.2.9-2") + + +if __name__ == "__main__": + unittest.main() |
