import hashlib import importlib.util import json from pathlib import Path import subprocess import tarfile import tempfile import unittest ROOT = Path(__file__).resolve().parents[1] spec = importlib.util.spec_from_file_location("package_source", ROOT / "deploy" / "package_source.py") package_source = importlib.util.module_from_spec(spec) spec.loader.exec_module(package_source) def run(repository: Path, *arguments: str) -> str: result = subprocess.run( ["git", "-C", str(repository), *arguments], check=True, capture_output=True, text=True, ) return result.stdout.strip() class PackageSourceTests(unittest.TestCase): def repository(self, root: Path, dotnet_version: str = "1.2.3", web_version: str = "1.2.3") -> tuple[Path, str]: repository = root / "repository" (repository / "web").mkdir(parents=True) run(repository, "init") run(repository, "config", "user.name", "GuestOps Test") run(repository, "config", "user.email", "guestops@example.invalid") run(repository, "config", "core.autocrlf", "false") (repository / "Directory.Build.props").write_text( f"{dotnet_version}\n", encoding="utf-8", ) (repository / "web" / "package.json").write_text( json.dumps({"version": web_version}) + "\n", encoding="utf-8" ) (repository / "application.txt").write_text("committed application\n", encoding="utf-8") run(repository, "add", ".") run(repository, "commit", "-m", "fixture") return repository, run(repository, "rev-parse", "HEAD") def test_packages_only_the_selected_commit_and_records_identity(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) repository, commit = self.repository(root) (repository / "application.txt").write_text("uncommitted change\n", encoding="utf-8") archive, record_path, record = package_source.build_package(repository, commit, root / "output") self.assertEqual(record["commit"], commit) self.assertEqual(record["version"], "1.2.3") self.assertEqual(record["artifact"]["sha256"], hashlib.sha256(archive.read_bytes()).hexdigest()) self.assertEqual(json.loads(record_path.read_text(encoding="utf-8")), record) with tarfile.open(archive, "r:gz") as package: member = package.extractfile("GuestOps-1.2.3/application.txt") self.assertIsNotNone(member) self.assertEqual(member.read().decode("utf-8").strip(), "committed application") def test_same_commit_produces_identical_package(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) repository, commit = self.repository(root) first, _, _ = package_source.build_package(repository, commit, root / "first") second, _, _ = package_source.build_package(repository, commit, root / "second") self.assertEqual(first.read_bytes(), second.read_bytes()) def test_rejects_mismatched_versions_and_existing_output(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) repository, commit = self.repository(root, web_version="1.2.4") with self.assertRaisesRegex(ValueError, "versions differ"): package_source.build_package(repository, commit, root / "output") with tempfile.TemporaryDirectory() as directory: root = Path(directory) repository, commit = self.repository(root) package_source.build_package(repository, commit, root / "output") with self.assertRaisesRegex(ValueError, "not overwritten"): package_source.build_package(repository, commit, root / "output") if __name__ == "__main__": unittest.main()