#!/bin/bash # Immich Restore Script Test Suite # This script tests the restoration functionality with mock data and validation set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Test configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TEST_DIR="${SCRIPT_DIR}/test_data" RESTORE_SCRIPT="${SCRIPT_DIR}/restore-immich.sh" TEST_LOG="${SCRIPT_DIR}/../logs/immich-restore-test.log" # Test counters TESTS_RUN=0 TESTS_PASSED=0 TESTS_FAILED=0 # Create test directory mkdir -p "$TEST_DIR" mkdir -p "$(dirname "$TEST_LOG")" # Logging function log_test() { local message="$1" echo "$(date '+%Y-%m-%d %H:%M:%S') - TEST: $message" | tee -a "$TEST_LOG" } log_pass() { local test_name="$1" echo -e "${GREEN}✅ PASS${NC}: $test_name" echo "$(date '+%Y-%m-%d %H:%M:%S') - PASS: $test_name" >> "$TEST_LOG" TESTS_PASSED=$((TESTS_PASSED + 1)) } log_fail() { local test_name="$1" local details="$2" echo -e "${RED}❌ FAIL${NC}: $test_name" [ -n "$details" ] && echo " Details: $details" echo "$(date '+%Y-%m-%d %H:%M:%S') - FAIL: $test_name - $details" >> "$TEST_LOG" TESTS_FAILED=$((TESTS_FAILED + 1)) } log_info() { local message="$1" echo -e "${BLUE}ℹ️ INFO${NC}: $message" } # Test script existence and permissions test_script_setup() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Script Setup Validation" if [ -f "$RESTORE_SCRIPT" ]; then if [ -x "$RESTORE_SCRIPT" ]; then log_pass "Script exists and is executable" else log_fail "Script exists but is not executable" chmod +x "$RESTORE_SCRIPT" log_info "Made script executable" fi else log_fail "Restore script not found at $RESTORE_SCRIPT" return 1 fi } # Test help functionality test_help_functionality() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Help Functionality" local help_output if help_output=$("$RESTORE_SCRIPT" --help 2>&1); then if echo "$help_output" | grep -q "Usage:"; then log_pass "Help command works and shows usage" else log_fail "Help command runs but doesn't show proper usage" fi else log_fail "Help command failed to execute" fi } # Create mock backup files create_mock_backups() { log_test "Creating mock backup files for testing" # Create mock database backup (gzipped SQL) local mock_db_backup="${TEST_DIR}/mock_immich_db_backup_20250603_120000.sql.gz" echo "-- Mock Immich Database Backup CREATE DATABASE IF NOT EXISTS immich; USE immich; CREATE TABLE IF NOT EXISTS test_table (id INT PRIMARY KEY, name VARCHAR(100)); INSERT INTO test_table VALUES (1, 'test_data'); -- End of mock backup" | gzip > "$mock_db_backup" # Create mock uploads backup (tar.gz) local mock_uploads_backup="${TEST_DIR}/mock_immich_uploads_20250603_120000.tar.gz" mkdir -p "${TEST_DIR}/mock_uploads/upload" mkdir -p "${TEST_DIR}/mock_uploads/thumbs" echo "Mock photo data" > "${TEST_DIR}/mock_uploads/upload/photo1.jpg" echo "Mock thumbnail data" > "${TEST_DIR}/mock_uploads/thumbs/thumb1.jpg" tar -czf "$mock_uploads_backup" -C "${TEST_DIR}" mock_uploads # Create corrupted backup files for testing echo "corrupted data" > "${TEST_DIR}/corrupted_db.sql.gz" echo "not a tar file" > "${TEST_DIR}/corrupted_uploads.tar.gz" log_info "Mock backup files created" return 0 } # Test dry-run functionality test_dry_run() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Dry Run Functionality" local mock_db_backup="${TEST_DIR}/mock_immich_db_backup_20250603_120000.sql.gz" local mock_uploads_backup="${TEST_DIR}/mock_immich_uploads_20250603_120000.tar.gz" local output if output=$("$RESTORE_SCRIPT" --db-backup "$mock_db_backup" --uploads-backup "$mock_uploads_backup" --dry-run 2>&1); then if echo "$output" | grep -q "DRY RUN MODE"; then log_pass "Dry run mode works correctly" else log_fail "Dry run executed but didn't show proper dry run message" fi else log_fail "Dry run command failed" fi } # Test file validation test_file_validation() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Backup File Validation" # Test with non-existent files local output if output=$("$RESTORE_SCRIPT" --db-backup "/nonexistent/file.sql.gz" --uploads-backup "/nonexistent/file.tar.gz" --dry-run 2>&1); then log_fail "Script should fail with non-existent files but didn't" else if echo "$output" | grep -q "not found"; then log_pass "File validation correctly detects missing files" else log_fail "Script failed but not with expected error message" fi fi } # Test corrupted file detection test_corrupted_file_detection() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Corrupted File Detection" local corrupted_db="${TEST_DIR}/corrupted_db.sql.gz" local corrupted_uploads="${TEST_DIR}/corrupted_uploads.tar.gz" local output if output=$("$RESTORE_SCRIPT" --db-backup "$corrupted_db" --uploads-backup "$corrupted_uploads" --dry-run 2>&1); then log_fail "Script should detect corrupted files but didn't" else if echo "$output" | grep -q "corrupted"; then log_pass "Corrupted file detection works" else log_fail "Script failed but not with corrupted file error" fi fi } # Test skip options test_skip_options() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Skip Options Functionality" # Test skip-db option local output if output=$("$RESTORE_SCRIPT" --uploads-backup "${TEST_DIR}/mock_immich_uploads_20250603_120000.tar.gz" --skip-db --dry-run 2>&1); then if echo "$output" | grep -q "Database backup: SKIPPED"; then log_pass "Skip database option works" else log_fail "Skip database option doesn't show correct status" fi else log_fail "Skip database option test failed" fi TESTS_RUN=$((TESTS_RUN + 1)) # Test skip-uploads option if output=$("$RESTORE_SCRIPT" --db-backup "${TEST_DIR}/mock_immich_db_backup_20250603_120000.sql.gz" --skip-uploads --dry-run 2>&1); then if echo "$output" | grep -q "Uploads backup: SKIPPED"; then log_pass "Skip uploads option works" else log_fail "Skip uploads option doesn't show correct status" fi else log_fail "Skip uploads option test failed" fi } # Test environment variable validation test_env_validation() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Environment Variable Validation" # Temporarily move .env file to test missing env local env_file="$(dirname "$RESTORE_SCRIPT")/../.env" if [ -f "$env_file" ]; then mv "$env_file" "${env_file}.backup" local output if output=$("$RESTORE_SCRIPT" --help 2>&1); then if echo "$output" | grep -q "Error.*env"; then log_pass "Missing environment file detection works" else log_fail "Script should detect missing .env file" fi else log_pass "Script correctly fails with missing .env file" fi # Restore .env file mv "${env_file}.backup" "$env_file" else log_info "No .env file found to test with" fi } # Test notification system (dry run) test_notification_system() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Notification System" local mock_db_backup="${TEST_DIR}/mock_immich_db_backup_20250603_120000.sql.gz" local mock_uploads_backup="${TEST_DIR}/mock_immich_uploads_20250603_120000.tar.gz" # Set a test webhook URL temporarily export WEBHOOK_URL="https://httpbin.org/post" local output if output=$("$RESTORE_SCRIPT" --db-backup "$mock_db_backup" --uploads-backup "$mock_uploads_backup" --dry-run 2>&1); then if echo "$output" | grep -q "Immich Restore Started"; then log_pass "Notification system appears to be working" else log_fail "Notification system not triggering properly" fi else log_fail "Test with notifications failed" fi unset WEBHOOK_URL } # Test argument parsing test_argument_parsing() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Argument Parsing" # Test unknown option local output if output=$("$RESTORE_SCRIPT" --unknown-option 2>&1); then if echo "$output" | grep -q "Unknown option"; then log_pass "Unknown option detection works" else log_fail "Unknown option should be detected" fi else log_pass "Script correctly fails with unknown option" fi } # Test logging functionality test_logging() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Logging Functionality" local log_dir="$(dirname "$RESTORE_SCRIPT")/../logs" local restore_log="${log_dir}/immich-restore.log" # Clear previous log entries [ -f "$restore_log" ] && > "$restore_log" local mock_db_backup="${TEST_DIR}/mock_immich_db_backup_20250603_120000.sql.gz" local mock_uploads_backup="${TEST_DIR}/mock_immich_uploads_20250603_120000.tar.gz" "$RESTORE_SCRIPT" --db-backup "$mock_db_backup" --uploads-backup "$mock_uploads_backup" --dry-run >/dev/null 2>&1 if [ -f "$restore_log" ] && [ -s "$restore_log" ]; then if grep -q "IMMICH RESTORATION STARTED" "$restore_log"; then log_pass "Logging functionality works" else log_fail "Log file exists but doesn't contain expected content" fi else log_fail "Log file not created or is empty" fi } # Performance test with larger mock files test_performance() { TESTS_RUN=$((TESTS_RUN + 1)) log_test "Performance with Larger Files" # Create a larger mock database backup local large_db_backup="${TEST_DIR}/large_mock_db.sql.gz" { echo "-- Large Mock Database Backup" for i in {1..1000}; do echo "INSERT INTO test_table VALUES ($i, 'test_data_$i');" done echo "-- End of large mock backup" } | gzip > "$large_db_backup" # Create larger mock uploads local large_uploads_backup="${TEST_DIR}/large_mock_uploads.tar.gz" mkdir -p "${TEST_DIR}/large_mock_uploads" for i in {1..50}; do echo "Mock large file content $i" > "${TEST_DIR}/large_mock_uploads/file_$i.txt" done tar -czf "$large_uploads_backup" -C "${TEST_DIR}" large_mock_uploads local start_time=$(date +%s) local output if output=$("$RESTORE_SCRIPT" --db-backup "$large_db_backup" --uploads-backup "$large_uploads_backup" --dry-run 2>&1); then local end_time=$(date +%s) local duration=$((end_time - start_time)) if [ $duration -lt 30 ]; then # Should complete dry run in under 30 seconds log_pass "Performance test completed in ${duration}s" else log_fail "Performance test took too long: ${duration}s" fi else log_fail "Performance test failed to execute" fi } # Cleanup test data cleanup_test_data() { log_test "Cleaning up test data" rm -rf "$TEST_DIR" log_info "Test data cleaned up" } # Generate test report generate_test_report() { echo "" echo "==================================================================" echo -e "${BLUE}IMMICH RESTORE SCRIPT TEST REPORT${NC}" echo "==================================================================" echo "Test Date: $(date)" echo "Script Tested: $RESTORE_SCRIPT" echo "" echo "Test Results:" echo -e " Total Tests Run: ${BLUE}$TESTS_RUN${NC}" echo -e " Tests Passed: ${GREEN}$TESTS_PASSED${NC}" echo -e " Tests Failed: ${RED}$TESTS_FAILED${NC}" echo "" if [ $TESTS_FAILED -eq 0 ]; then echo -e "${GREEN}✅ ALL TESTS PASSED${NC}" echo "The restore script is ready for production use." else echo -e "${RED}❌ SOME TESTS FAILED${NC}" echo "Please review the test log for details: $TEST_LOG" fi echo "" echo "Test Log Location: $TEST_LOG" echo "==================================================================" } # Main test execution main() { echo -e "${BLUE}Starting Immich Restore Script Test Suite${NC}" echo "Test Directory: $TEST_DIR" echo "Log File: $TEST_LOG" echo "" # Initialize test log echo "=== Immich Restore Script Test Suite ===" > "$TEST_LOG" echo "Started: $(date)" >> "$TEST_LOG" echo "" >> "$TEST_LOG" # Run all tests test_script_setup create_mock_backups test_help_functionality test_dry_run test_file_validation test_corrupted_file_detection test_skip_options test_env_validation test_notification_system test_argument_parsing test_logging test_performance # Cleanup and report cleanup_test_data generate_test_report # Exit with appropriate code if [ $TESTS_FAILED -eq 0 ]; then exit 0 else exit 1 fi } # Run tests main "$@"