import tempfile from pathlib import Path from media_library_viewer_api.services.settings_store import SettingsStore def test_backup_schema_created(): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "test_settings.sqlite" store = SettingsStore(db_path) store.init_schema() with store.connect() as conn: tables = conn.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'backup_%'" ).fetchall() table_names = [t[0] for t in tables] assert "backup_jobs" in table_names assert "backup_runs" in table_names assert "backup_alerts" in table_names def test_backup_report_model(): from media_library_viewer_api.models.backups import BackupReportRequest report = BackupReportRequest( name="test-backup", started_at="2026-05-11T02:00:00Z", status="success", ended_at="2026-05-11T02:15:00Z", duration_ms=900000, bytes_transferred=1024, ) assert report.name == "test-backup" assert report.status == "success" def test_create_job_and_run(): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "test_settings.sqlite" store = SettingsStore(db_path) store.init_schema() job = store.upsert_backup_job({ "name": "test-job", "source": "server-a:/data", "target": "server-b:/backups", "schedule_interval_seconds": 86400, }) assert job["name"] == "test-job" run = store.create_backup_run({ "job_id": job["id"], "started_at": 1715392800, "status": "success", "ended_at": 1715393700, "duration_ms": 900000, "bytes_transferred": 1024, }) assert run["job_id"] == job["id"] assert run["status"] == "success" def test_api_key_auth(): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "test_settings.sqlite" store = SettingsStore(db_path) store.init_schema() from fastapi import HTTPException from media_library_viewer_api.auth import get_api_key, require_api_key from media_library_viewer_api.services import settings_store # Monkey-patch the global store for this test original_store = settings_store._store settings_store._store = store # Reset the cached API key import media_library_viewer_api.auth as auth_module auth_module._API_KEY = None try: # Should generate and return an API key api_key = get_api_key() assert api_key assert len(api_key) > 0 # Should raise 401 without key try: require_api_key("") assert False, "Should have raised" except HTTPException as e: assert e.status_code == 401 # Should raise 401 with wrong key try: require_api_key("Bearer wrong-key") assert False, "Should have raised" except HTTPException as e: assert e.status_code == 401 # Should succeed with correct key result = require_api_key(f"Bearer {api_key}") assert result == f"Bearer {api_key}" finally: settings_store._store = original_store auth_module._API_KEY = None def test_alert_failed_status(): from media_library_viewer_api.services.backup_alert_engine import generate_alerts_for_run run = { "id": "run-1", "job_id": "job-1", "status": "failure", "bytes_transferred": 0, "duration_ms": 1000, "started_at": 1715392800, } alerts = generate_alerts_for_run(run, [], None) assert len(alerts) == 1 assert alerts[0]["alert_type"] == "failed_status" assert alerts[0]["severity"] == "critical" def test_backup_poller_detects_missed_schedule(): import tempfile from pathlib import Path from media_library_viewer_api.services.backup_poller import BackupAlertPoller from media_library_viewer_api.services.settings_store import SettingsStore with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "test_settings.sqlite" store = SettingsStore(db_path) store.init_schema() import time # Create job with created_at in the past so it's already overdue past_time = int(time.time()) - 200 job = store.upsert_backup_job({ "name": "old-job", "schedule_interval_seconds": 60, }) # Override created_at to be in the past so missed schedule fires with store.connect() as conn: conn.execute("UPDATE backup_jobs SET created_at = ? WHERE id = ?", (past_time, job["id"])) poller = BackupAlertPoller() poller._run_cycle(store) alerts = store.list_backup_alerts(job_id=job["id"]) assert len(alerts) == 1 assert alerts[0]["alert_type"] == "missed_schedule"