From ce2bd0fcd778b119b6a82af89a865fdfda2ab485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=BChl?= Date: Mon, 13 Apr 2026 10:02:31 +0000 Subject: [PATCH] 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 --- test-gc.sh | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100755 test-gc.sh diff --git a/test-gc.sh b/test-gc.sh new file mode 100755 index 0000000..39c410c --- /dev/null +++ b/test-gc.sh @@ -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