package cli import ( "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" "gitea.mynodes.xyz/ilker/llmgw/internal/config" "gitea.mynodes.xyz/ilker/llmgw/internal/control/catalog" ) func TestTheInitAgentUnitIsTheShippedUnit(t *testing.T) { b, err := os.ReadFile("../../deploy/systemd/llmgw-agent.service") if err != nil { t.Fatal(err) } if string(b) != agentUnit { t.Error("deploy/systemd/llmgw-agent.service and the unit 'server init' writes have drifted") } } func TestTheStarterUsesTheGPUAndFallsBackToCPUOnThisMachine(t *testing.T) { m := starterModel("http://10.0.0.5:8081/qwen2.5-0.5b-instruct/starter/q.gguf", []string{"4090-24g"}, true) c, err := catalog.New([]catalog.Model{m}) if err != nil { t.Fatalf("the starter is not a valid catalog entry: %v", err) } got, _ := c.Resolve(starterName) if len(got.Profiles) != 2 { t.Fatalf("profiles = %+v", got.Profiles) } gpu, cpu := got.Profiles[0], got.Profiles[1] if gpu.GPUClass != "4090-24g" || gpu.Priority <= cpu.Priority { t.Errorf("the GPU profile should come first: %+v", gpu) } if cpu.GPUClass != "" || cpu.Engine != "llamacpp" { t.Errorf("the fallback should be llama.cpp on CPU: %+v", cpu) } for _, p := range got.Profiles { if p.NodeSelector[localLabelKey] != localLabelValue { t.Errorf("profile %s is not pinned to this machine", p.Name) } } if got.Scaling.Min != 1 { t.Error("the starter should be running, not waiting to be asked for") } if m := starterModel("http://x/q.gguf", nil, true); len(m.Profiles) != 1 || m.Profiles[0].Name != "cpu" { t.Errorf("without a GPU only the CPU profile: %+v", m.Profiles) } } func TestTheMirrorBlockIsAddedAndReads(t *testing.T) { in, out := newTestInit(t) if err := in.run(t.Context()); err != nil { t.Fatalf("%v\n%s", err, out) } if err := appendMirrorBlockFor(in.configPath(), "http://"+mirrorAPI, "# the mirror"); err != nil { t.Fatal(err) } cfg, err := config.Load(in.configPath()) if err != nil { t.Fatal(err) } if cfg.Mirror.API != "http://"+mirrorAPI { t.Errorf("mirror.api = %q", cfg.Mirror.API) } if err := cfg.Validate(); err != nil { t.Error(err) } backups, _ := filepath.Glob(in.configPath() + ".bak-*") if len(backups) != 1 { t.Errorf("backups = %v", backups) } } func TestTheMirrorUnitAdvertisesAnAddressNodesCanReach(t *testing.T) { in := &serverInit{hosts: []string{"10.0.0.140"}} u := in.mirrorUnit() if !strings.Contains(u, "--base http://10.0.0.140:8081") { t.Errorf("base: %s", u) } // The management port can delete models; nothing but this machine may // reach it, which is what lets it go without a certificate. if !strings.Contains(u, "--api-listen 127.0.0.1:8082") { t.Errorf("the management API is not on loopback: %s", u) } } func TestWithNoNodeHereTheStarterGoesToTheFirstNodeThatJoins(t *testing.T) { m := starterModel("http://x/q.gguf", nil, false) for _, p := range m.Profiles { if len(p.NodeSelector) > 0 { t.Errorf("profile %s is pinned to a machine that is not a node: %v", p.Name, p.NodeSelector) } } } func TestTheMirrorAPIOnlyAnswersItsControlPlane(t *testing.T) { allowed, err := parseAllow([]string{"10.0.0.140", "10.1.0.0/24"}) if err != nil { t.Fatal(err) } h := onlyFrom(allowed, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {})) for addr, want := range map[string]int{ "10.0.0.140:5000": 200, "10.1.0.7:5000": 200, "127.0.0.1:5000": 200, "[::1]:5000": 200, "10.0.0.141:5000": 403, "192.168.1.9:5000": 403, } { r := httptest.NewRequest("GET", "/api/v1/health", nil) r.RemoteAddr = addr w := httptest.NewRecorder() h.ServeHTTP(w, r) if w.Code != want { t.Errorf("%s: %d, want %d", addr, w.Code, want) } } if _, err := parseAllow([]string{"not-an-address"}); err == nil { t.Error("nonsense was accepted") } }