241 lines
8.1 KiB
Bash
Executable File
241 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# FILE: test/test-api.sh
|
|
|
|
# Chess API Test Suite
|
|
# Requires: curl, jq (optional for pretty output)
|
|
|
|
BASE_URL="http://localhost:8080"
|
|
API_URL="${BASE_URL}/api/v1"
|
|
|
|
# Configurable delay between API calls (in seconds)
|
|
API_DELAY=${API_DELAY:-0.2} # Default 200ms between calls
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
# Test counters
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
# Helper functions
|
|
test_case() {
|
|
echo -e "\n${YELLOW}TEST: $1${NC}"
|
|
sleep $API_DELAY # Add delay before each test
|
|
}
|
|
|
|
assert_status() {
|
|
local expected=$1
|
|
local actual=$2
|
|
local test_name=$3
|
|
|
|
if [ "$actual" = "$expected" ]; then
|
|
echo -e "${GREEN}✓ $test_name: HTTP $actual${NC}"
|
|
((PASS++))
|
|
else
|
|
echo -e "${RED}✗ $test_name: Expected HTTP $expected, got $actual${NC}"
|
|
((FAIL++))
|
|
fi
|
|
}
|
|
|
|
api_request() {
|
|
local method=$1
|
|
local url=$2
|
|
shift 2
|
|
curl -s "$@" -X "$method" "$url"
|
|
local status=$?
|
|
sleep $API_DELAY
|
|
return $status
|
|
}
|
|
|
|
# Start tests
|
|
echo "=== Chess API Test Suite ==="
|
|
echo "Server: $BASE_URL"
|
|
echo "Starting tests..."
|
|
|
|
# Test 1: Health check
|
|
test_case "Health Check"
|
|
STATUS=$(api_request GET "$BASE_URL/health" -o /dev/null -w "%{http_code}")
|
|
assert_status 200 "$STATUS" "Health endpoint"
|
|
|
|
# Test 2: Create human vs computer game
|
|
test_case "Create Human vs Computer Game"
|
|
GAME_RESPONSE=$(api_request POST "$API_URL/games" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"white": 0, "black": 1}')
|
|
GAME_ID=$(echo "$GAME_RESPONSE" | grep -o '"gameId":"[^"]*' | cut -d'"' -f4)
|
|
STATUS=$(api_request POST "$API_URL/games" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"white": 0, "black": 1}')
|
|
assert_status 201 "$STATUS" "Create game"
|
|
echo "Game ID: $GAME_ID"
|
|
|
|
# Test 3: Make valid human move
|
|
test_case "Make Valid Human Move"
|
|
STATUS=$(api_request POST "$API_URL/games/$GAME_ID/moves" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"move": "e2e4"}')
|
|
assert_status 200 "$STATUS" "Valid move e2e4"
|
|
|
|
# Test 4: Get game state (should auto-execute computer move)
|
|
test_case "Get Game State (Auto-Execute Computer)"
|
|
RESPONSE=$(api_request GET "$API_URL/games/$GAME_ID")
|
|
STATUS=$(api_request GET "$API_URL/games/$GAME_ID" -o /dev/null -w "%{http_code}")
|
|
assert_status 200 "$STATUS" "Get game state"
|
|
echo "Current turn: $(echo "$RESPONSE" | grep -o '"turn":"[^"]*' | cut -d'"' -f4)"
|
|
|
|
# Test 5: Make invalid human move
|
|
test_case "Make Invalid Human Move"
|
|
STATUS=$(api_request POST "$API_URL/games/$GAME_ID/moves" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"move": "e2e5"}')
|
|
assert_status 400 "$STATUS" "Invalid move e2e5"
|
|
|
|
# Test 6: Undo last move
|
|
test_case "Undo Last Move"
|
|
STATUS=$(api_request POST "$API_URL/games/$GAME_ID/undo" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"count": 2}')
|
|
assert_status 200 "$STATUS" "Undo 2 moves"
|
|
|
|
# Test 7: Get ASCII board
|
|
test_case "Get ASCII Board"
|
|
BOARD_RESPONSE=$(api_request GET "$API_URL/games/$GAME_ID/board")
|
|
STATUS=$(api_request GET "$API_URL/games/$GAME_ID/board" -o /dev/null -w "%{http_code}")
|
|
assert_status 200 "$STATUS" "Get board"
|
|
echo "$BOARD_RESPONSE" | grep -o '"board":"[^"]*' | cut -d'"' -f4 | sed 's/\\n/\n/g'
|
|
|
|
# Test 8: Delete game
|
|
test_case "Delete Game"
|
|
STATUS=$(api_request DELETE "$API_URL/games/$GAME_ID" -o /dev/null -w "%{http_code}")
|
|
assert_status 204 "$STATUS" "Delete game"
|
|
|
|
# Test 9: Create computer vs computer game
|
|
test_case "Create Computer vs Computer Game"
|
|
COMP_RESPONSE=$(api_request POST "$API_URL/games" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"white": 1, "black": 1}')
|
|
COMP_ID=$(echo "$COMP_RESPONSE" | grep -o '"gameId":"[^"]*' | cut -d'"' -f4)
|
|
echo "Computer game ID: $COMP_ID"
|
|
|
|
# Test 10: Multiple GET requests to observe progress
|
|
test_case "Computer vs Computer Progress"
|
|
for i in {1..3}; do
|
|
RESPONSE=$(api_request GET "$API_URL/games/$COMP_ID")
|
|
MOVES=$(echo "$RESPONSE" | grep -o '"moves":\[[^]]*' | cut -d'[' -f2 | cut -d']' -f1)
|
|
STATE=$(echo "$RESPONSE" | grep -o '"state":"[^"]*' | cut -d'"' -f4)
|
|
echo "Move $i - State: $STATE, Moves made: $(echo "$MOVES" | grep -o ',' | wc -l)"
|
|
if [ "$STATE" != "ongoing" ]; then
|
|
echo "Game ended: $STATE"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# Test 11: Clean up computer game
|
|
api_request DELETE "$API_URL/games/$COMP_ID" > /dev/null
|
|
|
|
# Test 12: Rate limiting - 2 requests within 1 second
|
|
test_case "Rate Limiting - Rapid Requests"
|
|
STATUS1=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL/games/test")
|
|
STATUS2=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL/games/test")
|
|
assert_status 404 "$STATUS1" "First request"
|
|
assert_status 429 "$STATUS2" "Second request (rate limited)"
|
|
echo "Test will fail in dev mode as rate limiter is permissive."
|
|
|
|
# Test 13: Wait and retry after rate limit
|
|
test_case "Rate Limit Recovery"
|
|
sleep 1.5
|
|
STATUS=$(api_request GET "$API_URL/games/test" -o /dev/null -w "%{http_code}")
|
|
assert_status 404 "$STATUS" "Request after waiting"
|
|
|
|
# Test 14: Test with X-Forwarded-For (different IPs)
|
|
test_case "Rate Limiting with Different IPs"
|
|
STATUS1=$(api_request GET "$API_URL/games/test" -o /dev/null -w "%{http_code}" -H "X-Forwarded-For: 192.168.1.1")
|
|
STATUS2=$(api_request GET "$API_URL/games/test" -o /dev/null -w "%{http_code}" -H "X-Forwarded-For: 192.168.1.2")
|
|
assert_status 404 "$STATUS1" "IP 192.168.1.1"
|
|
assert_status 404 "$STATUS2" "IP 192.168.1.2 (different IP)"
|
|
|
|
# Test 15: Invalid JSON body
|
|
test_case "Invalid JSON Body"
|
|
STATUS=$(api_request POST "$API_URL/games" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: application/json" \
|
|
-d 'invalid json')
|
|
assert_status 400 "$STATUS" "Invalid JSON"
|
|
|
|
# Test 16: Wrong Content-Type header
|
|
test_case "Wrong Content-Type Header"
|
|
STATUS=$(api_request POST "$API_URL/games" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: text/plain" \
|
|
-d '{"white": 0, "black": 1}')
|
|
assert_status 415 "$STATUS" "Wrong Content-Type"
|
|
|
|
# Test 17: Non-existent gameId
|
|
test_case "Non-existent Game ID"
|
|
STATUS=$(api_request GET "$API_URL/games/non-existent-id" -o /dev/null -w "%{http_code}")
|
|
assert_status 404 "$STATUS" "Game not found"
|
|
|
|
# Test 18: Create game to test end conditions
|
|
test_case "Move When Game Over"
|
|
ENDGAME_RESPONSE=$(api_request POST "$API_URL/games" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"white": 0, "black": 0, "fen": "7k/5Q2/5K2/8/8/8/8/8 w - - 0 1"}')
|
|
ENDGAME_ID=$(echo "$ENDGAME_RESPONSE" | grep -o '"gameId":"[^"]*' | cut -d'"' -f4)
|
|
|
|
# Make checkmate move
|
|
api_request POST "$API_URL/games/$ENDGAME_ID/moves" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"move": "f7g7"}' > /dev/null
|
|
|
|
# Try to make another move after checkmate
|
|
STATUS=$(api_request POST "$API_URL/games/$ENDGAME_ID/moves" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"move": "h8h7"}')
|
|
assert_status 400 "$STATUS" "Move after game over"
|
|
|
|
# Clean up
|
|
api_request DELETE "$API_URL/games/$ENDGAME_ID" > /dev/null
|
|
|
|
# Test 19: Move when not player's turn - Use human vs human game
|
|
test_case "Move When Not Player's Turn"
|
|
# Create human vs human game so no automatic moves happen
|
|
TURN_RESPONSE=$(api_request POST "$API_URL/games" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"white": 0, "black": 0}') # BOTH are human players
|
|
TURN_ID=$(echo "$TURN_RESPONSE" | grep -o '"gameId":"[^"]*' | cut -d'"' -f4)
|
|
|
|
# White moves
|
|
api_request POST "$API_URL/games/$TURN_ID/moves" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"move": "e2e4"}' > /dev/null
|
|
|
|
# Now it's black's turn, try to move as white again (should fail)
|
|
STATUS=$(api_request POST "$API_URL/games/$TURN_ID/moves" \
|
|
-o /dev/null -w "%{http_code}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"move": "d2d4"}')
|
|
assert_status 400 "$STATUS" "Move when not turn"
|
|
|
|
# Clean up
|
|
api_request DELETE "$API_URL/games/$TURN_ID" > /dev/null
|
|
|
|
# Summary
|
|
echo -e "\n=== Test Summary ==="
|
|
echo -e "${GREEN}Passed: $PASS${NC}"
|
|
echo -e "${RED}Failed: $FAIL${NC}"
|
|
|
|
if [ $FAIL -eq 0 ]; then
|
|
echo -e "\n${GREEN}All tests passed!${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "\n${RED}Some tests failed${NC}"
|
|
exit 1
|
|
fi |