Files
SirRoboGarage/common_libs/test_framework/runner_process.nim
T
SirStone 7e1f1483a4 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>
2026-09-13 10:54:56 +02:00

63 lines
2.1 KiB
Nim

## BattleRunner Java subprocess — capture stdout JSON-lines output.
import std/[osproc, os, strutils, streams, times, net]
const
DefaultRunnerJar = "/home/davide/Projects/tank-royale/runner/examples/lib/robocode-tankroyale-runner.jar"
ScriptDir = currentSourcePath().parentDir() / ".." / ".." / "tools" / "battle_runner"
proc runBattleRunner*(serverUrl: string, botDirs: seq[string], rounds: int,
timeout: int = 30000): string =
## Starts TestBattleRunner as a subprocess. Returns captured stdout on success.
## Raises IOError on non-zero exit or TimeoutError on timeout.
let jar = getEnv("TR_BATTLE_RUNNER", DefaultRunnerJar)
let classDir = getEnv("TR_BATTLE_RUNNER_DIR", ScriptDir)
let args = @[
"-cp", classDir & ":" & jar,
"TestBattleRunner",
"--server-url", serverUrl,
"--rounds", $rounds,
"--bot-dirs", botDirs.join(",")
]
let p = startProcess("java", args = args,
options = {poUsePath, poStdErrToStdOut})
defer:
p.close()
let deadline = epochTime() + timeout.float / 1000.0
var stdout = ""
var line: string
# ponytail: poll instead of blocking readLine; 50ms sleep is fine for battle timescales
while epochTime() < deadline:
if p.peekExitCode() != -1:
# Process finished; drain remaining output without blocking
while p.outputStream.atEnd == false:
discard p.outputStream.readLine(line)
stdout.add(line & "\n")
break
sleep(50)
if epochTime() >= deadline and p.peekExitCode() == -1:
p.terminate()
raise newException(TimeoutError,
"BattleRunner timed out after " & $timeout & "ms")
let code = p.waitForExit()
if code != 0:
raise newException(IOError,
"BattleRunner exited with code " & $code & "\nOutput:\n" & stdout)
result = stdout
when isMainModule:
echo "runner_process.nim — usage:"
echo " runBattleRunner(serverUrl, botDirs, rounds, timeout)"
echo ""
echo "Env vars:"
echo " TR_BATTLE_RUNNER JAR path (default: " & DefaultRunnerJar & ")"
echo " TR_BATTLE_RUNNER_DIR class dir (default: tools/battle_runner/)"
echo ""
echo "Cannot self-test without a running TR server. Start one first."