#!/usr/bin/env bash # TST-016: Backup Restore Test — CC-047 # Verifies Zerobyte backup integrity for CEO-OS on supersrv. # Usage: bash scripts/test-backup-restore.sh # Exit codes: 0=PASS, 1=FAIL, 2=WARN set -euo pipefail ZEROBYTE_DB="${ZEROBYTE_DB:-/var/lib/zerobyte/data/zerobyte.db}" MAX_AGE_HOURS="${MAX_AGE_HOURS:-26}" # warn if newest backup older than 26h PASS=0; WARN=0; FAIL=0 log() { echo "[$(date -u +%H:%M:%S)] $*"; } pass() { log "PASS: $*"; ((PASS++)) || true; } warn() { log "WARN: $*"; ((WARN++)) || true; } fail() { log "FAIL: $*"; ((FAIL++)) || true; } log "=== TST-016: Backup/Restore Test ===" log "Zerobyte DB: $ZEROBYTE_DB" log "Max age: ${MAX_AGE_HOURS}h" # 1. Zerobyte DB exists if [[ -f "$ZEROBYTE_DB" ]]; then pass "Zerobyte SQLite DB exists at $ZEROBYTE_DB" else fail "Zerobyte SQLite DB NOT found at $ZEROBYTE_DB" log "RESULT: FAIL ($FAIL failures, $WARN warnings, $PASS passed)" exit 1 fi # 2. DB is readable if sqlite3 "$ZEROBYTE_DB" "SELECT 1" &>/dev/null; then pass "Zerobyte DB is readable" else fail "Zerobyte DB is not readable" exit 1 fi # 3. Check tables TABLES=$(sqlite3 "$ZEROBYTE_DB" "SELECT name FROM sqlite_master WHERE type='table'" 2>/dev/null | tr '\n' ',') log "Tables: $TABLES" if [[ "$TABLES" == *"backups"* ]]; then pass "backups table exists" else warn "backups table not found — schema may differ" fi # 4. Check recent backups BACKUP_COUNT=$(sqlite3 "$ZEROBYTE_DB" "SELECT COUNT(*) FROM backups" 2>/dev/null || echo "0") log "Total backup records: $BACKUP_COUNT" if [[ "$BACKUP_COUNT" -gt 0 ]]; then pass "Backup records found: $BACKUP_COUNT" # Check newest backup age NEWEST=$(sqlite3 "$ZEROBYTE_DB" "SELECT MAX(created_at) FROM backups" 2>/dev/null || echo "") if [[ -n "$NEWEST" ]]; then NEWEST_EPOCH=$(date -d "$NEWEST" +%s 2>/dev/null || date -j -f "%Y-%m-%d %H:%M:%S" "$NEWEST" +%s 2>/dev/null || echo "0") NOW_EPOCH=$(date +%s) AGE_HOURS=$(( (NOW_EPOCH - NEWEST_EPOCH) / 3600 )) log "Newest backup: $NEWEST (${AGE_HOURS}h ago)" if [[ "$AGE_HOURS" -lt "$MAX_AGE_HOURS" ]]; then pass "Newest backup is ${AGE_HOURS}h old (within ${MAX_AGE_HOURS}h threshold)" else fail "Newest backup is ${AGE_HOURS}h old — exceeds ${MAX_AGE_HOURS}h threshold" fi fi # Check failed backups FAILED=$(sqlite3 "$ZEROBYTE_DB" "SELECT COUNT(*) FROM backups WHERE status='failed'" 2>/dev/null || echo "0") if [[ "$FAILED" -gt 0 ]]; then warn "$FAILED backup(s) with status=failed" else pass "No failed backups found" fi # List last 4 backups log "Last 4 backups:" sqlite3 "$ZEROBYTE_DB" "SELECT id, name, status, created_at FROM backups ORDER BY created_at DESC LIMIT 4" 2>/dev/null | while IFS='|' read -r id name status ts; do log " [$status] $name @ $ts" done else warn "No backup records in Zerobyte DB — first run or schema mismatch" fi # 5. Zerobyte agent process running if pgrep -f zerobyte &>/dev/null; then pass "Zerobyte agent process is running" else fail "Zerobyte agent process NOT running" fi # 6. Zerobyte port 4096 responding if curl -s --max-time 3 http://localhost:4096/ &>/dev/null; then pass "Zerobyte HTTP service responding on port 4096" else warn "Zerobyte HTTP port 4096 not responding (may require auth)" fi # ── Summary ───────────────────────────────────────────────────────────────── log "" log "=== TST-016 RESULT ===" log "PASS: $PASS | WARN: $WARN | FAIL: $FAIL" if [[ "$FAIL" -gt 0 ]]; then log "STATUS: FAIL" exit 1 elif [[ "$WARN" -gt 0 ]]; then log "STATUS: WARN" exit 2 else log "STATUS: PASS" exit 0 fi