package server import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "os" "testing" "github.com/cnachtigall/heatwave-autopilot/internal/compute" "github.com/cnachtigall/heatwave-autopilot/internal/config" ) func TestMain(m *testing.M) { // Tests run from the package directory. Set WebFS to point to web/ dir. WebFS = os.DirFS("../../web") os.Exit(m.Run()) } func testServer(t *testing.T) *Server { t.Helper() s, err := New(Options{ Port: 0, DevMode: false, Config: config.DefaultConfig(), }) if err != nil { t.Fatalf("create server: %v", err) } return s } func TestDashboardPage(t *testing.T) { s := testServer(t) req := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("got status %d, want 200; body: %s", w.Code, w.Body.String()) } if ct := w.Header().Get("Content-Type"); ct != "text/html; charset=utf-8" { t.Errorf("got content-type %q, want text/html", ct) } } func TestSetupPage(t *testing.T) { s := testServer(t) req := httptest.NewRequest("GET", "/setup", nil) w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("got status %d, want 200; body: %s", w.Code, w.Body.String()) } } func TestGuidePage(t *testing.T) { s := testServer(t) req := httptest.NewRequest("GET", "/guide", nil) w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("got status %d, want 200; body: %s", w.Code, w.Body.String()) } } func TestNotFound(t *testing.T) { s := testServer(t) req := httptest.NewRequest("GET", "/nonexistent", nil) w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Errorf("got status %d, want 404", w.Code) } } func TestLanguageDetection(t *testing.T) { s := testServer(t) req := httptest.NewRequest("GET", "/?lang=de", nil) w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("got status %d, want 200", w.Code) } body := w.Body.String() if !bytes.Contains([]byte(body), []byte(`lang="de"`)) { t.Error("expected lang=de in response") } cookies := w.Result().Cookies() found := false for _, c := range cookies { if c.Name == "heatguard_lang" && c.Value == "de" { found = true } } if !found { t.Error("expected heatguard_lang cookie to be set") } } func TestComputeAPI_NoForecasts(t *testing.T) { s := testServer(t) reqBody := compute.ComputeRequest{ Profile: compute.Profile{Name: "Test", Timezone: "UTC"}, Date: "2025-07-15", } b, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", "/api/compute/dashboard", bytes.NewReader(b)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("got status %d, want 400", w.Code) } } func TestComputeAPI_MethodNotAllowed(t *testing.T) { s := testServer(t) req := httptest.NewRequest("GET", "/api/compute/dashboard", nil) w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusMethodNotAllowed { t.Errorf("got status %d, want 405", w.Code) } } func TestLLMConfigAPI(t *testing.T) { s := testServer(t) req := httptest.NewRequest("GET", "/api/llm/config", nil) w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("got status %d, want 200", w.Code) } var resp struct { Provider string `json:"provider"` Model string `json:"model"` Available bool `json:"available"` } json.NewDecoder(w.Body).Decode(&resp) if resp.Available { t.Errorf("expected available=false for noop provider, got provider=%q model=%q available=%v", resp.Provider, resp.Model, resp.Available) } } func TestLLMSummarize_Noop(t *testing.T) { s := testServer(t) body := `{"date":"2025-07-15","peakTempC":35,"riskLevel":"high"}` req := httptest.NewRequest("POST", "/api/llm/summarize", bytes.NewBufferString(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() s.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("got status %d, want 200", w.Code) } var resp map[string]string json.NewDecoder(w.Body).Decode(&resp) if resp["summary"] != "" { t.Errorf("expected empty summary for noop, got %q", resp["summary"]) } }