orchestrator-claude-bin.test.sh
1 #!/bin/sh 2 # Test: resolve_claude_bin skips wrapper scripts and picks real binaries. 3 # This validates the fix for the CLAUDE_BIN stale-version bug where 4 # the orchestrator resolved once at startup and never re-resolved when 5 # Claude auto-updates deleted the old version. 6 # 7 # Run: sh tests/orchestrator-claude-bin.test.sh 8 9 set -e 10 11 PASS=0 12 FAIL=0 13 14 assert_eq() { 15 local label="$1" expected="$2" actual="$3" 16 if [ "$expected" = "$actual" ]; then 17 echo " PASS: $label" 18 PASS=$((PASS + 1)) 19 else 20 echo " FAIL: $label (expected '$expected', got '$actual')" 21 FAIL=$((FAIL + 1)) 22 fi 23 } 24 25 # Create temp directory simulating ~/.local/share/claude/versions/ 26 TMPDIR=$(mktemp -d) 27 trap "rm -rf $TMPDIR" EXIT 28 29 VERSIONS_DIR="$TMPDIR/versions" 30 mkdir -p "$VERSIONS_DIR" 31 32 # Create a fake binary (>1MB) 33 dd if=/dev/zero of="$VERSIONS_DIR/2.1.78" bs=1M count=2 2>/dev/null 34 chmod +x "$VERSIONS_DIR/2.1.78" 35 36 # Create a wrapper script (small, like the real 2.1.79) 37 cat > "$VERSIONS_DIR/2.1.79" << 'WRAPPER' 38 #!/bin/sh 39 echo "I am a wrapper" 40 WRAPPER 41 chmod +x "$VERSIONS_DIR/2.1.79" 42 43 echo "Test 1: resolve_claude_bin picks binary over wrapper" 44 # Source the resolve function with our test directory 45 HOME_SAVE="$HOME" 46 export HOME="$TMPDIR" 47 mkdir -p "$TMPDIR/.local/share/claude" 48 ln -s "$VERSIONS_DIR" "$TMPDIR/.local/share/claude/versions" 49 50 # Extract and run resolve_claude_bin 51 resolve_claude_bin() { 52 _claude_bin="" 53 if [ -d "$HOME/.local/share/claude/versions" ]; then 54 for _v in $(ls -1 "$HOME/.local/share/claude/versions" 2>/dev/null | sort -V -r); do 55 _candidate="$HOME/.local/share/claude/versions/$_v" 56 _sz=$(stat -c%s "$_candidate" 2>/dev/null || echo 0) 57 if [ -x "$_candidate" ] && [ "$_sz" -gt 1000000 ]; then 58 _claude_bin="$_candidate" 59 break 60 fi 61 done 62 fi 63 export CLAUDE_BIN="$_claude_bin" 64 } 65 66 resolve_claude_bin 67 # CLAUDE_BIN may resolve through symlink — check basename matches 68 _resolved_base=$(basename "$CLAUDE_BIN") 69 assert_eq "should pick 2.1.78 (binary)" "2.1.78" "$_resolved_base" 70 71 echo "" 72 echo "Test 2: resolve_claude_bin handles only wrapper scripts" 73 rm "$VERSIONS_DIR/2.1.78" 74 resolve_claude_bin 75 assert_eq "should be empty when only wrapper exists" "" "$CLAUDE_BIN" 76 77 echo "" 78 echo "Test 3: resolve_claude_bin handles empty directory" 79 rm "$VERSIONS_DIR/2.1.79" 80 resolve_claude_bin 81 assert_eq "should be empty when dir is empty" "" "$CLAUDE_BIN" 82 83 echo "" 84 echo "Test 4: wrapper script resolves to binary (not itself)" 85 # Recreate both 86 dd if=/dev/zero of="$VERSIONS_DIR/2.1.78" bs=1M count=2 2>/dev/null 87 chmod +x "$VERSIONS_DIR/2.1.78" 88 89 cat > "$VERSIONS_DIR/2.1.79" << WRAPPER 90 #!/bin/sh 91 _dir="$VERSIONS_DIR" 92 _latest=\$(ls -1 "\$_dir" 2>/dev/null | grep -v '\.tmp\$' | sort -V | while read -r v; do 93 _f="\$_dir/\$v" 94 _sz=\$(stat -c%s "\$_f" 2>/dev/null || echo 0) 95 [ -x "\$_f" ] && [ "\$_sz" -gt 1000000 ] && echo "\$v" 96 done | tail -1) 97 if [ -n "\$_latest" ]; then 98 echo "\$_dir/\$_latest" 99 fi 100 WRAPPER 101 chmod +x "$VERSIONS_DIR/2.1.79" 102 103 RESOLVED=$("$VERSIONS_DIR/2.1.79") 104 assert_eq "wrapper should resolve to 2.1.78" "$VERSIONS_DIR/2.1.78" "$RESOLVED" 105 106 export HOME="$HOME_SAVE" 107 108 echo "" 109 echo "Results: $PASS passed, $FAIL failed" 110 [ "$FAIL" -eq 0 ] || exit 1