package api import ( "bytes" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" "github.com/thepeterstone/claudomator/internal/storage" ) func TestListTemplates_Empty(t *testing.T) { srv, _ := testServer(t) req := httptest.NewRequest("GET", "/api/templates", nil) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("status: want 200, got %d; body: %s", w.Code, w.Body.String()) } var templates []storage.Template json.NewDecoder(w.Body).Decode(&templates) if len(templates) != 0 { t.Errorf("want 0 templates, got %d", len(templates)) } } func TestCreateTemplate_Success(t *testing.T) { srv, _ := testServer(t) payload := `{ "name": "Go: Run Tests", "description": "Run the full test suite with race detector", "agent": { "type": "claude", "model": "sonnet", "instructions": "Run go test -race ./...", "max_budget_usd": 0.50, "allowed_tools": ["Bash"] }, "timeout": "10m", "priority": "normal", "tags": ["go", "testing"] }` req := httptest.NewRequest("POST", "/api/templates", bytes.NewBufferString(payload)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusCreated { t.Fatalf("status: want 201, got %d; body: %s", w.Code, w.Body.String()) } var created storage.Template json.NewDecoder(w.Body).Decode(&created) if created.Name != "Go: Run Tests" { t.Errorf("name: want 'Go: Run Tests', got %q", created.Name) } if created.ID == "" { t.Error("expected auto-generated ID") } } func TestGetTemplate_AfterCreate(t *testing.T) { srv, _ := testServer(t) payload := `{"name": "Fetch Me", "agent": {"type": "claude", "instructions": "do thing", "model": "haiku"}}` req := httptest.NewRequest("POST", "/api/templates", bytes.NewBufferString(payload)) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusCreated { t.Fatalf("create: want 201, got %d", w.Code) } var created storage.Template json.NewDecoder(w.Body).Decode(&created) req2 := httptest.NewRequest("GET", fmt.Sprintf("/api/templates/%s", created.ID), nil) w2 := httptest.NewRecorder() srv.Handler().ServeHTTP(w2, req2) if w2.Code != http.StatusOK { t.Fatalf("get: want 200, got %d; body: %s", w2.Code, w2.Body.String()) } var fetched storage.Template json.NewDecoder(w2.Body).Decode(&fetched) if fetched.ID != created.ID { t.Errorf("id: want %q, got %q", created.ID, fetched.ID) } if fetched.Name != "Fetch Me" { t.Errorf("name: want 'Fetch Me', got %q", fetched.Name) } } func TestGetTemplate_NotFound(t *testing.T) { srv, _ := testServer(t) req := httptest.NewRequest("GET", "/api/templates/nonexistent", nil) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Errorf("status: want 404, got %d", w.Code) } } func TestUpdateTemplate(t *testing.T) { srv, _ := testServer(t) payload := `{"name": "Original Name", "agent": {"type": "claude", "instructions": "original"}}` req := httptest.NewRequest("POST", "/api/templates", bytes.NewBufferString(payload)) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) var created storage.Template json.NewDecoder(w.Body).Decode(&created) update := `{"name": "Updated Name", "agent": {"type": "claude", "instructions": "updated"}}` req2 := httptest.NewRequest("PUT", fmt.Sprintf("/api/templates/%s", created.ID), bytes.NewBufferString(update)) w2 := httptest.NewRecorder() srv.Handler().ServeHTTP(w2, req2) if w2.Code != http.StatusOK { t.Fatalf("update: want 200, got %d; body: %s", w2.Code, w2.Body.String()) } var updated storage.Template json.NewDecoder(w2.Body).Decode(&updated) if updated.Name != "Updated Name" { t.Errorf("name: want 'Updated Name', got %q", updated.Name) } } func TestUpdateTemplate_NotFound(t *testing.T) { srv, _ := testServer(t) update := `{"name": "Ghost", "agent": {"type": "claude", "instructions": "x"}}` req := httptest.NewRequest("PUT", "/api/templates/nonexistent", bytes.NewBufferString(update)) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Errorf("status: want 404, got %d", w.Code) } } func TestDeleteTemplate(t *testing.T) { srv, _ := testServer(t) payload := `{"name": "To Delete", "agent": {"type": "claude", "instructions": "bye"}}` req := httptest.NewRequest("POST", "/api/templates", bytes.NewBufferString(payload)) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) var created storage.Template json.NewDecoder(w.Body).Decode(&created) req2 := httptest.NewRequest("DELETE", fmt.Sprintf("/api/templates/%s", created.ID), nil) w2 := httptest.NewRecorder() srv.Handler().ServeHTTP(w2, req2) if w2.Code != http.StatusNoContent { t.Fatalf("delete: want 204, got %d; body: %s", w2.Code, w2.Body.String()) } // Subsequent GET returns 404. req3 := httptest.NewRequest("GET", fmt.Sprintf("/api/templates/%s", created.ID), nil) w3 := httptest.NewRecorder() srv.Handler().ServeHTTP(w3, req3) if w3.Code != http.StatusNotFound { t.Fatalf("get after delete: want 404, got %d", w3.Code) } } func TestDeleteTemplate_NotFound(t *testing.T) { srv, _ := testServer(t) req := httptest.NewRequest("DELETE", "/api/templates/nonexistent", nil) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Errorf("status: want 404, got %d", w.Code) } }