Files
chess/test/README.md
T
lixen 664cf9654e
test / test (push) Canceled after 0s
test / e2e (push) Canceled after 0s
v0.16.0 import PGN, delete games, two-layout web client
2026-10-19 21:02:39 -04:00

273 lines
11 KiB
Markdown
Executable File

# Chess API Test Suite
This directory contains comprehensive test suites for the Chess API server, covering API functionality, database operations, authentication, and real-time updates.
## Prerequisites
- `jq` - JSON processor
- `curl` - HTTP client
- `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, either way:
# a) your own OS account owns the test database (peer authentication over
# the local socket, no password; create the role first if needed:
# sudo -u postgres createuser "$USER")
createdb chess_test
export CHESS_TEST_DSN='dbname=chess_test'
# b) a dedicated role with a password, over TCP (what CI uses)
sudo -u postgres psql -c "CREATE ROLE chess_test LOGIN PASSWORD 'chess_test'" \
-c "CREATE DATABASE chess_test OWNER chess_test"
export CHESS_TEST_DSN='postgres://chess_test:chess_test@localhost:5432/chess_test?sslmode=disable'
```
`run-test-server.sh` prints these steps when the variable is unset. The DSN
is libpq keyword/value or URL form, as for the server's `-dsn`.
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
```bash
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.
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; `WEB_PORT` also serves
the embedded web client and `MAIL_DIR` turns on password recovery with the
email written to that directory (both used by the end-to-end suite):
```bash
LOG_LEVEL=info LOG_HTTP=false test/run-test-server.sh bin/chess-server
WEB_PORT=9090 MAIL_DIR=/tmp/chess-mail test/run-test-server.sh bin/chess-server
```
### Pre-configured Users
| Username | Password | Email |
|----------|----------|-------|
| alice | AlicePass123 | alice@example.com |
| bob | BobPass456 | bob@example.com |
### Features
- Automatically initializes database schema
- Creates three test users
- Runs on port 8080 (API) and 9090 (Web UI)
- Development mode with relaxed rate limits
- Fixed JWT secret for consistent tokens
- Debug persistence and engine-queue logs by default
- Graceful shutdown on Ctrl+C
### Manual Testing Examples
```bash
# Login as alice
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"identifier":"alice","password":"AlicePass123"}'
# Create authenticated game
TOKEN="<jwt-from-login>"
curl -X POST http://localhost:8080/api/games \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"white":{"type":1},"black":{"type":2,"level":10}}'
```
## Test Suite Overview
| Test Suite | File | Coverage |
|------------|------|----------|
| 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 |
| End States | `test-endstate.sh` | Checkmate, stalemate, terminal custom positions |
| Replay | `test-replay.sh` | SAN history, PGN export, ETag/304, promotion, FEN validation, cursor-paged listing |
| Draws & Resignation | `test-draw.sh` | Automatic draws, offers (human and computer), resignation and authorization, long-poll wake-up, concessions and claim control, server version, hand-deleted game row |
| Web client (end-to-end) | `e2e/` | Playwright in Chromium against the embedded web client: play, My games, replay controls and keyboard, autoplay, FEN/PGN export and download compared with the API, deep links, device list |
| Test Server | `run-test-server.sh` | Pre-populated test environment |
## 1. API Functionality Tests (`test-api.sh`)
Tests core game mechanics and API endpoints.
### Running the test
```bash
# Terminal 1: Start server in development mode
test/run-test-server.sh bin/chess-server
# Direct (no cleanup required): bin/chess-server -dev
# Terminal 2: Run API tests
test/test-api.sh
```
### Coverage
- **Game Creation**: Human vs Human, Human vs Computer, Computer vs Computer
- **Move Validation**: Legal/illegal moves, UCI notation
- **Computer Play**: Async engine moves with "cccc" trigger
- **Undo System**: Single and multiple move reversal
- **Player Configuration**: Dynamic player type changes
- **Rate Limiting**: 20 req/s in dev mode
- **Error Handling**: Invalid inputs, missing games, wrong content-types
- **Security**: Input validation, FEN injection prevention
## 2. Database & Authentication Tests (`test-db.sh`)
Tests user management, authentication, and persistence via API integration.
**Requires Running Server Script**
### Running the test
```bash
# Terminal 1: Start test server with database
# 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
```
### Coverage
- **User Registration**: Account creation, password hashing
- **Duplicate Prevention**: Username/email uniqueness
- **Authentication**: Login with JWT generation
- **Token Validation**: JWT parsing and claims verification
- **Password Security**: Argon2id hashing, complexity requirements
- **Case Sensitivity**: Case-insensitive username/email matching
- **Database Schema**: Table creation, constraints, indexes
### Test Flow
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. Leaves cleanup (dropping tables) to `run-test-server.sh`
## 3. Long-Polling Tests (`test-longpoll.sh`)
Tests real-time game updates via HTTP long-polling.
### Running the test
```bash
# Terminal 1: Start server with storage
test/run-test-server.sh bin/chess-server
# Direct (table cleanup required): CHESS_DSN="$CHESS_TEST_DSN" bin/chess-server -dev
# Terminal 2: Run long-polling tests
test/test-longpoll.sh
```
### Coverage
- **Basic Long-Polling**: Wait for game state changes
- **Multi-Client**: Multiple simultaneous waiters
- **Timeout Behavior**: 25-second timeout verification
- **Immediate Response**: No wait when state already changed
- **Connection Handling**: Client disconnect cleanup
- **Game Deletion**: Notification on game removal
- **Move Detection**: Accurate move count tracking
### Test Scenarios
1. **Single Waiter**: Client waits, receives update after move
2. **Multiple Waiters**: 3 clients wait, all receive notification
3. **Timeout**: Verify 25-second timeout with valid response
4. **Skip Wait**: Immediate return when moveCount outdated
5. **Disconnection**: Proper cleanup on client disconnect
## Replay Tests (`test-replay.sh`)
Exercises the replay API over HTTP with human-vs-human games, so no engine
search is involved. Each run registers a fresh account, so it can be repeated
against the same server.
```bash
# Terminal 1
test/run-test-server.sh bin/chess-server
# Terminal 2
test/test-replay.sh
```
Covers SAN and results in the history, the PGN attachment (tag order,
movetext, `?ply=`), `ETag`/`If-None-Match`, castling and en passant notation,
promotion (a missing piece is rejected, `g8=N` from the custom position that
reported the web-client bug), rejected starting FENs, and cursor paging with
`status`/`color` filters. `API_DELAY` (seconds, default `0.06`) keeps it under
the dev-mode rate limit.
## Draw and Resignation Tests (`test-draw.sh`)
Plays short human-vs-human lines, switching a side to the computer where the
computer's answer to a draw offer is tested, so the only engine work is two
short evaluations. Each run registers two fresh accounts and can be repeated
against the same server.
```bash
test/test-draw.sh
```
Covers the automatic draws (K+B v K after a capture, a knight shuffle
repeated three times, the hundredth quiet ply, a drawn starting position),
undo after a draw, resignation (side inference, hot-seat ambiguity, a side
claimed by another user), draw offers between humans (standing offer,
decline, one offer per move, acceptance waking a long-poll, lapse on the
opponent's move), the computer declining early, accepting in a level
position and declining when a queen up, concessions (an agreed draw final in
a hot-seat game; between two players no takeback, no anonymous undo, no
reconfiguration, a final resignation, unload only by a player; against the
computer the claimant undoes a resignation and history and PGN keep it), an
unknown route answered with `NOT_FOUND`, `/health` reporting the build, and a
game whose row is deleted with
psql (needs `CHESS_TEST_DSN` and `psql`; the server unloads the game and
stays healthy).
## Web client end-to-end tests (`e2e/`)
Playwright drives the embedded web client in Chromium against a running
server with PostgreSQL and Stockfish: it plays a short game, lists it under
My games, replays it with the buttons and the keyboard, autoplays to the end,
compares the FEN and PGN it exports (copy and download) with the API, follows
a deep link to a checkmate, steps back through the browser history, replays
an anonymous game from the device list, checks that a phone-sized viewport
holds the board and the controls without scrolling, and resets a forgotten
password through the link in the emailed message (needs `MAIL_DIR`).
Requirements: Node.js 20+ and a Chromium that Playwright can run.
```bash
# Terminal 1: the test server with the web client and mail to a directory
WEB_PORT=9090 MAIL_DIR=/tmp/chess-mail test/run-test-server.sh bin/chess-server
# Terminal 2, once
cd test/e2e && npm install && npx playwright install chromium
# Terminal 2: run
CHESS_E2E_MAIL_DIR=/tmp/chess-mail npm test # or, from the repository root: make test-e2e
```
Environment:
- `CHESS_E2E_WEB` (default `http://localhost:9090`): the web client's origin
- `CHESS_E2E_API` (default `http://localhost:8080`): the API's origin, used
to register users, create games and fetch what the client should export
- `CHESS_E2E_CHROMIUM`: path to a Chromium binary when
`npx playwright install` is not possible (an already installed browser)
- `CHESS_E2E_MAIL_DIR`: the server's `-mail-dir` (`MAIL_DIR` of the test
server); the password-reset test reads the link from the newest file and
is skipped when unset
Each test registers its own user or plays anonymously, so the suite can be
repeated against the same server. The engine plays at level 0 with a 100 ms
search, so a run takes about ten seconds. On failure Playwright keeps a trace
under `test/e2e/test-results/`; open it with `npx playwright show-trace`.