Feature: Dynamic command discovery and enhanced RPC testing #3
@@ -2,19 +2,27 @@ name: Smoke tests
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
smoke:
|
||||
name: Build and smoke test
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_DB: ./mudserver.db.test
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
- name: Install needed tools
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
run: |
|
||||
set -e
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends openssh-client netcat-openbsd ca-certificates curl
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build
|
||||
run: cargo build
|
||||
@@ -22,5 +30,143 @@ jobs:
|
||||
- name: Validate world data
|
||||
run: ./target/debug/mudtool validate -w ./world
|
||||
|
||||
- name: Run smoke tests
|
||||
run: ./run-tests.sh
|
||||
- name: Reset smoke database
|
||||
run: rm -f "$TEST_DB"
|
||||
|
||||
- name: Smoke - new player and basics
|
||||
run: |
|
||||
set -euo pipefail
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
MUD_PID=$!
|
||||
trap 'kill $MUD_PID 2>/dev/null || true' EXIT
|
||||
bash scripts/ci/wait-for-tcp.sh 127.0.0.1 2222
|
||||
set +e
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
1
|
||||
1
|
||||
look
|
||||
stats
|
||||
go south
|
||||
go down
|
||||
go north
|
||||
talk barkeep
|
||||
go south
|
||||
go south
|
||||
examine thief
|
||||
attack thief
|
||||
flee
|
||||
quit
|
||||
EOF
|
||||
r=$?
|
||||
set -e
|
||||
[[ $r -eq 0 || $r -eq 255 ]]
|
||||
|
||||
- name: Smoke - persistence (reconnect)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
MUD_PID=$!
|
||||
trap 'kill $MUD_PID 2>/dev/null || true' EXIT
|
||||
bash scripts/ci/wait-for-tcp.sh 127.0.0.1 2222
|
||||
set +e
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
look
|
||||
stats
|
||||
quit
|
||||
EOF
|
||||
r=$?
|
||||
set -e
|
||||
[[ $r -eq 0 || $r -eq 255 ]]
|
||||
|
||||
- name: Smoke - mudtool admin
|
||||
run: |
|
||||
set -euo pipefail
|
||||
./target/debug/mudtool -d "$TEST_DB" players list
|
||||
./target/debug/mudtool -d "$TEST_DB" players set-admin smoketest true
|
||||
./target/debug/mudtool -d "$TEST_DB" players show smoketest
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open false
|
||||
./target/debug/mudtool -d "$TEST_DB" settings list
|
||||
|
||||
- name: Smoke - in-game admin
|
||||
run: |
|
||||
set -euo pipefail
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
MUD_PID=$!
|
||||
trap 'kill $MUD_PID 2>/dev/null || true' EXIT
|
||||
bash scripts/ci/wait-for-tcp.sh 127.0.0.1 2222
|
||||
set +e
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
admin help
|
||||
admin list
|
||||
admin registration on
|
||||
admin info smoketest
|
||||
quit
|
||||
EOF
|
||||
r=$?
|
||||
set -e
|
||||
[[ $r -eq 0 || $r -eq 255 ]]
|
||||
|
||||
- name: Smoke - registration gate
|
||||
run: |
|
||||
set -euo pipefail
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open false
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
MUD_PID=$!
|
||||
trap 'kill $MUD_PID 2>/dev/null || true' EXIT
|
||||
bash scripts/ci/wait-for-tcp.sh 127.0.0.1 2222
|
||||
set +e
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 newplayer@localhost <<'EOF'
|
||||
quit
|
||||
EOF
|
||||
r=$?
|
||||
set -e
|
||||
[[ $r -eq 0 || $r -eq 255 ]]
|
||||
|
||||
- name: Smoke - tick-based combat
|
||||
run: |
|
||||
set -euo pipefail
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open true
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete smoketest
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
MUD_PID=$!
|
||||
trap 'kill $MUD_PID 2>/dev/null || true' EXIT
|
||||
bash scripts/ci/wait-for-tcp.sh 127.0.0.1 2222
|
||||
set +e
|
||||
(
|
||||
echo "1"
|
||||
echo "1"
|
||||
echo "go south"
|
||||
echo "go down"
|
||||
echo "go south"
|
||||
echo "attack thief"
|
||||
sleep 8
|
||||
echo "stats"
|
||||
echo "quit"
|
||||
) | ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost
|
||||
r=$?
|
||||
set -e
|
||||
[[ $r -eq 0 || $r -eq 255 ]]
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open true
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete smoketest
|
||||
|
||||
- name: Smoke - JSON-RPC list_commands
|
||||
run: |
|
||||
set -euo pipefail
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
MUD_PID=$!
|
||||
trap 'kill $MUD_PID 2>/dev/null || true' EXIT
|
||||
bash scripts/ci/wait-for-tcp.sh 127.0.0.1 2222
|
||||
set +e
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 rpctest@localhost <<'EOF'
|
||||
1
|
||||
1
|
||||
quit
|
||||
EOF
|
||||
r=$?
|
||||
set -e
|
||||
[[ $r -eq 0 || $r -eq 255 ]]
|
||||
echo '{"_jsonrpc": "2.0", "method": "login", "params": {"username": "rpctest"}, "id": 1}' | nc -w 2 localhost 2223 > rpc_resp.json
|
||||
echo '{"_jsonrpc": "2.0", "method": "list_commands", "params": {}, "id": 2}' | nc -w 2 localhost 2223 >> rpc_resp.json
|
||||
grep -q '"shop"' rpc_resp.json
|
||||
rm rpc_resp.json
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete rpctest
|
||||
|
||||
92
TESTING.md
92
TESTING.md
@@ -6,9 +6,9 @@
|
||||
./run-tests.sh
|
||||
```
|
||||
|
||||
This builds the server and mudtool, starts the server with a temporary DB, runs the smoke test below (new player, persistence, admin, registration gate, combat), then cleans up. Use it locally to match what Gitea Actions run on push/pull_request. The script uses `MUD_TEST_DB` (default `./mudserver.db.test`) so it does not overwrite your normal `mudserver.db`.
|
||||
This builds the server and mudtool, starts the server with a temporary DB, and runs the same sequence as the smoke steps in [`.gitea/workflows/smoke-tests.yml`](.gitea/workflows/smoke-tests.yml) (new player, persistence, mudtool admin, in-game admin, registration gate, tick combat), then cleans up. Use `MUD_TEST_DB` (default `./mudserver.db.test`) so you do not overwrite your normal `mudserver.db`.
|
||||
|
||||
Prerequisites: Rust toolchain (cargo), ssh client. In CI, Rust is installed by the workflow.
|
||||
Prerequisites: Rust toolchain (cargo), OpenSSH client, and OpenBSD `nc` (`netcat-openbsd` on Debian/Ubuntu) for [`scripts/ci/wait-for-tcp.sh`](scripts/ci/wait-for-tcp.sh). CI installs these explicitly before the smoke steps.
|
||||
|
||||
---
|
||||
|
||||
@@ -247,90 +247,4 @@ Run through the checks below before every commit to ensure consistent feature co
|
||||
|
||||
## Quick Smoke Test Script
|
||||
|
||||
The canonical implementation is **`./run-tests.sh`** (see top of this file). The following is the same sequence for reference; when writing or extending tests, keep `run-tests.sh` and this section in sync.
|
||||
|
||||
```bash
|
||||
# Start server in background (use -d for test DB so you don't overwrite mudserver.db)
|
||||
TEST_DB=./mudserver.db.test
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
SERVER_PID=$!
|
||||
sleep 2
|
||||
|
||||
# Test 1: New player creation + basic commands
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
1
|
||||
1
|
||||
look
|
||||
stats
|
||||
go north
|
||||
talk barkeep
|
||||
go south
|
||||
go south
|
||||
examine thief
|
||||
attack thief
|
||||
flee
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 2: Persistence - reconnect
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
look
|
||||
stats
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 3: Admin via mudtool (use same test DB)
|
||||
./target/debug/mudtool -d "$TEST_DB" players list
|
||||
./target/debug/mudtool -d "$TEST_DB" players set-admin smoketest true
|
||||
./target/debug/mudtool -d "$TEST_DB" players show smoketest
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open false
|
||||
./target/debug/mudtool -d "$TEST_DB" settings list
|
||||
|
||||
# Test 4: Admin commands in-game
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
admin help
|
||||
admin list
|
||||
admin registration on
|
||||
admin info smoketest
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 5: Registration gate
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open false
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 newplayer@localhost <<'EOF'
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 6: Tick-based combat (connect and wait for ticks)
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open true
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete smoketest
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
1
|
||||
1
|
||||
go south
|
||||
go south
|
||||
attack thief
|
||||
EOF
|
||||
# Wait for several combat ticks to resolve
|
||||
sleep 8
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
|
||||
stats
|
||||
quit
|
||||
EOF
|
||||
# Verify XP changed (combat happened via ticks)
|
||||
|
||||
# Test 7: JSON-RPC interface and dynamic command list
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 rpctest@localhost <<'EOF'
|
||||
1
|
||||
1
|
||||
quit
|
||||
EOF
|
||||
echo '{"_jsonrpc": "2.0", "method": "login", "params": {"username": "rpctest"}, "id": 1}' | nc -w 2 localhost 2223
|
||||
echo '{"_jsonrpc": "2.0", "method": "list_commands", "params": {}, "id": 2}' | nc -w 2 localhost 2223
|
||||
|
||||
# Cleanup
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open true
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete smoketest
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete rpctest
|
||||
kill $SERVER_PID
|
||||
```
|
||||
**CI:** each scenario is a separate step in [`.gitea/workflows/smoke-tests.yml`](.gitea/workflows/smoke-tests.yml) (each SSH step starts `mudserver`, runs the block, stops it; the same `TEST_DB` file carries state between steps). The last step exercises JSON-RPC `login` / `list_commands` on port 2223 (expects `shop` in the command list). **Local:** **`./run-tests.sh`** runs the full sequence in one process. When you add or change coverage, update the workflow steps and `run-tests.sh` together, and keep the checklist sections above aligned.
|
||||
|
||||
17
run-tests.sh
17
run-tests.sh
@@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
TEST_DB=${MUD_TEST_DB:-./mudserver.db.test}
|
||||
SERVER_PID=
|
||||
|
||||
# SSH returns 255 when MUD closes connection after quit — treat as success
|
||||
ssh_mud() {
|
||||
set +e
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 "$@"
|
||||
@@ -23,9 +25,8 @@ trap cleanup EXIT
|
||||
cargo build
|
||||
RUST_LOG=info ./target/debug/mudserver -d "$TEST_DB" &
|
||||
SERVER_PID=$!
|
||||
sleep 2
|
||||
bash "$ROOT/scripts/ci/wait-for-tcp.sh" 127.0.0.1 2222
|
||||
|
||||
# Test 1: New player creation + basic commands
|
||||
ssh_mud smoketest@localhost <<'EOF'
|
||||
1
|
||||
1
|
||||
@@ -43,21 +44,18 @@ flee
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 2: Persistence - reconnect
|
||||
ssh_mud smoketest@localhost <<'EOF'
|
||||
look
|
||||
stats
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 3: Admin via mudtool (use same test DB)
|
||||
./target/debug/mudtool -d "$TEST_DB" players list
|
||||
./target/debug/mudtool -d "$TEST_DB" players set-admin smoketest true
|
||||
./target/debug/mudtool -d "$TEST_DB" players show smoketest
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open false
|
||||
./target/debug/mudtool -d "$TEST_DB" settings list
|
||||
|
||||
# Test 4: Admin commands in-game
|
||||
ssh_mud smoketest@localhost <<'EOF'
|
||||
admin help
|
||||
admin list
|
||||
@@ -66,16 +64,13 @@ admin info smoketest
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 5: Registration gate
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open false
|
||||
ssh_mud newplayer@localhost <<'EOF'
|
||||
quit
|
||||
EOF
|
||||
|
||||
# Test 6: Tick-based combat (connect and wait for ticks)
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open true
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete smoketest
|
||||
# Use subshell to pipe commands with a delay between them while staying connected
|
||||
(
|
||||
echo "1"
|
||||
echo "1"
|
||||
@@ -88,9 +83,6 @@ EOF
|
||||
echo "quit"
|
||||
) | ssh_mud smoketest@localhost
|
||||
|
||||
# Test 7: JSON-RPC interface and dynamic command list
|
||||
# We need an active player for the login to succeed in mud-mcp style
|
||||
# (though list_commands doesn't require session, the MCP does login on startup)
|
||||
ssh_mud rpctest@localhost <<'EOF'
|
||||
1
|
||||
1
|
||||
@@ -107,7 +99,6 @@ if ! grep -q '"shop"' rpc_resp.json; then
|
||||
fi
|
||||
rm rpc_resp.json
|
||||
|
||||
# Cleanup (trap handles server kill)
|
||||
./target/debug/mudtool -d "$TEST_DB" settings set registration_open true
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete smoketest
|
||||
./target/debug/mudtool -d "$TEST_DB" players delete rpctest
|
||||
|
||||
13
scripts/ci/wait-for-tcp.sh
Executable file
13
scripts/ci/wait-for-tcp.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
host=${1:-127.0.0.1}
|
||||
port=${2:-2222}
|
||||
max_attempts=${3:-30}
|
||||
for _ in $(seq 1 "$max_attempts"); do
|
||||
if nc -z -w 1 "$host" "$port" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo "timeout waiting for $host:$port" >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user