nordabiz/tests/smoke/test_backup_health.py
Maciej Pienczyn a57187e05f
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
test: Add comprehensive testing infrastructure
- pytest framework with fixtures for auth (auth_client, admin_client)
- Unit tests for SearchService
- Integration tests for auth flow
- Security tests (OWASP Top 10: SQL injection, XSS, CSRF)
- Smoke tests for production health and backup monitoring
- E2E tests with Playwright (basic structure)
- DR tests for backup/restore procedures
- GitHub Actions CI/CD workflow (.github/workflows/test.yml)
- Coverage configuration (.coveragerc) with 80% minimum
- DR documentation and restore script

Staging environment: VM 248, staging.nordabiznes.pl

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 07:52:34 +01:00

133 lines
4.1 KiB
Python

"""
Smoke tests for backup health
==============================
Verify that backups are being created and are valid.
These tests require SSH access to production server.
Usage:
pytest tests/smoke/test_backup_health.py -v
"""
import os
import subprocess
from datetime import datetime, timedelta
import pytest
pytestmark = [pytest.mark.smoke, pytest.mark.dr]
# Production server
PROD_HOST = os.environ.get('PROD_HOST', 'maciejpi@10.22.68.249')
BACKUP_DIR = '/var/backups/nordabiz'
def ssh_command(cmd: str) -> tuple[int, str, str]:
"""Execute SSH command on production server."""
result = subprocess.run(
['ssh', PROD_HOST, cmd],
capture_output=True,
text=True,
timeout=30
)
return result.returncode, result.stdout, result.stderr
class TestBackupFreshness:
"""Tests for backup freshness."""
@pytest.mark.slow
def test_hourly_backup_exists(self):
"""Hourly backup from last 2 hours should exist."""
returncode, stdout, stderr = ssh_command(
f'ls -t {BACKUP_DIR}/hourly/ | head -1'
)
assert returncode == 0, f"SSH failed: {stderr}"
assert stdout.strip(), "No hourly backup found"
# Check file is recent
returncode, stdout, _ = ssh_command(
f'stat -c %Y {BACKUP_DIR}/hourly/$(ls -t {BACKUP_DIR}/hourly/ | head -1)'
)
if returncode == 0 and stdout.strip():
file_time = int(stdout.strip())
now = int(datetime.now().timestamp())
age_hours = (now - file_time) / 3600
assert age_hours < 2, f"Hourly backup is {age_hours:.1f} hours old (should be < 2)"
@pytest.mark.slow
def test_daily_backup_exists(self):
"""Daily backup from last 25 hours should exist."""
returncode, stdout, stderr = ssh_command(
f'ls -t {BACKUP_DIR}/daily/ | head -1'
)
assert returncode == 0, f"SSH failed: {stderr}"
assert stdout.strip(), "No daily backup found"
class TestBackupSize:
"""Tests for backup file sizes."""
@pytest.mark.slow
def test_hourly_backup_size_reasonable(self):
"""Hourly backup should be at least 1MB (not empty/corrupt)."""
returncode, stdout, stderr = ssh_command(
f'du -b {BACKUP_DIR}/hourly/$(ls -t {BACKUP_DIR}/hourly/ | head -1) | cut -f1'
)
assert returncode == 0, f"SSH failed: {stderr}"
size_bytes = int(stdout.strip())
size_mb = size_bytes / (1024 * 1024)
assert size_mb >= 1, f"Backup too small: {size_mb:.2f} MB (should be >= 1 MB)"
@pytest.mark.slow
def test_daily_backup_size_consistent(self):
"""Daily backup should not vary wildly from previous."""
returncode, stdout, stderr = ssh_command(
f'du -b {BACKUP_DIR}/daily/* | sort -k2 -r | head -2 | cut -f1'
)
if returncode == 0 and stdout.strip():
sizes = [int(s) for s in stdout.strip().split('\n') if s]
if len(sizes) >= 2:
latest, previous = sizes[0], sizes[1]
ratio = latest / previous if previous > 0 else 0
# Size should be within 50% of previous
assert 0.5 < ratio < 2.0, f"Backup size changed significantly: {ratio:.2f}x"
class TestDRScriptReady:
"""Tests for DR restore script availability."""
@pytest.mark.slow
def test_dr_restore_script_exists(self):
"""DR restore script should exist and be executable."""
returncode, stdout, stderr = ssh_command(
'test -x /var/www/nordabiznes/scripts/dr-restore.sh && echo "OK"'
)
assert returncode == 0, f"DR restore script not found or not executable: {stderr}"
assert 'OK' in stdout
class TestBackupCronActive:
"""Tests for backup cron jobs."""
@pytest.mark.slow
def test_backup_cron_exists(self):
"""Backup cron job should be configured."""
returncode, stdout, stderr = ssh_command(
'cat /etc/cron.d/nordabiz-backup 2>/dev/null || crontab -l | grep nordabiz'
)
# Either cron.d file exists or user crontab has entry
assert returncode == 0 or 'nordabiz' in stdout.lower(), "No backup cron found"