diff options
| author | Craig Jennings <c@cjennings.net> | 2026-01-29 12:18:12 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-01-29 12:18:12 -0600 |
| commit | f272f2a14c60ef853bb860c0612ad931d5a21d74 (patch) | |
| tree | ae07730fa28db2309c524c00fd2689d934252aa4 /tests/cases/test_backup.sh | |
| parent | 2bc8c5c7b416d506e9c46d9f381c73f5f9f052b9 (diff) | |
| download | rsyncshot-f272f2a14c60ef853bb860c0612ad931d5a21d74.tar.gz rsyncshot-f272f2a14c60ef853bb860c0612ad931d5a21d74.zip | |
Add SSH remote backup support, new commands, and test suite
- Add remote mode for SSH-based backups to servers like TrueNAS
- Add SSH_IDENTITY_FILE config for non-root SSH keys
- Add new commands: backup, status, list, dryrun
- Add dependency checks for rsync, ssh, flock
- Add timestamped logging
- Fix: duplicate cron jobs on repeated setup
- Fix: use mktemp for temp files
- Fix: use portable sed instead of grep -oP
- Fix: strengthen input validation with regex anchors
- Fix: handle paths with spaces (newline-separated includes)
- Change license from MIT to GPL v3
- Add automated test suite (25 tests)
- Update README with new features and testing docs
Diffstat (limited to 'tests/cases/test_backup.sh')
| -rwxr-xr-x | tests/cases/test_backup.sh | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/tests/cases/test_backup.sh b/tests/cases/test_backup.sh new file mode 100755 index 0000000..1ab4fbd --- /dev/null +++ b/tests/cases/test_backup.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash +# ============================================================================== +# Backup and Rotation Tests +# ============================================================================== + +source "$(dirname "${BASH_SOURCE[0]}")/../lib/test_helpers.sh" + +# ------------------------------------------------------------------------------ +# Test: Creates backup directory structure +# ------------------------------------------------------------------------------ +test_creates_backup_structure() { + setup_test_env + + create_test_config + create_test_includes + create_test_excludes + + local output + output=$(sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" manual 1 2>&1) + local exit_code=$? + + # Check directory structure + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME" "should create hostname dir" || { + teardown_test_env + return 1 + } + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/latest" "should create latest dir" || { + teardown_test_env + return 1 + } + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.0" "should create MANUAL.0 snapshot" || { + teardown_test_env + return 1 + } + + teardown_test_env +} + +# ------------------------------------------------------------------------------ +# Test: Copies files to backup +# ------------------------------------------------------------------------------ +test_copies_files() { + setup_test_env + + create_test_config + create_test_includes + create_test_excludes + + local output + output=$(sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" manual 1 2>&1) + + # Check files were copied + assert_file_exists "$TEST_BACKUP_DIR/$HOSTNAME/latest/home/testuser/file1.txt" "should copy file1.txt" || { + teardown_test_env + return 1 + } + assert_file_exists "$TEST_BACKUP_DIR/$HOSTNAME/latest/etc/test.conf" "should copy test.conf" || { + teardown_test_env + return 1 + } + + teardown_test_env +} + +# ------------------------------------------------------------------------------ +# Test: Snapshot is read-only +# ------------------------------------------------------------------------------ +test_snapshot_readonly() { + setup_test_env + + create_test_config + create_test_includes + create_test_excludes + + local output + output=$(sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" manual 1 2>&1) + + # Check snapshot directory has no write permission + # Note: We use stat to check actual permissions because -w always returns true for root + local perms + perms=$(stat -c '%A' "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.0" 2>/dev/null) + if [[ "$perms" == *w* ]]; then + echo "FAIL: Snapshot should be read-only (perms: $perms)" + teardown_test_env + return 1 + fi + + teardown_test_env + return 0 +} + +# ------------------------------------------------------------------------------ +# Test: Rotation works correctly +# ------------------------------------------------------------------------------ +test_rotation() { + setup_test_env + + create_test_config + create_test_includes + create_test_excludes + + # Run backup twice + sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" manual 3 2>&1 >/dev/null + sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" manual 3 2>&1 >/dev/null + + # Should have MANUAL.0 and MANUAL.1 + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.0" "should have MANUAL.0" || { + teardown_test_env + return 1 + } + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.1" "should have MANUAL.1 after rotation" || { + teardown_test_env + return 1 + } + + teardown_test_env +} + +# ------------------------------------------------------------------------------ +# Test: Deletes oldest snapshot beyond retention +# ------------------------------------------------------------------------------ +test_retention_limit() { + setup_test_env + + create_test_config + create_test_includes + create_test_excludes + + # Run backup 4 times with retention of 3 + for i in 1 2 3 4; do + sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" manual 3 2>&1 >/dev/null + done + + # Should have MANUAL.0, MANUAL.1, MANUAL.2 but NOT MANUAL.3 + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.0" "should have MANUAL.0" || { + teardown_test_env + return 1 + } + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.1" "should have MANUAL.1" || { + teardown_test_env + return 1 + } + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.2" "should have MANUAL.2" || { + teardown_test_env + return 1 + } + assert_dir_not_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.3" "should NOT have MANUAL.3 (beyond retention)" || { + teardown_test_env + return 1 + } + + teardown_test_env +} + +# ------------------------------------------------------------------------------ +# Test: Backup command works as alias +# ------------------------------------------------------------------------------ +test_backup_command() { + setup_test_env + + create_test_config + create_test_includes + create_test_excludes + + local output + output=$(sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" backup 2>&1) + local exit_code=$? + + # Should create MANUAL.0 (backup is alias for manual 1) + assert_dir_exists "$TEST_BACKUP_DIR/$HOSTNAME/MANUAL.0" "backup should create MANUAL.0" || { + teardown_test_env + return 1 + } + + teardown_test_env +} + +# ------------------------------------------------------------------------------ +# Test: Excludes files matching patterns +# ------------------------------------------------------------------------------ +test_excludes_patterns() { + setup_test_env + + create_test_config + create_test_includes + + # Create exclude file + cat > "$TEST_CONFIG_DIR/exclude.txt" << 'EOF' +*.tmp +*.log +EOF + + # Create files that should be excluded + echo "temp" > "$TEST_SOURCE_DIR/home/testuser/temp.tmp" + echo "log" > "$TEST_SOURCE_DIR/home/testuser/app.log" + + local output + output=$(sudo INSTALLHOME="$TEST_CONFIG_DIR" RSYNCSHOT_SKIP_MOUNT_CHECK=1 "$SCRIPT_PATH" manual 1 2>&1) + + # Excluded files should not exist in backup + assert_file_not_exists "$TEST_BACKUP_DIR/$HOSTNAME/latest/home/testuser/temp.tmp" "should exclude .tmp files" || { + teardown_test_env + return 1 + } + assert_file_not_exists "$TEST_BACKUP_DIR/$HOSTNAME/latest/home/testuser/app.log" "should exclude .log files" || { + teardown_test_env + return 1 + } + # Regular files should still exist + assert_file_exists "$TEST_BACKUP_DIR/$HOSTNAME/latest/home/testuser/file1.txt" "should include regular files" || { + teardown_test_env + return 1 + } + + teardown_test_env +} + +# ------------------------------------------------------------------------------ +# Run tests +# ------------------------------------------------------------------------------ +run_backup_tests() { + echo "" + echo "Running backup tests..." + echo "------------------------------------------------------------" + + run_test "creates backup directory structure" test_creates_backup_structure + run_test "copies files to backup" test_copies_files + run_test "snapshot is read-only" test_snapshot_readonly + run_test "rotation works correctly" test_rotation + run_test "respects retention limit" test_retention_limit + run_test "backup command works as alias" test_backup_command + run_test "excludes files matching patterns" test_excludes_patterns +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + run_backup_tests + print_summary +fi |
