Files
cad-atlas/internal/atlas/cluster_test.go
T
mathiasandClaude Opus 4.8 633ba153f2
CD / Detect unsubstituted template (push) Successful in 1s
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Successful in 14s
CD / Deploy via GitOps (push) Successful in 1s
feat(atlas): Phase B tail — live namespaces + trim inline fallback
NamespaceSummary (test-first) renders the substrate ns line from live cluster
namespaces (system-filtered, sorted, capped). Handler now overlays both node
specs and the ns line via a single cached liveOverlay(). Removed the inline
SUBSTRATE/STAGES/NS data — /api/atlas.json is the single source; the page shows
an error banner on fetch failure instead of stale data.

GPU model naming intentionally NOT done: koala's node has no GPU product label
(only nvidia.com/gpu count), so "1× GPU" is the API's truth — naming the RTX 5070
would need GPU-feature-discovery, out of scope.

Verified: build/vet/lint(0)/test green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 00:56:40 +02:00

106 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package atlas_test
import (
"reflect"
"strings"
"testing"
"git.d-ma.be/mathias/cad-atlas/internal/atlas"
)
func TestHostsFromNodes_DerivesSpecFromNodeStatus(t *testing.T) {
nodes := []byte(`{"items":[
{"metadata":{"name":"koala"},
"status":{"capacity":{"cpu":"16","memory":"67108864Ki","nvidia.com/gpu":"1"},
"nodeInfo":{"architecture":"amd64","kubeletVersion":"v1.31.4+k3s1"}}},
{"metadata":{"name":"worker2"},
"status":{"capacity":{"cpu":"8","memory":"33554432Ki"},
"nodeInfo":{"architecture":"arm64","kubeletVersion":"v1.30.0+k3s1"}}}
]}`)
hosts, err := atlas.HostsFromNodes(nodes)
if err != nil {
t.Fatalf("HostsFromNodes: %v", err)
}
want := []atlas.Host{
{Name: "koala", Spec: "amd64 · 16 cpu · 64Gi · 1× GPU · k3s v1.31.4"},
{Name: "worker2", Spec: "arm64 · 8 cpu · 32Gi · k3s v1.30.0"},
}
if !reflect.DeepEqual(hosts, want) {
t.Fatalf("hosts = %+v\nwant %+v", hosts, want)
}
}
func TestMergeSubstrate_LiveOverridesAuthoredKeepsRestAppendsNew(t *testing.T) {
authored := []atlas.Host{
{Name: "koala", Spec: "RTX 5070 · authored"},
{Name: "iguana", Spec: "M2 Ultra · Ollama / mlx"},
{Name: "piguard", Spec: "NGINX reverse-proxy · ntfy"},
}
live := []atlas.Host{
{Name: "koala", Spec: "amd64 · 16 cpu · 60Gi · 1× GPU · k3s v1.34.5"},
{Name: "worker9", Spec: "arm64 · 4 cpu"},
}
got := atlas.MergeSubstrate(authored, live)
want := []atlas.Host{
{Name: "koala", Spec: "amd64 · 16 cpu · 60Gi · 1× GPU · k3s v1.34.5"}, // live wins
{Name: "iguana", Spec: "M2 Ultra · Ollama / mlx"}, // authored kept
{Name: "piguard", Spec: "NGINX reverse-proxy · ntfy"}, // authored kept
{Name: "worker9", Spec: "arm64 · 4 cpu"}, // live-only appended
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("merge = %+v\nwant %+v", got, want)
}
}
func TestMergeSubstrate_NoLiveReturnsAuthored(t *testing.T) {
authored := []atlas.Host{{Name: "koala", Spec: "authored"}}
got := atlas.MergeSubstrate(authored, nil)
if !reflect.DeepEqual(got, authored) {
t.Fatalf("merge with no live = %+v, want %+v", got, authored)
}
}
func TestNamespaceSummary_FiltersSystemSortsAndJoins(t *testing.T) {
ns := []byte(`{"items":[
{"metadata":{"name":"gitea"}},
{"metadata":{"name":"kube-system"}},
{"metadata":{"name":"ai-stack"}},
{"metadata":{"name":"default"}},
{"metadata":{"name":"flux-system"}},
{"metadata":{"name":"brain"}}
]}`)
got, err := atlas.NamespaceSummary(ns)
if err != nil {
t.Fatalf("NamespaceSummary: %v", err)
}
if want := "ns: ai-stack · brain · gitea"; got != want {
t.Fatalf("summary = %q, want %q", got, want)
}
}
func TestNamespaceSummary_CapsWithMore(t *testing.T) {
var items []string
for i := 0; i < 15; i++ {
items = append(items, `{"metadata":{"name":"app`+string(rune('a'+i))+`"}}`)
}
ns := []byte(`{"items":[` + strings.Join(items, ",") + `]}`)
got, err := atlas.NamespaceSummary(ns)
if err != nil {
t.Fatalf("NamespaceSummary: %v", err)
}
if !strings.HasSuffix(got, "· +3 more") {
t.Fatalf("expected cap suffix, got %q", got)
}
}
func TestHostsFromNodes_ErrorsOnBadJSON(t *testing.T) {
if _, err := atlas.HostsFromNodes([]byte("{not json")); err == nil {
t.Fatal("expected error on bad JSON, got nil")
}
}