package main // Locks the two things that are easy to break silently: the RCON allowlist // (the guarantee that this service cannot run commands) and the `neoforge tps` // output format, which differs from the older Forge wording. import "testing" func TestParseTPSRealOutput(t *testing.T) { // Captured verbatim from `docker exec minecraft rcon-cli neoforge tps` on prod, // ANSI resets included. raw := "Overworld: 20.000 TPS (0.298 ms/tick)\n\x1b[0mThe Nether: 19.100 TPS (0.014 ms/tick)\n" + "\x1b[0mworld_dimension_nexus:creative: 20.000 TPS (0.009 ms/tick)\n" + "\x1b[0mOverall: 18.500 TPS (0.357 ms/tick)\n\x1b[0m" got, err := parseTPS(raw) if err != nil { t.Fatalf("err: %v", err) } if got.TPS != 18.5 || got.MSPT != 0.357 { t.Fatalf("overall wrong: %+v", got) } if len(got.Dimensions) != 3 { t.Fatalf("want 3 dims, got %d: %+v", len(got.Dimensions), got.Dimensions) } } func TestParseTPSUnknownCommand(t *testing.T) { if _, err := parseTPS("Unknown or incomplete command, see below for error\nforge tps<--[HERE]"); err == nil { t.Fatal("want error for unknown command") } } func TestRCONAllowlist(t *testing.T) { for _, bad := range []string{"op Oier", "stop", "say hi", "ban x", "", "neoforge tps ", "LIST"} { if _, err := rconQuery("127.0.0.1:1", "pw", bad, 0); err != errRCONNotAllowed { t.Fatalf("command %q was not rejected by the allowlist (err=%v)", bad, err) } } } func TestSessionParse(t *testing.T) { e := newEvents(10) e.observe("[01Aug2026 22:55:34.358] [Server thread/INFO] [net.minecraft.server.MinecraftServer/]: Oier joined the game") e.observe("[01Aug2026 23:01:02.111] [Server thread/INFO] [net.minecraft.server.MinecraftServer/]: Oier left the game") e.observe("[01Aug2026 23:02:00.000] [Server thread/INFO] [x/]: something else entirely") got := e.recent(10) if len(got) != 2 { t.Fatalf("want 2 events, got %d: %+v", len(got), got) } if got[0].Action != "left" || got[0].Player != "Oier" || got[0].Time != "01Aug2026 23:01:02.111" { t.Fatalf("newest-first wrong: %+v", got[0]) } }