An empty server list was sent as null, so the page threw on .length and showed only the loading placeholder. The API now always returns a list, the page tolerates null, and tests cover the empty config and the token. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
73 lines
2.1 KiB
Go
73 lines
2.1 KiB
Go
package admin
|
|
|
|
import (
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.veillax.com/Veillax/spinner/internal/config"
|
|
"git.veillax.com/Veillax/spinner/internal/health"
|
|
"git.veillax.com/Veillax/spinner/internal/proxy"
|
|
)
|
|
|
|
func newAdmin(t *testing.T, cfg string) http.Handler {
|
|
t.Helper()
|
|
log := slog.New(slog.NewTextHandler(io.Discard, nil))
|
|
path := filepath.Join(t.TempDir(), "spinner.json")
|
|
if err := os.WriteFile(path, []byte(cfg), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m, err := config.NewManager(path, log)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
h := health.New(log)
|
|
return (&Admin{Cfg: m, Health: h, Proxy: proxy.New(m, h, log), Token: "secret"}).Handler()
|
|
}
|
|
|
|
func get(h http.Handler, path, token string) *httptest.ResponseRecorder {
|
|
req := httptest.NewRequest("GET", path, nil)
|
|
if token != "" {
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
}
|
|
rec := httptest.NewRecorder()
|
|
h.ServeHTTP(rec, req)
|
|
return rec
|
|
}
|
|
|
|
// The page reads .length on these lists, so an empty config must give [] and never null.
|
|
func TestEmptyConfigGivesEmptyLists(t *testing.T) {
|
|
for _, cfg := range []string{`{}`, `{"servers":[]}`} {
|
|
h := newAdmin(t, cfg)
|
|
if body := get(h, "/api/overview", "secret").Body.String(); !strings.Contains(body, `"servers":[]`) {
|
|
t.Errorf("%s: overview servers not an empty list: %s", cfg, body)
|
|
}
|
|
if body := get(h, "/api/config", "secret").Body.String(); !strings.Contains(body, `"servers":[]`) {
|
|
t.Errorf("%s: config servers not an empty list: %s", cfg, body)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAuthRequired(t *testing.T) {
|
|
h := newAdmin(t, `{}`)
|
|
for _, p := range []string{"/api/overview", "/api/config", "/metrics"} {
|
|
if c := get(h, p, "").Code; c != http.StatusUnauthorized {
|
|
t.Errorf("%s without token: %d", p, c)
|
|
}
|
|
if c := get(h, p, "wrong").Code; c != http.StatusUnauthorized {
|
|
t.Errorf("%s with wrong token: %d", p, c)
|
|
}
|
|
if c := get(h, p, "secret").Code; c != http.StatusOK {
|
|
t.Errorf("%s with token: %d", p, c)
|
|
}
|
|
}
|
|
if c := get(h, "/", "").Code; c != http.StatusOK {
|
|
t.Errorf("page should load without a token: %d", c)
|
|
}
|
|
}
|