v0.12.0 migrate sqlite3 to psql18, updated auth, deploy docs, account and replay updates
test / test (push) Canceled after 0s

This commit is contained in:
lixen committed 2026-09-26 20:58:19 -04:00
1 parent 5d2be4abb2
commit d0326b059e
66 files changed
+4016 -2433

No files matched your search

+26 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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++))