from __future__ import annotations import re import shutil import subprocess import unittest from pathlib import Path BACKUP_SCRIPT = Path(__file__).with_name("backup-vignette-db.ps1") class BackupVignetteDatabaseTest(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.source = BACKUP_SCRIPT.read_text(encoding="utf-8") def test_uses_custom_dump_and_verifies_toc_before_publish(self) -> None: dump_index = self.source.index("'pg_dump'") verify_index = self.source.index("'pg_restore', '--list'") publish_index = self.source.index( "Move-Item -LiteralPath $partialPath -Destination $finalPath" ) self.assertLess(dump_index, verify_index) self.assertLess(verify_index, publish_index) self.assertIn("'--format=custom'", self.source) self.assertIn("'--no-owner'", self.source) self.assertIn("'--no-privileges'", self.source) def test_manifest_binds_dump_to_hash_and_container(self) -> None: for expected in ( "container_id = $containerId", "size_bytes = (Get-Item -LiteralPath $finalPath).Length", "sha256 = $sha256", "verified_with = 'pg_restore --list'", ): self.assertIn(expected, self.source) self.assertIn("Get-FileHash -LiteralPath $partialPath -Algorithm SHA256", self.source) def test_never_removes_database_container_or_volume(self) -> None: forbidden = ( r"(?im)^\s*(?:&\s*)?docker(?:\.exe)?\s+(?:container\s+)?rm\b", r"(?im)^\s*(?:&\s*)?docker(?:\.exe)?\s+volume\s+(?:rm|prune)\b", r"(?im)^\s*(?:&\s*)?docker(?:\.exe)?\s+compose\s+down\b", ) for pattern in forbidden: self.assertIsNone(re.search(pattern, self.source), pattern) self.assertIn("rm -f $containerTempPath", self.source) def test_windows_powershell_51_parser_accepts_script(self) -> None: powershell = shutil.which("powershell.exe") if powershell is None: self.skipTest("Windows PowerShell 5.1 is unavailable") escaped_path = str(BACKUP_SCRIPT.resolve()).replace("'", "''") command = ( "$tokens=$null; $errors=$null; " "[System.Management.Automation.Language.Parser]::ParseFile(" f"'{escaped_path}', [ref]$tokens, [ref]$errors) | Out-Null; " "if ($errors.Count -gt 0) { " "$errors | ForEach-Object { Write-Error $_.Message }; exit 1 }; exit 0" ) completed = subprocess.run( [powershell, "-NoProfile", "-Command", command], check=False, capture_output=True, text=True, encoding="utf-8", ) self.assertEqual( completed.returncode, 0, msg=f"stdout={completed.stdout}\nstderr={completed.stderr}", ) if __name__ == "__main__": unittest.main()