CI / test (push) Successful in 3m57s
Every model of a stopped system asks for no replica and so has what it asks for. Until the control plane took the setting up, seconds later, start --wait saw 18 of 18 satisfied and returned at once, with nothing started. It now counts only once the control plane says it is in the state asked for, both ways. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
138 lines
4.3 KiB
Go
138 lines
4.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/control/adminapi"
|
|
)
|
|
|
|
func TestTheServicesHereAreFoundAndAskedAbout(t *testing.T) {
|
|
old, oldRun := unitDir, serviceRunner
|
|
unitDir = t.TempDir()
|
|
t.Cleanup(func() { unitDir, serviceRunner = old, oldRun })
|
|
for _, u := range []string{"llmgw-server", "llmgw-agent"} {
|
|
_ = os.WriteFile(filepath.Join(unitDir, u+".service"), []byte("[Unit]"), 0o644)
|
|
}
|
|
var asked []string
|
|
serviceRunner = func(_ context.Context, args ...string) (string, error) {
|
|
asked = append(asked, strings.Join(args, " "))
|
|
if args[0] == "is-active" {
|
|
return "active", nil
|
|
}
|
|
return "Wed 2026-10-07 12:00:00 UTC", nil
|
|
}
|
|
|
|
units, err := installedServices(context.Background(), nil)
|
|
if err != nil || strings.Join(units, ",") != "llmgw-server,llmgw-agent" {
|
|
t.Fatalf("%v %v", units, err)
|
|
}
|
|
if _, err := installedServices(context.Background(), []string{"mirror"}); err == nil ||
|
|
!strings.Contains(err.Error(), "server, agent") {
|
|
t.Errorf("a service not here: %v", err)
|
|
}
|
|
if u, err := installedServices(context.Background(), []string{"agent"}); err != nil || len(u) != 1 {
|
|
t.Errorf("one named: %v %v", u, err)
|
|
}
|
|
|
|
if runtime.GOOS != "linux" {
|
|
return
|
|
}
|
|
var out bytes.Buffer
|
|
c := serviceVerbs()[0]
|
|
c.SetOut(&out)
|
|
c.SetContext(context.Background())
|
|
if err := c.RunE(c, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(out.String(), "server") || !strings.Contains(out.String(), "active") {
|
|
t.Errorf("%s", out.String())
|
|
}
|
|
}
|
|
|
|
func TestStopSetsTheClustersServingStopped(t *testing.T) {
|
|
var put adminapi.SettingsRequest
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.URL.Path == "/api/v1/summary":
|
|
_ = json.NewEncoder(w).Encode(adminapi.Summary{})
|
|
case r.Method == "GET" && r.URL.Path == "/api/v1/settings":
|
|
_ = json.NewEncoder(w).Encode(adminapi.SettingsView{Version: 3, Body: "router:\n retries: 2\n"})
|
|
case r.Method == "PUT" && r.URL.Path == "/api/v1/settings":
|
|
_ = json.NewDecoder(r.Body).Decode(&put)
|
|
_ = json.NewEncoder(w).Encode(adminapi.SettingsView{Version: 4, Body: put.Body})
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
dir := t.TempDir()
|
|
cfg := filepath.Join(dir, "server.yaml")
|
|
_ = os.WriteFile(filepath.Join(dir, "token"), []byte("t"), 0o600)
|
|
_ = os.WriteFile(cfg, []byte("listen: \":8080\"\nagent_insecure: true\nadmin_listen: "+
|
|
strings.TrimPrefix(srv.URL, "http://")+"\nadmin_remote: true\nadmin_token_file: "+filepath.Join(dir, "token")+"\n"), 0o600)
|
|
|
|
var stop *cobra.Command
|
|
for _, c := range newSystemCmds() {
|
|
if c.Name() == "stop" {
|
|
stop = c
|
|
}
|
|
}
|
|
var out bytes.Buffer
|
|
stop.SetOut(&out)
|
|
stop.SetArgs([]string{"--config", cfg, "--note", "maintenance"})
|
|
if err := stop.ExecuteContext(context.Background()); err != nil {
|
|
t.Fatalf("%v: %s", err, out.String())
|
|
}
|
|
if put.Base != 3 || !strings.Contains(put.Body, "stopped: true") || !strings.Contains(put.Body, "retries: 2") ||
|
|
put.Note != "maintenance" {
|
|
t.Errorf("sent %+v", put)
|
|
}
|
|
if !strings.Contains(out.String(), "stopping") {
|
|
t.Errorf("%s", out.String())
|
|
}
|
|
}
|
|
|
|
// Started while the control plane has not yet taken the setting up: every
|
|
// model of a stopped system has the nothing it asks for, which is not
|
|
// serving.
|
|
func TestStartWaitsForTheControlPlaneToServe(t *testing.T) {
|
|
old := servicePoll
|
|
servicePoll = time.Millisecond
|
|
t.Cleanup(func() { servicePoll = old })
|
|
answers := []adminapi.Summary{
|
|
{Stopped: true, Models: adminapi.ModelTotals{Total: 2, Satisfied: 2}},
|
|
{Models: adminapi.ModelTotals{Total: 2, Satisfied: 0}},
|
|
{Models: adminapi.ModelTotals{Total: 2, Satisfied: 2}},
|
|
}
|
|
asked := 0
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
_ = json.NewEncoder(w).Encode(answers[min(asked, len(answers)-1)])
|
|
asked++
|
|
}))
|
|
defer srv.Close()
|
|
|
|
var out bytes.Buffer
|
|
cmd := &cobra.Command{}
|
|
cmd.SetOut(&out)
|
|
cmd.SetContext(context.Background())
|
|
c := &ctlClient{base: srv.URL, http: srv.Client()}
|
|
if err := waitForService(cmd, func() *ctlClient { return c }, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if asked != 3 {
|
|
t.Errorf("returned after %d answers: %s", asked, out.String())
|
|
}
|
|
}
|