#!/bin/bash # kugetsu test suite # Run with: bash skills/kugetsu/tests/test-kugetsu.sh # # Memory management approach: # - Sequential test execution (no parallel) # - Cleanup between tests that spawn opencode # - No hard memory cap (ulimit -v breaks Bun/opencode) # - If OOM occurs, it is a known failure mode set -euo pipefail KUGETSU="./skills/kugetsu/scripts/kugetsu" TEST_SESSION_PREFIX="kugetsu-test-" PASS=0 FAIL=0 cleanup_sessions() { for dir in ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}*; do [ -d "$dir" ] && rm -rf "$dir" 2>/dev/null || true done } cleanup_opencode() { pkill -f "opencode.*${TEST_SESSION_PREFIX}" 2>/dev/null || true pkill -f "kugetsu.*${TEST_SESSION_PREFIX}" 2>/dev/null || true sleep 0.5 } cleanup() { cleanup_sessions cleanup_opencode } pass() { echo "✅ PASS: $1" PASS=$((PASS + 1)) } fail() { echo "❌ FAIL: $1" FAIL=$((FAIL + 1)) } cleanup echo "=== kugetsu Test Suite ===" echo "" # Test 1: Help echo "--- Test: help ---" if $KUGETSU help 2>&1 | grep -q "kugetsu - OpenCode Session Manager"; then pass "help displays usage" else fail "help displays usage" fi echo "" # Test 2: List empty echo "--- Test: list (empty) ---" if $KUGETSU list 2>&1 | grep -q "SESSION_ID"; then pass "list shows header even when empty" else fail "list shows header even when empty" fi echo "" # Test 3: List --all empty echo "--- Test: list --all (empty) ---" if $KUGETSU list --all 2>&1 | grep -q "SESSION_ID"; then pass "list --all shows header even when empty" else fail "list --all shows header even when empty" fi echo "" # Test 4: Start session (quick exit) echo "--- Test: start session ---" if timeout 15 bash -c "$KUGETSU start ${TEST_SESSION_PREFIX}start-test 'echo hello'" 2>&1; then if [ -d ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}start-test ]; then pass "start creates session directory" else fail "start creates session directory" fi else fail "start runs successfully" fi echo "" # Test 5: List shows only left by default echo "--- Test: list default filters non-left ---" if ! $KUGETSU list 2>&1 | grep -q "${TEST_SESSION_PREFIX}start-test"; then pass "list default hides idle sessions" else fail "list default hides idle sessions" fi echo "" # Test 6: List --all shows all echo "--- Test: list --all shows all states ---" if $KUGETSU list --all 2>&1 | grep -q "${TEST_SESSION_PREFIX}start-test"; then pass "list --all shows all sessions" else fail "list --all shows all sessions" fi echo "" # Test 7: Resume with auto-fill echo "--- Test: resume auto-fill ---" mkdir -p ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}resume-test echo "left" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}resume-test/state echo "continue this task" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}resume-test/message OUTPUT=$(timeout 10 bash -c "$KUGETSU resume ${TEST_SESSION_PREFIX}resume-test" 2>&1 || true) if echo "$OUTPUT" | grep -q "Auto-filled message: continue this task"; then pass "resume auto-fills stored message" else fail "resume auto-fills stored message" fi cleanup echo "" # Test 8: Resume with provided message overrides echo "--- Test: resume with message overrides ---" mkdir -p ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}resume-override echo "left" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}resume-override/state echo "original message" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}resume-override/message OUTPUT=$(timeout 30 bash -c "$KUGETSU resume ${TEST_SESSION_PREFIX}resume-override 'new message'" 2>&1 || true) if echo "$OUTPUT" | grep -q "new message" && ! echo "$OUTPUT" | grep -q "Auto-filled message"; then pass "resume uses provided message over auto-fill" else fail "resume uses provided message over auto-fill: $OUTPUT" fi cleanup echo "" # Test 9: Resume idle session fails echo "--- Test: resume idle session fails ---" rm -rf ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}idle-test 2>/dev/null mkdir -p ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}idle-test echo "idle" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}idle-test/state OUTPUT=$(timeout 5 bash -c "$KUGETSU resume ${TEST_SESSION_PREFIX}idle-test" 2>&1 || true) if echo "$OUTPUT" | grep -q "cannot be resumed"; then pass "resume idle session fails with message" else echo "DEBUG: $OUTPUT" fail "resume idle session fails with message" fi echo "" # Test 10: Resume non-existent session fails echo "--- Test: resume non-existent session fails ---" rm -rf ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}nonexistent 2>/dev/null OUTPUT=$(timeout 5 bash -c "$KUGETSU resume ${TEST_SESSION_PREFIX}nonexistent" 2>&1 || true) if echo "$OUTPUT" | grep -q "not found"; then pass "resume non-existent session fails" else echo "DEBUG: $OUTPUT" fail "resume non-existent session fails" fi echo "" # Test 11: Stop non-used session fails echo "--- Test: stop non-used session fails ---" rm -rf ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}notused 2>/dev/null mkdir -p ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}notused echo "idle" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}notused/state OUTPUT=$(timeout 5 bash -c "$KUGETSU stop ${TEST_SESSION_PREFIX}notused" 2>&1 || true) if echo "$OUTPUT" | grep -q "not in use"; then pass "stop non-used session fails" else echo "DEBUG: $OUTPUT" fail "stop non-used session fails" fi echo "" # Test 12: Start existing left session resumes instead echo "--- Test: start on left session resumes ---" mkdir -p ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}left-start echo "left" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}left-start/state echo "original task" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}left-start/message OUTPUT=$(timeout 10 bash -c "$KUGETSU start ${TEST_SESSION_PREFIX}left-start 'new task'" 2>&1 || true) if echo "$OUTPUT" | grep -q "Resuming instead"; then pass "start on left session resumes" else fail "start on left session resumes" fi cleanup echo "" # ============================================================================ # FLAKY TESTS - Commented out due to timing/process behavior issues # ============================================================================ # Test: Stop active session (FLAKY - timing dependent) # echo "--- Test: stop active session (FLAKY) ---" # ( # timeout 20 bash -c "$KUGETSU start ${TEST_SESSION_PREFIX}stop-test 'sleep 30'" 2>&1 & # KUGETSU_PID=$! # sleep 3 # # # Check session is in use # if ! $KUGETSU list --all 2>&1 | grep -q "${TEST_SESSION_PREFIX}stop-test.*used"; then # echo "⚠️ SKIP (FLAKY): Could not verify session was used" # elif timeout 5 bash -c "$KUGETSU stop ${TEST_SESSION_PREFIX}stop-test" 2>&1; then # if [ "$(cat ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}stop-test/state 2>/dev/null)" = "idle" ]; then # echo "✅ PASS (FLAKY): stop transitions to idle" # else # echo "❌ FAIL (FLAKY): stop does not transition to idle" # fi # else # echo "❌ FAIL (FLAKY): stop command failed" # fi # # wait $KUGETSU_PID 2>/dev/null || true # ) 2>&1 || true # Test: Interrupt session leaves state as left (FLAKY - opencode signal handling) # echo "--- Test: interrupt session leaves left (FLAKY) ---" # ( # bash -c "$KUGETSU start ${TEST_SESSION_PREFIX}interrupt-test 'sleep 30'" 2>&1 & # KUGETSU_PID=$! # sleep 3 # # # Find and kill opencode process # OPENCODE_PID=$(pgrep -f "opencode.*${TEST_SESSION_PREFIX}interrupt-test" | head -1 || true) # if [ -n "$OPENCODE_PID" ]; then # kill -9 $OPENCODE_PID 2>/dev/null || true # fi # # wait $KUGETSU_PID 2>/dev/null || true # sleep 1 # # STATE=$(cat ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}interrupt-test/state 2>/dev/null || echo "unknown") # if [ "$STATE" = "left" ]; then # echo "✅ PASS (FLAKY): interrupt leaves state as left" # else # echo "❌ FAIL (FLAKY): interrupt left state=$STATE (expected left)" # fi # ) 2>&1 || true # Test: Concurrent resume attempts (FLAKY - race condition) # echo "--- Test: concurrent resume (FLAKY) ---" # mkdir -p ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}concurrent # echo "left" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}concurrent/state # echo "test task" > ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}concurrent/message # # ( # timeout 10 bash -c "$KUGETSU resume ${TEST_SESSION_PREFIX}concurrent" 2>&1 & # timeout 10 bash -c "$KUGETSU resume ${TEST_SESSION_PREFIX}concurrent" 2>&1 # ) 2>&1 || true # # echo "⚠️ NOTE (FLAKY): This test is informational only - no assertion" # rm -rf ~/.kugetsu/sessions/${TEST_SESSION_PREFIX}concurrent # ============================================================================ # Cleanup # ============================================================================ cleanup echo "" echo "=== Test Summary ===" echo "Passed: $PASS" echo "Failed: $FAIL" echo "" if [ $FAIL -eq 0 ]; then echo "All tests passed!" exit 0 else echo "Some tests failed." exit 1 fi