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>
154 lines
4.2 KiB
Go
154 lines
4.2 KiB
Go
package docgen
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// repoRoot is where the source paths in Sources are relative to.
|
|
func repoRoot(t *testing.T) string {
|
|
t.Helper()
|
|
_, file, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
t.Fatal("cannot locate this test")
|
|
}
|
|
return filepath.Join(filepath.Dir(file), "..", "..")
|
|
}
|
|
|
|
func sourcePaths(t *testing.T) []string {
|
|
t.Helper()
|
|
root := repoRoot(t)
|
|
out := make([]string, len(Sources))
|
|
for i, s := range Sources {
|
|
out[i] = filepath.Join(root, s)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestTheReferenceIsNotStale(t *testing.T) {
|
|
// The whole point. A generated document that nobody regenerates is the
|
|
// same lie as a hand-written one, arrived at more slowly: it describes the
|
|
// configuration of some earlier week, and the setting somebody came to
|
|
// look up is the one that is missing.
|
|
blocks, err := Collect(sourcePaths(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := Render(blocks)
|
|
|
|
path := filepath.Join(repoRoot(t), "docs", "reference.md")
|
|
got, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatalf("docs/reference.md is missing; run go generate ./...: %v", err)
|
|
}
|
|
if string(got) != want {
|
|
t.Error("docs/reference.md no longer matches the configuration structs.\n" +
|
|
"Run: go generate ./...")
|
|
}
|
|
}
|
|
|
|
func TestEveryConfigurationFileIsListed(t *testing.T) {
|
|
// Sources is a list, and a list is a thing to forget. A new file full of
|
|
// settings would otherwise be absent from the reference with nothing
|
|
// saying so — which is exactly the failure the reference exists to fix.
|
|
root := repoRoot(t)
|
|
var tagged []string
|
|
err := filepath.Walk(filepath.Join(root, "internal"), func(p string, info os.FileInfo, err error) error {
|
|
if err != nil || info.IsDir() || !strings.HasSuffix(p, ".go") || strings.HasSuffix(p, "_test.go") {
|
|
return err
|
|
}
|
|
b, err := os.ReadFile(p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !strings.Contains(string(b), `koanf:"`) {
|
|
return nil
|
|
}
|
|
rel, err := filepath.Rel(root, p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tagged = append(tagged, rel)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(tagged) == 0 {
|
|
t.Fatal("found no configuration files at all, so this test proves nothing")
|
|
}
|
|
|
|
for _, f := range tagged {
|
|
if slices.Contains(Sources, f) {
|
|
continue
|
|
}
|
|
// Deliberately out: these hold koanf tags for structs an operator
|
|
// never writes — inventory and catalog entries come from the API or
|
|
// from a model file, not from the configuration.
|
|
if slices.Contains(notReference, f) {
|
|
continue
|
|
}
|
|
t.Errorf("%s declares configuration and is not in Sources or notReference", f)
|
|
}
|
|
}
|
|
|
|
func TestADocumentedKeyKeepsItsComment(t *testing.T) {
|
|
// The descriptions are the field comments, which is what makes the
|
|
// reference worth reading rather than a list of names. A field whose
|
|
// comment was the only explanation anywhere must not render blank.
|
|
blocks, err := Collect(sourcePaths(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var lease Field
|
|
for _, b := range blocks {
|
|
for _, f := range b.Fields {
|
|
if f.Key == "lease_ttl" {
|
|
lease = f
|
|
}
|
|
}
|
|
}
|
|
if lease.Key == "" {
|
|
t.Fatal("lease_ttl is not in the reference")
|
|
}
|
|
if !strings.Contains(lease.Doc, "shared store") {
|
|
t.Errorf("lease_ttl lost its explanation: %q", lease.Doc)
|
|
}
|
|
}
|
|
|
|
func TestAFieldMarkedNotConfigurableIsLeftOut(t *testing.T) {
|
|
// koanf:"-" means the field is carried in the struct and never read from
|
|
// a file. Listing it would send somebody looking for a setting that does
|
|
// not exist.
|
|
blocks, err := Collect(sourcePaths(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, b := range blocks {
|
|
for _, f := range b.Fields {
|
|
if f.Key == "-" || f.Key == "" {
|
|
t.Errorf("%s lists a non-configurable field: %+v", b.Name, f)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTheSettingsScreensDescribeTheCode(t *testing.T) {
|
|
// The screens list Reference; it must be what the structs say now.
|
|
blocks, err := Collect(sourcePaths(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
have, err := os.ReadFile(filepath.Join(repoRoot(t), "internal", "docgen", "reference_gen.go"))
|
|
if err != nil {
|
|
t.Fatalf("reference_gen.go is missing; run go generate ./...: %v", err)
|
|
}
|
|
if string(have) != RenderGo(blocks) {
|
|
t.Error("internal/docgen/reference_gen.go no longer matches the configuration structs; run go generate ./...")
|
|
}
|
|
}
|