feat: add shared integration test framework for garages (#126)
Implements: - BattleResult type and JSON-lines parser (#127) - TR server lifecycle manager (#128) - Bot compiler using nim c (#129) - runBattle() orchestrator (#130) - Example test in OscillatorBot_garage (#131) - Framework usage guide (#132) - TestBattleRunner.java for external server (#133) - BattleRunner process lifecycle (#134) Fix: runner_process.nim was redefining TimeoutError locally; now uses std/net.TimeoutError consistently with server_manager.nim.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
## TR server lifecycle manager — lazy singleton for integration tests.
|
||||
## Start with ensureServer(), query with getServerUrl().
|
||||
|
||||
import std/[osproc, net, os, strutils, times, streams, exitprocs]
|
||||
|
||||
const
|
||||
DefaultJar = "/home/davide/Projects/tank-royale/server/build/libs/robocode-tankroyale-server-0.35.5-all.jar"
|
||||
ReadySignal = "Starting server on port"
|
||||
StartupTimeout = 15.0 # seconds
|
||||
|
||||
var
|
||||
serverProc: Process = nil
|
||||
serverPort: int = 0
|
||||
|
||||
proc findFreePort(): int =
|
||||
let s = newSocket()
|
||||
s.bindAddr(Port(0))
|
||||
let (_, port) = s.getLocalAddr()
|
||||
result = port.int
|
||||
s.close()
|
||||
|
||||
proc ensureServer*() =
|
||||
if serverProc != nil: return
|
||||
|
||||
let jar = getEnv("TR_SERVER_JAR", DefaultJar)
|
||||
if not fileExists(jar):
|
||||
raise newException(IOError, "TR server JAR not found: " & jar &
|
||||
"\nSet TR_SERVER_JAR env var to override.")
|
||||
|
||||
serverPort = findFreePort()
|
||||
serverProc = startProcess("java",
|
||||
args = @["-jar", jar, "--port", $serverPort, "--enable-initial-position"],
|
||||
options = {poUsePath, poStdErrToStdOut})
|
||||
|
||||
exitprocs.addExitProc(proc() =
|
||||
if serverProc != nil:
|
||||
serverProc.terminate()
|
||||
serverProc.close()
|
||||
)
|
||||
|
||||
# Wait for ready signal
|
||||
let deadline = epochTime() + StartupTimeout
|
||||
var ready = false
|
||||
while epochTime() < deadline:
|
||||
var line: string
|
||||
discard serverProc.outputStream.readLine(line)
|
||||
if ReadySignal in line:
|
||||
ready = true
|
||||
break
|
||||
if not ready:
|
||||
serverProc.terminate()
|
||||
serverProc.close()
|
||||
serverProc = nil
|
||||
raise newException(TimeoutError, "TR server did not start within " & $StartupTimeout & "s")
|
||||
|
||||
proc getServerUrl*(): string =
|
||||
if serverPort == 0:
|
||||
raise newException(CatchableError, "Server not started — call ensureServer() first")
|
||||
"ws://localhost:" & $serverPort
|
||||
|
||||
when isMainModule:
|
||||
echo "Starting TR server..."
|
||||
ensureServer()
|
||||
echo "Server ready at: ", getServerUrl()
|
||||
echo "Sleeping 2s then exiting (addExitProc will kill server)..."
|
||||
os.sleep(2000)
|
||||
echo "Done."
|
||||
Reference in New Issue
Block a user