Files
llmgw/internal/settings/settings_test.go
T
Ilker ManapandClaude Opus 5.5 9ab93a0aa6 Watch the cluster and edit every setting from the console
The console gains live views of nodes, GPUs, models, replicas, usage and
agent logs, and a settings tree over every key of server.yaml (agent.yaml on
a node), generated from the configuration structs: values with their
defaults and doc comments, edited in dialogs, saved only once the service's
own loader accepts them, comments kept. The generator now tells blocks apart
by package, which brings the TLS, engine and supervisor settings back into
the reference.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 22:54:09 +02:00

123 lines
3.5 KiB
Go

package settings
import (
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"gitea.mynodes.xyz/ilker/llmgw/internal/config"
"gitea.mynodes.xyz/ilker/llmgw/internal/docgen"
)
func TestEveryKeyOfBothFilesCanBeReached(t *testing.T) {
// Walked from each file's root: every block a key opens is found, so no
// setting is a dead end on the screens.
for _, file := range []string{"/etc/llmgw/server.yaml", "/etc/llmgw/agent.yaml"} {
root, err := Root(file)
if err != nil {
t.Fatal(err)
}
seen := map[string]bool{}
var walk func(b *docgen.Block, path string)
count := 0
walk = func(b *docgen.Block, path string) {
if seen[b.ID()] {
return
}
seen[b.ID()] = true
for _, k := range Keys(b) {
count++
if k.Nested != "" && k.Block == nil {
t.Errorf("%s: %s.%s opens %s, which is not in the reference", file, path, k.Key, k.Nested)
}
if k.Block != nil {
walk(k.Block, path+"."+k.Key)
}
}
}
walk(root, "")
if count < 20 {
t.Errorf("%s: only %d keys reached", file, count)
}
}
// The TLS settings, which the reference used to lose to a name clash.
root, _ := Root("server.yaml")
for _, k := range Keys(root) {
if k.Key == "agent_tls" && (k.Kind != Block || k.Block.ID() != "tlsconf.Config") {
t.Errorf("agent_tls is %v %v", k.Kind, k.Block)
}
if k.Key == "endpoints" && k.Kind != BlockList {
t.Errorf("endpoints is %v", k.Kind)
}
}
}
const sample = `# The control plane.
listen: ":8080"
router:
# How many other endpoints to try.
retries: 2
`
func TestAnEditKeepsTheFilesCommentsAndIsCheckedBeforeItIsWritten(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "server.yaml")
if err := os.WriteFile(path, []byte(sample), 0o644); err != nil {
t.Fatal(err)
}
d, err := Open(path)
if err != nil {
t.Fatal(err)
}
if err := d.Set([]string{"router", "retries"}, Int, "three"); err == nil {
t.Error("a word was taken for a number")
}
if err := d.Set([]string{"router", "retries"}, Int, "3"); err != nil {
t.Fatal(err)
}
if err := d.Set([]string{"router", "cooldown"}, Duration, "45s"); err != nil {
t.Fatal(err)
}
check := func(p string) error { _, err := config.Load(p); return err }
if _, err := d.Save(check); err != nil {
t.Fatalf("a good edit was refused: %v", err)
}
b, _ := os.ReadFile(path)
for _, want := range []string{"# The control plane.", "# How many other endpoints to try.", "retries: 3", "cooldown: 45s"} {
if !strings.Contains(string(b), want) {
t.Errorf("the file lacks %q:\n%s", want, b)
}
}
// Two endpoints with one id: the loader refuses, and nothing is written.
for range 2 {
i := d.Append([]string{"endpoints"})
for _, kv := range [][2]string{{"id", "a"}, {"url", "http://x"}} {
if err := d.Set([]string{"endpoints", itoa(i), kv[0]}, Text, kv[1]); err != nil {
t.Fatal(err)
}
}
_ = d.Set([]string{"endpoints", itoa(i), "models"}, TextList, "m")
}
if _, err := d.Save(check); err == nil {
t.Error("an invalid configuration was saved")
}
if b2, _ := os.ReadFile(path); string(b2) != string(b) {
t.Error("a refused save changed the file")
}
}
func TestTheValueThatAppliesIsShownWhenTheFileSetsNone(t *testing.T) {
cfg := config.Default()
if v, ok := Effective(cfg, []string{"router", "retries"}); !ok || v != "2" {
t.Errorf("router.retries: %q %v", v, ok)
}
if v, ok := Effective(cfg, []string{"router", "cooldown"}); !ok || v != "15s" {
t.Errorf("router.cooldown: %q", v)
}
}
func itoa(i int) string { return strconv.Itoa(i) }