- research: searches SearXNG, reads the best pages through the reader, has the model list the server's variants, then checks every Docker image and Steam app it named for real before an admin sees it. - build: first boot of the variant's images (skipping ones that need root), a draft by the model, then the draft deployed with the node-agent's BootTest like CI does; crashes, error lines and saves outside /server go back to the model, three boots at most. - worker: polls the panel's builder queue (outbound only), runs research or build in a fresh clone, streams the output as the job log, and opens the result as a pull request from gbr-bot. - Dockerfile.builder, a workflow publishing gbr-builder:latest, compose and env files for the builder VM, and BUILDER.md. draft now keeps its conversation in a drafter, so build can send boot failures back to the same model session. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
1.8 KiB
Go
51 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestBootFailureKeepsVerdictAndServerOutput(t *testing.T) {
|
|
out := "[boot-test] deploying boottest-valheim (cm2network/steamcmd)\n" +
|
|
"[boot-test] container started; waiting for ready pattern /Game server connected/\n" +
|
|
"[boot-test] FAILED: container exited before it was ready\n" +
|
|
"---- last 2 log lines ----\n" +
|
|
"Unknown argument --save-dir\n" +
|
|
"Usage: valheim_server.x86_64 ...\n"
|
|
got := bootFailure(out)
|
|
if !strings.Contains(got, "failed: FAILED: container exited before it was ready") {
|
|
t.Errorf("verdict missing: %s", got)
|
|
}
|
|
if !strings.Contains(got, "Unknown argument --save-dir") || strings.Contains(got, "deploying boottest") {
|
|
t.Errorf("want only the server's last lines, got: %s", got)
|
|
}
|
|
if v := bootVerdict("[boot-test] PASSED: READY: Game server connected"); v != "PASSED: READY: Game server connected" {
|
|
t.Errorf("verdict = %q", v)
|
|
}
|
|
}
|
|
|
|
func TestOutsideDirsSkipsSteamNoise(t *testing.T) {
|
|
r := &bootReport{ContainerChanges: []string{
|
|
"A /home/steam/.config/unity3d/IronGate/Valheim/worlds_local/w.db",
|
|
"A /home/steam/Steam/logs/connection_log.txt",
|
|
"C /home/steam/.steam/registry.vdf",
|
|
}}
|
|
got := outsideDirs(r)
|
|
if len(got) != 1 || got[0] != "/home/steam/.config/unity3d/IronGate/Valheim/worlds_local" {
|
|
t.Errorf("got %v", got)
|
|
}
|
|
if outsideDirs(nil) != nil {
|
|
t.Error("nil report should have no dirs")
|
|
}
|
|
}
|
|
|
|
func TestVariantNotes(t *testing.T) {
|
|
v := variant{Title: "Crossplay", Description: "PC + Xbox", StartupHint: "./valheim_server.x86_64 -crossplay", Ports: []string{"2456/udp"}}
|
|
got := variantNotes(v, "needs Xbox")
|
|
for _, want := range []string{"variant: Crossplay (PC + Xbox)", "documented startup: ./valheim_server.x86_64 -crossplay", "2456/udp", "the admin asked for: needs Xbox"} {
|
|
if !strings.Contains(got, want) {
|
|
t.Errorf("missing %q in %q", want, got)
|
|
}
|
|
}
|
|
}
|