from __future__ import annotations import os import subprocess from pathlib import Path ROOT = Path(__file__).resolve().parents[3] COMMON = ROOT / "scripts" / "backup" / "common.sh" def test_latest_only_retention_uses_keep_last_one_and_explicit_password(tmp_path: Path) -> None: bin_dir = tmp_path / "bin" bin_dir.mkdir() event_log = tmp_path / "restic.args" restic = bin_dir / "restic" restic.write_text( '#!/bin/sh\nprintf "%s\\n" "$*" >> "$TEST_EVENT_LOG"\n', encoding="utf-8", ) restic.chmod(0o755) backup_base = tmp_path / "backup" password_file = backup_base / "scripts" / ".restic-password" password_file.parent.mkdir(parents=True) password_file.write_text("test-only\n", encoding="utf-8") env = os.environ.copy() env.update( { "BACKUP_BASE": str(backup_base), "RESTIC_PASSWORD_FILE": str(password_file), "PATH": f"{bin_dir}:{env['PATH']}", "TEST_EVENT_LOG": str(event_log), } ) subprocess.run( [ "bash", "-c", f'source "{COMMON}"; BACKUP_RETENTION_MODE=latest ' 'BACKUP_KEEP_LAST=1 cleanup_old_backups "$BACKUP_BASE/demo"', ], env=env, check=True, text=True, capture_output=True, ) args = event_log.read_text(encoding="utf-8") assert "forget --keep-last 1 --prune --password-file" in args def test_retention_rejects_invalid_keep_last_before_restic(tmp_path: Path) -> None: backup_base = tmp_path / "backup" env = os.environ.copy() env["BACKUP_BASE"] = str(backup_base) result = subprocess.run( [ "bash", "-c", f'source "{COMMON}"; BACKUP_RETENTION_MODE=latest ' 'BACKUP_KEEP_LAST=0 cleanup_old_backups "$BACKUP_BASE/demo"', ], env=env, text=True, capture_output=True, ) assert result.returncode == 64 assert "BACKUP_KEEP_LAST" in result.stdout def test_verify_backup_reads_the_requested_snapshot_before_repository_check( tmp_path: Path, ) -> None: bin_dir = tmp_path / "bin" bin_dir.mkdir() event_log = tmp_path / "restic.args" restic = bin_dir / "restic" restic.write_text( """#!/bin/sh printf '%s\n' "$*" >> "$TEST_EVENT_LOG" case " $* " in *" snapshots "*) printf '%s\n' '[{"short_id":"abcdef12"}]' ;; *" ls "*) printf '%s\n' '{"type":"file","path":"/backup/data.dump"}' ;; *" check "*) ;; esac """, encoding="utf-8", ) restic.chmod(0o755) backup_base = tmp_path / "backup" password_file = backup_base / "scripts" / ".restic-password" password_file.parent.mkdir(parents=True) password_file.write_text("test-only\n", encoding="utf-8") env = os.environ.copy() env.update( { "BACKUP_BASE": str(backup_base), "RESTIC_PASSWORD_FILE": str(password_file), "PATH": f"{bin_dir}:{env['PATH']}", "TEST_EVENT_LOG": str(event_log), } ) subprocess.run( ["bash", "-c", f'source "{COMMON}"; verify_backup /repo abcdef12'], env=env, check=True, text=True, capture_output=True, ) calls = event_log.read_text(encoding="utf-8") assert "snapshots abcdef12 --json" in calls assert "ls abcdef12 --json" in calls assert "check --read-data-subset=1%" in calls