import importlib.util import json from pathlib import Path import tempfile import unittest from unittest.mock import patch ROOT = Path(__file__).resolve().parents[1] spec = importlib.util.spec_from_file_location( 'release_manifest', ROOT / 'scripts/release-manifest.py' ) release = importlib.util.module_from_spec(spec) spec.loader.exec_module(release) class ReleaseTests(unittest.TestCase): def test_source_id_is_stable(self): self.assertEqual(release.source_id(), release.source_id()) self.assertTrue(release.source_id().startswith('csr-')) self.assertEqual(set(release.COMPONENTS.values()), {'intake-gui', 'pc-intake'}) def make_release(self, root): for name in release.COMPONENTS.values(): binary = root / name binary.write_bytes(name.encode()) binary.chmod(0o755) manifest = { 'schema_version': 1, 'build_id': 'csr-test', 'binaries': { name: {'sha256': release.digest(root / name)} for name in release.COMPONENTS.values() }, } (root / 'release.json').write_text(json.dumps(manifest)) def test_release_rejects_stale_binary(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) self.make_release(root) (root / 'intake-gui').write_bytes(b'stale binary') with self.assertRaisesRegex(ValueError, 'hash mismatch'): release.verify(root) def test_complete_release_is_verified(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) self.make_release(root) with patch.object(release.subprocess, 'check_output', return_value='GUI csr-test'): release.verify(root) (root / 'pc-intake').chmod(0o644) with self.assertRaisesRegex(ValueError, 'not executable'): release.verify(root) def test_release_requires_exact_component_set(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) self.make_release(root) manifest = json.loads((root / 'release.json').read_text()) manifest['binaries'].pop('pc-intake') (root / 'release.json').write_text(json.dumps(manifest)) with self.assertRaisesRegex(ValueError, 'missing or unexpected'): release.verify(root) if __name__ == '__main__': unittest.main()