Files
gbr-games/cmd/gbrgames/research_test.go
T
gregandClaude Opus 5.5 f1271341ef
Validate game templates / validate (push) Successful in 36s
Validate game templates / boot-test (push) Successful in 1m11s
Validate game templates / publish (push) Skipped
feat(builder): repair existing templates, a weekly check that queues repairs, and eval
The builder could only create games; nothing noticed when a live template
stopped working, and there was no way to tell whether a builder change made
it better or worse.

- repair -id ID: boots an existing template as nodes run it; if it fails,
  the same investigation as for a draft runs and the model changes only what
  the diagnosis says. The worker handles "repair" jobs (gameId from the
  panel) and opens "fix(games): repair ..." on draft/<id>; a template that
  boots as it is reports "nothing to repair" and opens no PR. The boot and
  fix loop is now shared by builds and repairs.
- validate.yml runs weekly and boot-tests every game; failed games are sent
  to the panel (X-GBR-Event: games_boot_failed) to queue repairs.
- eval -ids all: builds games that already have a template from scratch,
  blind, and scores each draft against it (boots, same image and app, ports,
  ready line, settings found) into eval.md and eval.json.
- research skips our own sites, so neither research nor eval reads our
  templates back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 00:42:34 -04:00

126 lines
4.0 KiB
Go

package main
import "testing"
func TestPickPagesPrefersDocsAndOnePerSite(t *testing.T) {
hits := []searchHit{
{URL: "https://blog.example.com/example-server"},
{URL: "https://github.com/a/example-docker"},
{URL: "https://github.com/b/other"},
{URL: "https://hub.docker.com/r/x/example"},
{URL: "https://blog.example.com/example-server"},
}
got := pickPages(hits, 3)
if len(got) != 3 {
t.Fatalf("got %d pages", len(got))
}
if got[0].URL != "https://github.com/a/example-docker" || got[1].URL != "https://hub.docker.com/r/x/example" || got[2].URL != "https://blog.example.com/example-server" {
t.Errorf("order: %v", got)
}
}
func TestTrimToJSON(t *testing.T) {
if got := trimToJSON("Here you go:\n```json\n{\"a\": 1}\n```"); got != `{"a": 1}` {
t.Errorf("got %q", got)
}
}
func TestAppNameFromAppInfo(t *testing.T) {
out := `"1000000"
{
"common"
{
"name" "Example Dedicated Server"
"type" "Tool"
}
}`
m := appName.FindStringSubmatch(out)
if m == nil || m[1] != "Example Dedicated Server" {
t.Errorf("got %v", m)
}
}
func TestParseAppInfoFindsLinuxServers(t *testing.T) {
linux, ok := parseAppInfo(`"1000000"
{
"common"
{
"name" "Example Dedicated Server"
"oslist" "windows,linux"
}
}`)
if !ok || linux.name != "Example Dedicated Server" || !linux.linux {
t.Errorf("got %+v %v", linux, ok)
}
// A server that only exists for Windows (needs Proton or Wine)
windows, _ := parseAppInfo(`"common" { "name" "Example Server" "oslist" "windows" }`)
if windows.linux {
t.Error("windows-only app reported as linux")
}
}
func TestWithSteamCMDGoesFirstOnlyForLinuxServers(t *testing.T) {
images := []string{"someone/example-server", "cm2network/steamcmd", "other/example"}
got := withSteamCMD(images, true)
if len(got) != 3 || got[0] != "cm2network/steamcmd" || got[1] != "someone/example-server" {
t.Errorf("linux: %v", got)
}
got = withSteamCMD([]string{"someone/proton-example"}, false)
if len(got) != 2 || got[1] != "cm2network/steamcmd" {
t.Errorf("windows-only: %v", got)
}
}
func TestRecommendPrefersTheSteamCMDVariant(t *testing.T) {
v := []variant{
{ID: "image", Recommended: true, Images: []string{"someone/example-server"}},
{ID: "steam", Images: []string{"cm2network/steamcmd", "someone/example-server"}},
{ID: "broken", Recommended: true},
}
recommend(v)
if v[0].Recommended || !v[1].Recommended || v[2].Recommended {
t.Errorf("got %+v", v)
}
// Without a SteamCMD variant, the model's runnable choice stands
v = []variant{{ID: "a", Images: []string{"x/a"}}, {ID: "b", Recommended: true, Images: []string{"x/b"}}}
recommend(v)
if v[0].Recommended || !v[1].Recommended {
t.Errorf("got %+v", v)
}
}
func TestOneOptionPerImageThenSteamCMDRecommended(t *testing.T) {
v := oneOptionPerImage([]variant{{
ID: "dedicated", Title: "Example Dedicated Server", Recommended: true, SteamAppID: "1000000",
Images: withSteamCMD([]string{"someone/example-server"}, true),
Verified: []string{"image someone/example-server exists", "Steam app 1000000 is \"Example Dedicated Server\""},
}})
recommend(v)
if len(v) != 2 {
t.Fatalf("want one option per image, got %+v", v)
}
steam, image := v[0], v[1]
if steam.Title != "Example Dedicated Server (SteamCMD)" || !steam.Recommended || steam.SteamAppID != "1000000" || len(steam.Images) != 1 {
t.Errorf("SteamCMD option: %+v", steam)
}
if image.Title != "Example Dedicated Server (image someone/example-server)" || image.Recommended || image.SteamAppID != "" {
t.Errorf("image option: %+v", image)
}
for _, line := range steam.Verified {
if line == "image someone/example-server exists" {
t.Error("SteamCMD option lists the other option's image check")
}
}
}
func TestResearchSkipsOurOwnSites(t *testing.T) {
got := dedupeHits([]searchHit{
{URL: "https://www.gitea.gbreed.com/gbreed-public/gbr-games/src/branch/main/games/x/game.yaml"},
{URL: "https://gbrhosting.com/games"},
{URL: "https://example.com/server-guide"},
})
if len(got) != 1 || got[0].URL != "https://example.com/server-guide" {
t.Errorf("got %v", got)
}
}