import json import tempfile from pathlib import Path from unittest.mock import patch from django.core.management import call_command from django.test import TestCase, override_settings from django.utils import timezone from workflows.backup_ops import latest_backup_health_snapshot class BackupReliabilityTests(TestCase): @override_settings(BACKUP_OUTPUT_DIR=tempfile.gettempdir()) def test_latest_backup_health_reports_missing_when_no_bundle_exists(self): with tempfile.TemporaryDirectory() as tmpdir: with override_settings(BACKUP_OUTPUT_DIR=tmpdir): snapshot = latest_backup_health_snapshot() self.assertEqual(snapshot['status'], 'missing') self.assertTrue(snapshot['is_stale']) def test_latest_backup_health_reports_stale_when_verification_is_old(self): with tempfile.TemporaryDirectory() as tmpdir: backup_dir = Path(tmpdir) / 'backup_20260326_010101' backup_dir.mkdir(parents=True) (backup_dir / 'db.dump').write_text('db', encoding='utf-8') (backup_dir / 'media.tar.gz').write_text('media', encoding='utf-8') (backup_dir / 'backup_meta.json').write_text( json.dumps( { 'created_at': timezone.now().isoformat(), 'verify_status': 'verified', 'verified_at': (timezone.now() - timezone.timedelta(hours=72)).isoformat(), } ), encoding='utf-8', ) with override_settings(BACKUP_OUTPUT_DIR=tmpdir): snapshot = latest_backup_health_snapshot(stale_after_hours=48) self.assertEqual(snapshot['status'], 'stale') self.assertEqual(snapshot['bundle_name'], 'backup_20260326_010101') @patch('workflows.management.commands.verify_latest_backup.verify_backup_bundle') @patch('workflows.management.commands.verify_latest_backup.list_backup_bundles') def test_verify_latest_backup_command_uses_existing_latest_bundle(self, list_bundles, verify_bundle): list_bundles.return_value = [{'name': 'backup_20260326_020202'}] verify_bundle.return_value = {'name': 'backup_20260326_020202', 'summary': 'ok'} call_command('verify_latest_backup') verify_bundle.assert_called_once_with('backup_20260326_020202') @patch('workflows.management.commands.verify_latest_backup.verify_backup_bundle') @patch('workflows.management.commands.verify_latest_backup.create_backup_bundle') @patch('workflows.management.commands.verify_latest_backup.list_backup_bundles') def test_verify_latest_backup_command_can_create_when_missing(self, list_bundles, create_bundle, verify_bundle): list_bundles.return_value = [] create_bundle.return_value = {'name': 'backup_20260326_030303'} verify_bundle.return_value = {'name': 'backup_20260326_030303', 'summary': 'ok'} call_command('verify_latest_backup', create_if_missing=True) create_bundle.assert_called_once() verify_bundle.assert_called_once_with('backup_20260326_030303')