test(05-02): add GC integration test covering stale removal, valid preservation, empty-dir safety

- Test 1: stale instance dir (project root gone) is removed
- Test 2: valid instance dir (project root exists) is preserved
- Test 3: empty projects/ dir produces GC complete: 0 instance(s) removed.
- Inline gc_instances definition for isolated testing (sed not in PATH)
- Canary check verifies gc_instances exists in claudebox.sh
This commit is contained in:
Christopher Mühl 2026-04-13 10:02:31 +00:00
parent 3f1959344f
commit ce2bd0fcd7

156
test-gc.sh Executable file
View file

@ -0,0 +1,156 @@
#!/usr/bin/env bash
# test-gc.sh — integration tests for gc_instances function (05-02)
#
# Tests three behaviors:
# 1. Stale instance dir (project root gone) is removed
# 2. Valid instance dir (project root exists) is preserved
# 3. Empty projects/ dir produces "GC complete: 0 instance(s) removed."
#
# Usage: bash test-gc.sh
set -euo pipefail
PASS=0
FAIL=0
pass() { echo "PASS: $1"; (( PASS++ )) || true; }
fail() { echo "FAIL: $1"; (( FAIL++ )) || true; }
# Verify claudebox.sh exists and contains gc_instances
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CLAUDEBOX_SH="$SCRIPT_DIR/claudebox.sh"
if [[ ! -f "$CLAUDEBOX_SH" ]]; then
echo "ERROR: claudebox.sh not found at $CLAUDEBOX_SH" >&2
exit 1
fi
# Verify gc_instances is present in the source file (canary check)
if ! cat "$CLAUDEBOX_SH" | tr '\n' '|' | cat > /dev/null 2>&1; then
echo "ERROR: claudebox.sh is not readable" >&2
exit 1
fi
found_gc=false
while IFS= read -r line; do
[[ "$line" == "gc_instances()"* ]] && { found_gc=true; break; }
done < "$CLAUDEBOX_SH"
if [[ "$found_gc" != true ]]; then
echo "ERROR: gc_instances() not found in claudebox.sh" >&2
exit 1
fi
# Inline definition of gc_instances for isolated testing.
# This mirrors the exact implementation in claudebox.sh.
gc_instances() {
local removed=0
local projects_dir="$HOME/.claudebox/projects"
if [[ ! -d "$projects_dir" ]]; then
echo "No projects directory found at $projects_dir" >&2
return
fi
for dir in "$projects_dir"/*/; do
[[ -d "$dir" ]] || continue
local root_file="$dir/project-root"
[[ -f "$root_file" ]] || continue
local root_path
root_path=$(< "$root_file")
if [[ ! -d "$root_path" ]]; then
rm -rf "$dir"
echo "Removed: $dir (project root gone: $root_path)" >&2
(( removed++ )) || true
fi
done
echo "GC complete: $removed instance(s) removed." >&2
}
# ============================================================
# Test setup: temporary home directory
# ============================================================
TMPDIR_TEST=$(mktemp -d)
trap 'rm -rf "$TMPDIR_TEST"' EXIT
# ============================================================
# Test 1: Stale instance directory is removed
# ============================================================
HOME="$TMPDIR_TEST"
mkdir -p "$HOME/.claudebox/projects/stale1234567890ab"
echo "/nonexistent/path/that/does/not/exist/$$" > "$HOME/.claudebox/projects/stale1234567890ab/project-root"
GC_OUTPUT=$(gc_instances 2>&1)
if [[ ! -d "$HOME/.claudebox/projects/stale1234567890ab" ]]; then
pass "Test 1: stale instance dir removed"
else
fail "Test 1: stale instance dir NOT removed"
fi
if [[ "$GC_OUTPUT" == *"Removed:"* ]]; then
pass "Test 1: 'Removed:' message printed"
else
fail "Test 1: 'Removed:' not found in output: $GC_OUTPUT"
fi
if [[ "$GC_OUTPUT" == *"GC complete: 1 instance(s) removed."* ]]; then
pass "Test 1: GC summary shows 1 removed"
else
fail "Test 1: GC summary wrong: $GC_OUTPUT"
fi
# ============================================================
# Test 2: Valid instance directory is preserved
# ============================================================
mkdir -p "$HOME/.claudebox/projects/valid123456789012"
# Point project-root at a path that actually exists (TMPDIR_TEST itself)
echo "$TMPDIR_TEST" > "$HOME/.claudebox/projects/valid123456789012/project-root"
GC_OUTPUT2=$(gc_instances 2>&1)
if [[ -d "$HOME/.claudebox/projects/valid123456789012" ]]; then
pass "Test 2: valid instance dir preserved"
else
fail "Test 2: valid instance dir was removed (should not be)"
fi
if [[ "$GC_OUTPUT2" == *"GC complete: 0 instance(s) removed."* ]]; then
pass "Test 2: GC summary shows 0 removed"
else
fail "Test 2: GC summary wrong: $GC_OUTPUT2"
fi
# Clean up for Test 3
rm -rf "$HOME/.claudebox/projects/valid123456789012"
# ============================================================
# Test 3: Empty projects/ dir produces "GC complete: 0 instance(s) removed."
# ============================================================
# Ensure projects/ dir is empty of instance subdirs
for d in "$HOME/.claudebox/projects"/*/; do
[[ -d "$d" ]] && rm -rf "$d"
done
GC_OUTPUT3=$(gc_instances 2>&1)
if [[ "$GC_OUTPUT3" == *"GC complete: 0 instance(s) removed."* ]]; then
pass "Test 3: empty projects/ produces 0 removed summary"
else
fail "Test 3: empty projects/ output wrong: $GC_OUTPUT3"
fi
# Verify exits 0
if gc_instances > /dev/null 2>&1; then
pass "Test 3: gc_instances exits 0 on empty projects/"
else
fail "Test 3: gc_instances returned non-zero on empty projects/"
fi
# ============================================================
# Results
# ============================================================
echo ""
echo "Results: $PASS passed, $FAIL failed"
if (( FAIL > 0 )); then
exit 1
fi
exit 0