Files
llmgw/internal/cli/controlplanes_test.go
T
Ilker ManapandClaude Opus 5.5 c2b4985abe The floating address is read each time the summary is asked
server add records it after restarting the new control plane, which then
never named it.

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

135 lines
4.2 KiB
Go

package cli
import (
"bytes"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"github.com/spf13/cobra"
"gitea.mynodes.xyz/ilker/llmgw/internal/control/adminapi"
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
)
func TestStatusSaysWhichControlPlaneLeadsAndWhetherTheOthersStandBy(t *testing.T) {
render := func(s adminapi.Summary) string {
cmd := &cobra.Command{}
var b bytes.Buffer
cmd.SetOut(&b)
printSummary(cmd, s)
return b.String()
}
out := render(adminapi.Summary{ControlPlanes: adminapi.ControlPlanes{
Members: []adminapi.ControlPlane{
{Name: "llmgw-ctl", State: "leading", This: true},
{Name: "llmgw-ctl02", State: "standing by"},
},
Floating: "10.0.0.161", FloatingUp: true,
}})
if !strings.Contains(out, "CONTROL llmgw-ctl leads (this one), llmgw-ctl02 standing by · 10.0.0.161 on the leader") {
t.Errorf("status:\n%s", out)
}
out = render(adminapi.Summary{ControlPlanes: adminapi.ControlPlanes{
Members: []adminapi.ControlPlane{
{Name: "llmgw-ctl", State: "not answering"},
{Name: "llmgw-ctl02", State: "standing by", This: true},
},
Floating: "10.0.0.161",
}})
for _, want := range []string{"NO LEADER", "llmgw-ctl not answering", "10.0.0.161 NOT ANSWERING"} {
if !strings.Contains(out, want) {
t.Errorf("%q missing:\n%s", want, out)
}
}
if out := render(adminapi.Summary{}); strings.Contains(out, "CONTROL") {
t.Error("a single control plane got a control line")
}
}
func TestTheProbeAsksEachControlPlaneWhetherItLeads(t *testing.T) {
leading := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
defer leading.Close()
standby := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
}))
defer standby.Close()
gone := httptest.NewServer(http.NotFoundHandler())
gone.Close()
st, err := store.Open(t.Context(), filepath.Join(t.TempDir(), "s.db"))
if err != nil {
t.Fatal(err)
}
defer st.Close()
for _, cp := range []store.ControlPlane{
{URL: "https://10.0.0.1:7443", Name: "one"},
{URL: "https://10.0.0.2:7443", Name: "two"},
{URL: "https://10.0.0.3:7443", Name: "three"},
} {
if err := st.PutControlPlane(t.Context(), cp); err != nil {
t.Fatal(err)
}
}
at := map[string]string{"10.0.0.1": leading.URL, "10.0.0.2": standby.URL, "10.0.0.3": gone.URL, "10.0.0.161": leading.URL}
p := newControlPlaneProbe(st, ":8080")
floating := filepath.Join(t.TempDir(), "floating")
if err := os.WriteFile(floating, []byte("10.0.0.161/24\n"), 0o644); err != nil {
t.Fatal(err)
}
p.self, p.floating = "two", floating
p.leaderURL = func(host string) string { return at[host] + "/leader" }
s := p.Status()
got := map[string]adminapi.ControlPlane{}
for _, m := range s.Members {
got[m.Name] = m
}
if got["one"].State != "leading" || got["two"].State != "standing by" || got["three"].State != "not answering" {
t.Errorf("states: %+v", got)
}
if !got["two"].This || got["one"].This || got["one"].Address != "10.0.0.1" {
t.Errorf("which and where: %+v", got)
}
if !s.FloatingUp {
t.Error("a floating address on the leader read as down")
}
}
func TestOneControlPlaneIsNotASetOfThem(t *testing.T) {
st, err := store.Open(t.Context(), filepath.Join(t.TempDir(), "s.db"))
if err != nil {
t.Fatal(err)
}
defer st.Close()
if err := st.PutControlPlane(t.Context(), store.ControlPlane{URL: "https://10.0.0.1:7443", Name: "one"}); err != nil {
t.Fatal(err)
}
if s := newControlPlaneProbe(st, ":8080").Status(); len(s.Members) != 0 {
t.Errorf("one control plane reported as a set: %+v", s)
}
}
func TestTheFloatingAddressIsReadFromWhatServerAddWrote(t *testing.T) {
dir := t.TempDir()
file := filepath.Join(dir, "floating")
if err := os.WriteFile(file, []byte("10.0.0.161/24\n"), 0o644); err != nil {
t.Fatal(err)
}
if got := floatingAddress(file); got != "10.0.0.161" {
t.Errorf("read %q", got)
}
if err := os.WriteFile(file, []byte("not an address\n"), 0o644); err != nil {
t.Fatal(err)
}
if got := floatingAddress(file); got != "" {
t.Errorf("nonsense read as %q", got)
}
if got := floatingAddress(filepath.Join(dir, "none")); got != "" {
t.Errorf("no file read as %q", got)
}
}