package server import ( "encoding/json" "log/slog" "net/http" "net/http/httptest" "path/filepath" "testing" "gitea.stevedudenhoeffer.com/steve/foreman/internal/config" "gitea.stevedudenhoeffer.com/steve/foreman/internal/store" ) // newTestServer creates a Server backed by a temp-dir SQLite store. func newTestServer(t *testing.T, cfg config.Config) *Server { t.Helper() dbPath := filepath.Join(t.TempDir(), "test.db") st, err := store.Open(dbPath) if err != nil { t.Fatalf("store.Open: %v", err) } t.Cleanup(func() { st.Close() }) logger := slog.Default() return New(cfg, st, logger) } func TestHealthz_OK(t *testing.T) { srv := newTestServer(t, config.Config{ OllamaURL: "http://localhost:11434", }) req := httptest.NewRequest(http.MethodGet, "/healthz", nil) rec := httptest.NewRecorder() srv.Handler().ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK) } var resp healthResponse if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil { t.Fatalf("decode response: %v", err) } if resp.Status != "ok" { t.Errorf("status = %q, want %q", resp.Status, "ok") } if resp.Degraded { t.Error("degraded should be false") } } func TestHealthz_NoAuthRequired(t *testing.T) { srv := newTestServer(t, config.Config{ OllamaURL: "http://localhost:11434", Token: "secret-token", }) // /healthz should work without any auth header even when token is configured. req := httptest.NewRequest(http.MethodGet, "/healthz", nil) rec := httptest.NewRecorder() srv.Handler().ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Errorf("status = %d, want %d (healthz should bypass auth)", rec.Code, http.StatusOK) } } func TestAuth_RequiredWhenTokenSet(t *testing.T) { srv := newTestServer(t, config.Config{ OllamaURL: "http://localhost:11434", Token: "secret-token", }) tests := []struct { name string path string auth string want int }{ { name: "no auth header", path: "/some-route", auth: "", want: http.StatusUnauthorized, }, { name: "wrong token", path: "/some-route", auth: "Bearer wrong-token", want: http.StatusUnauthorized, }, { name: "correct token", path: "/some-route", auth: "Bearer secret-token", // Route doesn't exist so we get 404, but auth passed. want: http.StatusNotFound, }, { name: "invalid scheme", path: "/some-route", auth: "Basic dXNlcjpwYXNz", want: http.StatusUnauthorized, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, tt.path, nil) if tt.auth != "" { req.Header.Set("Authorization", tt.auth) } rec := httptest.NewRecorder() srv.Handler().ServeHTTP(rec, req) if rec.Code != tt.want { t.Errorf("status = %d, want %d", rec.Code, tt.want) } }) } } func TestAuth_NotRequiredWhenNoToken(t *testing.T) { srv := newTestServer(t, config.Config{ OllamaURL: "http://localhost:11434", // Token intentionally empty. }) // Without a configured token, any request should pass auth (even to a // nonexistent route, which returns 404 rather than 401). req := httptest.NewRequest(http.MethodGet, "/some-route", nil) rec := httptest.NewRecorder() srv.Handler().ServeHTTP(rec, req) if rec.Code == http.StatusUnauthorized { t.Error("should not require auth when no token is configured") } }