v0.12.0 migrate sqlite3 to psql18, updated auth, deploy docs, account and replay updates
test / test (push) Canceled after 0s
test / test (push) Canceled after 0s
This commit is contained in:
1 parent
5d2be4abb2
commit
d0326b059e
66 files changed
+4016
-2433
No files matched your search
+26
-9
@@ -6,9 +6,26 @@ This directory contains comprehensive test suites for the Chess API server, cove
|
||||
|
||||
- `jq` - JSON processor
|
||||
- `curl` - HTTP client
|
||||
- `sqlite3` - SQLite CLI (for database tests)
|
||||
- `psql` - PostgreSQL client (for database tests)
|
||||
- `base64` - Base64 encoder (for JWT tests)
|
||||
- Stockfish in `PATH`
|
||||
- Compiled `bin/chess-server` binary (or pass another path to the scripts)
|
||||
- A **disposable** PostgreSQL database named by `CHESS_TEST_DSN`
|
||||
|
||||
`CHESS_TEST_DSN` must be a libpq-compatible connection string, because the
|
||||
scripts pass it to both `chess-server` and `psql`. The test server drops every
|
||||
chess table in that database on start and exit, so never point it at real data.
|
||||
|
||||
```bash
|
||||
# One-time setup as a PostgreSQL superuser
|
||||
psql -U postgres -c "CREATE ROLE chess_test LOGIN PASSWORD 'chess_test'"
|
||||
psql -U postgres -c "CREATE DATABASE chess_test OWNER chess_test"
|
||||
|
||||
export CHESS_TEST_DSN='postgres://chess_test:chess_test@localhost:5432/chess_test?sslmode=disable'
|
||||
```
|
||||
|
||||
The same variable enables the Go database tests (`go test ./...`), which create
|
||||
and drop an isolated schema per test and are skipped when it is unset.
|
||||
|
||||
## Running the test server
|
||||
From repo root
|
||||
@@ -17,8 +34,8 @@ test/run-test-server.sh
|
||||
```
|
||||
|
||||
Pass the binary path as the first argument when it is not at `bin/chess-server`.
|
||||
The server runs with `-dev`, debug logging, HTTP request logging, and relaxed rate limiting. WAL is enabled for every persistent server mode.
|
||||
Will clean up test database and temporary files, so it's preferred for clean testing.
|
||||
The server runs with `-dev`, debug logging, HTTP request logging, and relaxed rate limiting.
|
||||
It drops the test tables on exit, so it's preferred for clean testing.
|
||||
Can be used for all the tests.
|
||||
|
||||
Logging can be adjusted without editing the script:
|
||||
@@ -63,7 +80,7 @@ curl -X POST http://localhost:8080/games \
|
||||
| API Functionality | `test-api.sh` | Game operations, moves, undo, rate limiting |
|
||||
| Database & Auth | `test-db.sh` | User registration, login, JWT tokens, persistence |
|
||||
| Long-Polling | `test-longpoll.sh` | Real-time updates, wait behavior, timeouts |
|
||||
| Test Server | `test-db-server.sh` | Pre-populated test environment |
|
||||
| Test Server | `run-test-server.sh` | Pre-populated test environment |
|
||||
|
||||
## 1. API Functionality Tests (`test-api.sh`)
|
||||
|
||||
@@ -97,8 +114,8 @@ Tests user management, authentication, and persistence via API integration.
|
||||
### Running the test
|
||||
```bash
|
||||
# Terminal 1: Start test server with database
|
||||
# Server is running with -dev and persistent WAL storage
|
||||
test/test-db-server.sh bin/chess-server
|
||||
# Server is running with -dev and PostgreSQL storage
|
||||
test/run-test-server.sh bin/chess-server
|
||||
|
||||
# Terminal 2: Run API integration tests
|
||||
test/test-db.sh bin/chess-server
|
||||
@@ -114,12 +131,12 @@ test/test-db.sh bin/chess-server
|
||||
- **Database Schema**: Table creation, constraints, indexes
|
||||
|
||||
### Test Flow
|
||||
1. Creates temporary `test.db` with schema
|
||||
1. Re-runs the idempotent schema initialization against `CHESS_TEST_DSN`
|
||||
2. Registers test users (alice, bob, charlie)
|
||||
3. Tests authentication endpoints
|
||||
4. Validates JWT tokens and claims
|
||||
5. Tests duplicate user prevention
|
||||
6. Cleans up test database
|
||||
6. Leaves cleanup (dropping tables) to `run-test-server.sh`
|
||||
|
||||
## 3. Long-Polling Tests (`test-longpoll.sh`)
|
||||
|
||||
@@ -129,7 +146,7 @@ Tests real-time game updates via HTTP long-polling.
|
||||
```bash
|
||||
# Terminal 1: Start server with storage
|
||||
test/run-test-server.sh bin/chess-server
|
||||
# Direct (test.db cleanup required): bin/chess-server -dev -storage-path test.db
|
||||
# Direct (table cleanup required): CHESS_DSN="$CHESS_TEST_DSN" bin/chess-server -dev
|
||||
|
||||
# Terminal 2: Run long-polling tests
|
||||
test/test-longpoll.sh
|
||||
|
||||
+15
-12
@@ -4,7 +4,10 @@ set -e
|
||||
|
||||
# Configuration
|
||||
CHESS_SERVER_EXEC=${1:-"bin/chess-server"}
|
||||
TEST_DB="test.db"
|
||||
# A DISPOSABLE database: every chess table in it is dropped on start and exit.
|
||||
# Use a libpq-compatible DSN; test-db.sh also passes it to psql.
|
||||
: "${CHESS_TEST_DSN:?set CHESS_TEST_DSN to a disposable PostgreSQL database}"
|
||||
export CHESS_DSN="$CHESS_TEST_DSN"
|
||||
PID_FILE="/tmp/chess-server_test.pid"
|
||||
API_PORT=${API_PORT:-8080}
|
||||
LOG_LEVEL=${LOG_LEVEL:-debug}
|
||||
@@ -41,9 +44,9 @@ cleanup() {
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
|
||||
# Clean up database files
|
||||
echo "Removing test database files..."
|
||||
rm -f "$TEST_DB" "${TEST_DB}-wal" "${TEST_DB}-shm"
|
||||
# Drop test tables
|
||||
echo "Dropping test database tables..."
|
||||
"$CHESS_SERVER_EXEC" db delete -confirm >/dev/null || true
|
||||
|
||||
echo -e "${GREEN}Cleanup complete${NC}"
|
||||
}
|
||||
@@ -51,13 +54,14 @@ cleanup() {
|
||||
# Set up trap for cleanup on exit
|
||||
trap cleanup EXIT SIGINT SIGTERM
|
||||
|
||||
# Clean slate - remove any existing test DB files
|
||||
# Clean slate - drop tables left by an earlier run
|
||||
echo -e "${CYAN}Preparing test environment...${NC}"
|
||||
rm -f "$TEST_DB" "${TEST_DB}-wal" "${TEST_DB}-shm" "$PID_FILE"
|
||||
rm -f "$PID_FILE"
|
||||
"$CHESS_SERVER_EXEC" db delete -confirm
|
||||
|
||||
# Initialize database
|
||||
echo -e "${CYAN}Initializing test database...${NC}"
|
||||
"$CHESS_SERVER_EXEC" db init -path "$TEST_DB"
|
||||
"$CHESS_SERVER_EXEC" db init
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Failed to initialize database${NC}"
|
||||
exit 1
|
||||
@@ -65,14 +69,14 @@ fi
|
||||
|
||||
# Add test users
|
||||
echo -e "${CYAN}Adding test users...${NC}"
|
||||
"$CHESS_SERVER_EXEC" db user add -path "$TEST_DB" \
|
||||
"$CHESS_SERVER_EXEC" db user add \
|
||||
-username alice -email alice@test.com -password AlicePass123
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Failed to create user alice${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$CHESS_SERVER_EXEC" db user add -path "$TEST_DB" \
|
||||
"$CHESS_SERVER_EXEC" db user add \
|
||||
-username bob -email bob@test.com -password BobSecure456
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Failed to create user bob${NC}"
|
||||
@@ -90,9 +94,9 @@ echo -e "${CYAN}╚════════════════════
|
||||
echo ""
|
||||
echo "Configuration:"
|
||||
echo " Executable: $CHESS_SERVER_EXEC"
|
||||
echo " Database: $TEST_DB"
|
||||
echo " Database: \$CHESS_TEST_DSN (tables dropped on exit)"
|
||||
echo " Port: $API_PORT"
|
||||
echo " Mode: Development (relaxed rate limits; persistent WAL storage)"
|
||||
echo " Mode: Development (relaxed rate limits; PostgreSQL storage)"
|
||||
echo " Log level: $LOG_LEVEL (HTTP requests: $LOG_HTTP)"
|
||||
echo " Purpose: Backend for chess-server tests"
|
||||
echo " PID File: $PID_FILE"
|
||||
@@ -111,7 +115,6 @@ echo ""
|
||||
-dev \
|
||||
-log-level "$LOG_LEVEL" \
|
||||
-log-http="$LOG_HTTP" \
|
||||
-storage-path "$TEST_DB" \
|
||||
-api-port "$API_PORT" \
|
||||
-pid "$PID_FILE" \
|
||||
-pid-lock
|
||||
+21
-18
@@ -8,8 +8,11 @@
|
||||
|
||||
BASE_URL="http://localhost:8080"
|
||||
API_URL="${BASE_URL}/api/v1"
|
||||
TEST_DB="test.db"
|
||||
CHESS_SERVER_EXEC=${1:-"bin/chess-server"}
|
||||
# Same disposable database as the running test server (see run-test-server.sh).
|
||||
# Use a libpq-compatible DSN: it is passed to both chess-server and psql.
|
||||
: "${CHESS_TEST_DSN:?set CHESS_TEST_DSN to the test server database}"
|
||||
export CHESS_DSN="$CHESS_TEST_DSN"
|
||||
API_DELAY=${API_DELAY:-50}
|
||||
|
||||
# Colors
|
||||
@@ -121,7 +124,7 @@ api_request() {
|
||||
}
|
||||
|
||||
# Check dependencies
|
||||
for cmd in jq sqlite3 curl; do
|
||||
for cmd in jq psql curl; do
|
||||
if ! command -v $cmd &> /dev/null; then
|
||||
echo -e "${RED}Error: $cmd is required but not installed${NC}"
|
||||
exit 1
|
||||
@@ -145,7 +148,7 @@ fi
|
||||
print_header "Database & User Management Test Suite"
|
||||
echo "Server: $BASE_URL"
|
||||
echo "Executable: $CHESS_SERVER_EXEC"
|
||||
echo "Test Database (server-managed): $TEST_DB"
|
||||
echo "Test Database: \$CHESS_TEST_DSN (server-managed)"
|
||||
echo ""
|
||||
|
||||
# ==============================================================================
|
||||
@@ -153,11 +156,11 @@ print_header "SECTION 1: CLI User Operations"
|
||||
# ==============================================================================
|
||||
|
||||
test_case "1.1: database initialization"
|
||||
assert_command "$CHESS_SERVER_EXEC db init -path $TEST_DB" 0 "initialize database"
|
||||
assert_command "$CHESS_SERVER_EXEC db init" 0 "initialize database"
|
||||
|
||||
# Create testuser1 first (not charlie)
|
||||
test_case "1.2: Add First User via CLI"
|
||||
OUTPUT=$($CHESS_SERVER_EXEC db user add -path "$TEST_DB" -username "testuser1" \
|
||||
OUTPUT=$($CHESS_SERVER_EXEC db user add -username "testuser1" \
|
||||
-email "testuser1@test.com" -password "TestPass123" 2>&1)
|
||||
if echo "$OUTPUT" | grep -qi "User created successfully"; then
|
||||
echo -e "${GREEN} ✓ User created: testuser1${NC}"
|
||||
@@ -168,7 +171,7 @@ else
|
||||
fi
|
||||
|
||||
test_case "1.3: Add Second User"
|
||||
OUTPUT=$($CHESS_SERVER_EXEC db user add -path "$TEST_DB" -username "testuser2" \
|
||||
OUTPUT=$($CHESS_SERVER_EXEC db user add -username "testuser2" \
|
||||
-password "TestPass456" 2>&1)
|
||||
if echo "$OUTPUT" | grep -qi "User created successfully"; then
|
||||
echo -e "${GREEN} ✓ User created: testuser2${NC}"
|
||||
@@ -180,7 +183,7 @@ fi
|
||||
|
||||
# Now test duplicate prevention with an existing user
|
||||
test_case "1.4: Duplicate Username Prevention"
|
||||
assert_command "$CHESS_SERVER_EXEC db user add -path $TEST_DB -username testuser1 -password TestPass789" 1 \
|
||||
assert_command "$CHESS_SERVER_EXEC db user add -username testuser1 -password TestPass789" 1 \
|
||||
"Duplicate username rejected"
|
||||
|
||||
test_case "1.5: Login with Case-Insensitive Username (ALICE)"
|
||||
@@ -196,11 +199,11 @@ else
|
||||
fi
|
||||
|
||||
test_case "1.6: Update User Email"
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-email -path $TEST_DB -username testuser2 -email testuser2_updated@test.com" 0 \
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-email -username testuser2 -email testuser2_updated@test.com" 0 \
|
||||
"Email update"
|
||||
|
||||
test_case "1.7: Update User Password"
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-password -path $TEST_DB -username testuser2 -password NewPass789" 0 \
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-password -username testuser2 -password NewPass789" 0 \
|
||||
"Password update"
|
||||
|
||||
test_case "2.1: Health Check"
|
||||
@@ -324,7 +327,7 @@ test_case "4.1: Verify Game Storage with User ID"
|
||||
if [ -n "$GAME_ID" ]; then
|
||||
sleep 0.5 # Allow async write
|
||||
|
||||
DB_WHITE_ID=$(sqlite3 "$TEST_DB" "SELECT white_player_id FROM games WHERE game_id = '$GAME_ID';" 2>/dev/null)
|
||||
DB_WHITE_ID=$(psql "$CHESS_TEST_DSN" -XAtqc "SELECT white_player_id FROM games WHERE game_id = '$GAME_ID';" 2>/dev/null)
|
||||
if [ "$DB_WHITE_ID" = "$USER_ID_ALICE" ]; then
|
||||
echo -e "${GREEN} ✓ User ID correctly persisted in database${NC}"
|
||||
((PASS++))
|
||||
@@ -335,7 +338,7 @@ if [ -n "$GAME_ID" ]; then
|
||||
fi
|
||||
|
||||
test_case "4.2: Query Games by User ID"
|
||||
GAMES_COUNT=$(sqlite3 "$TEST_DB" "SELECT COUNT(*) FROM games WHERE white_player_id = '$USER_ID_ALICE' OR black_player_id = '$USER_ID_ALICE';" 2>/dev/null)
|
||||
GAMES_COUNT=$(psql "$CHESS_TEST_DSN" -XAtqc "SELECT COUNT(*) FROM games WHERE white_player_id = '$USER_ID_ALICE' OR black_player_id = '$USER_ID_ALICE';" 2>/dev/null)
|
||||
if [ "$GAMES_COUNT" -ge "2" ]; then
|
||||
echo -e "${GREEN} ✓ User's games queryable: found $GAMES_COUNT games${NC}"
|
||||
((PASS++))
|
||||
@@ -350,7 +353,7 @@ print_header "SECTION 5: Password Operations"
|
||||
|
||||
# Now TEST_PASS2_NEW is defined, this test should work
|
||||
test_case "5.1: Update User Password via CLI for 'bob'"
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-password -path $TEST_DB -username $TEST_USER2 -password $TEST_PASS2_NEW" 0 \
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-password -username $TEST_USER2 -password $TEST_PASS2_NEW" 0 \
|
||||
"CLI password update for '$TEST_USER2'"
|
||||
|
||||
test_case "5.2: Login with NEW Password for 'bob'"
|
||||
@@ -373,11 +376,11 @@ STATUS=$(api_request POST "$API_URL/auth/login" \
|
||||
assert_status 401 "$STATUS" "Old password correctly rejected for '$TEST_USER2'"
|
||||
|
||||
test_case "5.4: Add new user '$TEST_USER_CLI' via CLI for hash test"
|
||||
assert_command "$CHESS_SERVER_EXEC db user add -path $TEST_DB -username $TEST_USER_CLI -password $TEST_PASS_CLI" 0 \
|
||||
assert_command "$CHESS_SERVER_EXEC db user add -username $TEST_USER_CLI -password $TEST_PASS_CLI" 0 \
|
||||
"Add user '$TEST_USER_CLI' for hash test"
|
||||
|
||||
test_case "5.5: CLI rejects unsupported hash format"
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-hash -path $TEST_DB -username $TEST_USER_CLI -hash '$UNSUPPORTED_HASH'" 1 \
|
||||
assert_command "$CHESS_SERVER_EXEC db user set-hash -username $TEST_USER_CLI -hash '$UNSUPPORTED_HASH'" 1 \
|
||||
"Unsupported bcrypt hash rejected by CLI"
|
||||
|
||||
# ==============================================================================
|
||||
@@ -409,7 +412,7 @@ test_case "6.2: Concurrent Registration Handling"
|
||||
wait
|
||||
|
||||
# Check only one user was created
|
||||
USER_COUNT=$(sqlite3 "$TEST_DB" "SELECT COUNT(*) FROM users WHERE username = 'concurrent';" 2>/dev/null)
|
||||
USER_COUNT=$(psql "$CHESS_TEST_DSN" -XAtqc "SELECT COUNT(*) FROM users WHERE username = 'concurrent';" 2>/dev/null)
|
||||
if [ "$USER_COUNT" = "1" ]; then
|
||||
echo -e "${GREEN} ✓ Concurrent registration handled correctly${NC}"
|
||||
((PASS++))
|
||||
@@ -420,15 +423,15 @@ fi
|
||||
|
||||
test_case "6.3: Delete User"
|
||||
# First, get a user to delete
|
||||
OUTPUT=$($CHESS_SERVER_EXEC db user add -path "$TEST_DB" -username "deleteme" \
|
||||
OUTPUT=$($CHESS_SERVER_EXEC db user add -username "deleteme" \
|
||||
-password "TempPass123" 2>&1)
|
||||
TEMP_ID=$(echo "$OUTPUT" | grep "ID:" | awk '{print $2}')
|
||||
|
||||
assert_command "$CHESS_SERVER_EXEC db user delete -path $TEST_DB -username deleteme" 0 \
|
||||
assert_command "$CHESS_SERVER_EXEC db user delete -username deleteme" 0 \
|
||||
"User deletion by username"
|
||||
|
||||
# Verify deletion
|
||||
USER_EXISTS=$(sqlite3 "$TEST_DB" "SELECT COUNT(*) FROM users WHERE user_id = '$TEMP_ID';" 2>/dev/null)
|
||||
USER_EXISTS=$(psql "$CHESS_TEST_DSN" -XAtqc "SELECT COUNT(*) FROM users WHERE user_id = '$TEMP_ID';" 2>/dev/null)
|
||||
if [ "$USER_EXISTS" = "0" ]; then
|
||||
echo -e "${GREEN} ✓ User successfully deleted from database${NC}"
|
||||
((PASS++))
|
||||
|
||||
Reference in new issue
Block a user