warpgate/tests/05-cache/test-dirty-no-evict.sh
grabbit a2d49137f9 Add comprehensive test suite: 63 integration tests + 110 Rust unit tests
Integration tests (tests/):
- 9 categories covering config, lifecycle, signals, supervision,
  cache, writeback, network faults, crash recovery, and CLI
- Shell-based harness with mock NAS (network namespace + SFTP),
  fault injection (tc netem), and power loss simulation
- TAP format runner (run-all.sh) with proper SKIP detection

Rust unit tests (warpgate/src/):
- 110 tests across 14 modules, all passing in 0.01s
- Config parsing, defaults validation, RestartTracker logic,
  RC API response parsing, rclone arg generation, service
  config generation, CLI output formatting, warmup path logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:21:35 +08:00

81 lines
2.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Test: dirty files are protected from LRU eviction
#
# Verifies that when the cache is under space pressure, dirty (unwritten)
# files are not evicted by the LRU policy. Clean cached files may be
# evicted, but dirty files must survive.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/../harness/helpers.sh"
source "$SCRIPT_DIR/../harness/mock-nas.sh"
require_root
setup_test_env
trap teardown_test_env EXIT
# Start mock NAS and pre-create 5 x 1 MB files for LRU pressure
start_mock_nas
for i in $(seq 1 5); do
nas_create_file "filler-${i}.bin" 1024
done
# Generate config with small cache (5 MB) and a very long write-back
# so dirty files remain dirty throughout the test
gen_config cache_max_size=5M write_back=300s
# Start warpgate and wait for readiness
start_warpgate
wait_for_mount
wait_for_rc_api
# Sever the network BEFORE writing the dirty file to prevent write-back
# from racing with LRU eviction — the file must stay dirty throughout.
inject_network_down
# Write a 1 MB dirty file through the mount (stays dirty due to 300s delay
# AND network being down, so write-back cannot succeed)
dd if=/dev/urandom bs=1K count=1024 2>/dev/null | \
dd of="$TEST_MOUNT/important-edit.bin" bs=1K 2>/dev/null
# Allow VFS to register the dirty write
sleep 2
# Confirm the file is dirty
dirty_before=$(get_dirty_count)
if [[ "$dirty_before" -lt 1 ]]; then
echo "FAIL: expected dirty count > 0 after write, got $dirty_before" >&2
exit 1
fi
# Now read the 5 x 1 MB filler files through the mount to create LRU
# pressure. With a 5 MB cache limit, evictions must happen, but the
# dirty file should be protected.
for i in $(seq 1 5); do
cat "$TEST_MOUNT/filler-${i}.bin" > /dev/null
done
# Allow time for LRU eviction to run
sleep 3
# The dirty file must still be present and dirty
dirty_after=$(get_dirty_count)
if [[ "$dirty_after" -lt 1 ]]; then
echo "FAIL: dirty file was evicted; dirty count dropped to $dirty_after" >&2
exit 1
fi
# Verify the dirty file is still readable through the mount
if [[ ! -f "$TEST_MOUNT/important-edit.bin" ]]; then
echo "FAIL: dirty file no longer accessible through mount" >&2
inject_network_up
exit 1
fi
# Verify the dirty file physically remains in the on-disk cache
assert_cached "important-edit.bin"
# Restore network for clean teardown
inject_network_up
echo "PASS: $(basename "$0" .sh)"