docs(test_framework): add comprehensive integration test guide and fix runner blocking issue
- Document exception handling, zero-value BotResult trap, shared adversary bots - Add offline parsing example using parseServerOutput - Skip tests gracefully when JARs missing (guard before suite blocks) - Fix blocking readLine in runner_process.nim: poll with 50ms sleep + atEnd check (was preventing timeout enforcement, now blocks correctly during battle) - Add test task to QBot.nimble and config.nims setup docs to AGENTS.md - Add debug logging to TestBattleRunner for bot identity tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -49,3 +49,74 @@ Single-context layout. See `docs/agents/domain.md`.
|
||||
### NIM
|
||||
|
||||
This repsoitory's main language is Nim, when you need to work with nim use the /nim mcp.
|
||||
|
||||
---
|
||||
|
||||
## Writing tests for a bot
|
||||
|
||||
Framework lives at `common_libs/test_framework/`. Full docs: `common_libs/test_framework/README.md`.
|
||||
|
||||
### One-liner
|
||||
|
||||
```nim
|
||||
import test_framework/test_framework
|
||||
|
||||
let r = runBattle(@[myBotDir, adversaryDir], rounds = 10)
|
||||
```
|
||||
|
||||
`runBattle` blocks, returns `BattleResult`, raises on failure.
|
||||
|
||||
### Types
|
||||
|
||||
```
|
||||
BattleResult → bots, rounds: seq[RoundResult], results: seq[BotResult], winners: seq[string]
|
||||
BotResult → name, totalScore, rank, firstPlaces, survivalCount
|
||||
RoundResult → round, results: seq[BotRoundResult]
|
||||
BotRoundResult→ name, score, rank, survived
|
||||
```
|
||||
|
||||
### Shared adversaries
|
||||
|
||||
```nim
|
||||
const tfAdversaries = currentSourcePath().parentDir.parentDir.parentDir /
|
||||
"common_libs" / "test_framework" / "adversaries"
|
||||
const sittingDuck = tfAdversaries / "SittingDuck" # passive — does nothing
|
||||
const oscillator = tfAdversaries / "OscillatorBot" # fights back
|
||||
```
|
||||
|
||||
### Setup (once per garage)
|
||||
|
||||
**`tests/config.nims`**
|
||||
```nim
|
||||
--path:"../../common_libs" # adjust depth to match garage location in repo
|
||||
```
|
||||
|
||||
**`YourBot.nimble`** test task:
|
||||
```nim
|
||||
task test, "Run integration tests":
|
||||
exec "nim c -r --path:../common_libs tests/test_basic_battle.nim"
|
||||
```
|
||||
|
||||
### Skip when JARs are absent (put before any suite block)
|
||||
|
||||
```nim
|
||||
import std/os
|
||||
if not existsEnv("TR_SERVER_JAR") or not existsEnv("TR_BATTLE_RUNNER"):
|
||||
echo "Skipping: TR_SERVER_JAR / TR_BATTLE_RUNNER not set"
|
||||
quit(0)
|
||||
```
|
||||
|
||||
### Offline parsing (no Java needed)
|
||||
|
||||
```nim
|
||||
import test_framework/battle_result
|
||||
let r = parseServerOutput(rawJsonLines)
|
||||
```
|
||||
|
||||
### Exceptions
|
||||
|
||||
| Exception | Cause |
|
||||
|---|---|
|
||||
| `OSError` | Bot compilation failed |
|
||||
| `IOError` | Battle runner exited non-zero |
|
||||
| `TimeoutError` | Server startup (15s), compile (30s/bot), or battle runner timeout |
|
||||
|
||||
Reference in New Issue
Block a user