package handlers import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/go-chi/chi/v5" "github.com/orchard9/rdev/internal/domain" "github.com/orchard9/rdev/internal/sdlc" "github.com/orchard9/rdev/internal/service" ) func setupOrchestratorHandler(exec *testSDLCExecutor) (*SDLCOrchestratorHandler, *chi.Mux) { repo := &testSDLCProjectRepo{ project: &domain.Project{ID: "test-project", PodName: "test-pod"}, } sdlcSvc := service.NewSDLCService(exec, repo) orchestrator := service.NewSDLCOrchestratorService( sdlcSvc, nil, // no agent registry for handler tests nil, // no git committer for handler tests repo, nil, // no build service for handler tests nil, // no db for handler tests ) handler := NewSDLCOrchestratorHandler(orchestrator) r := chi.NewRouter() r.Use(testAdminAuth) handler.Mount(r) return handler, r } func TestSDLCOrchestratorHandler_Execute(t *testing.T) { exec := &testSDLCExecutor{ classification: &sdlc.Classification{ Action: sdlc.ActionIdle, Feature: "auth-flow", Message: "No action needed", }, } _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.ExecuteRequest{Feature: "auth-flow"}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/execute", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Execute_MissingFeature(t *testing.T) { exec := &testSDLCExecutor{} _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.ExecuteRequest{}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/execute", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Execute_InvalidBody(t *testing.T) { exec := &testSDLCExecutor{} _, router := setupOrchestratorHandler(exec) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/execute", bytes.NewReader([]byte("not json"))) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Execute_FeatureNotFound(t *testing.T) { exec := &testSDLCExecutor{err: sdlc.ErrFeatureNotFound} _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.ExecuteRequest{Feature: "nonexistent"}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/execute", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusNotFound { t.Errorf("expected status 404, got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Execute_Transition(t *testing.T) { exec := &testSDLCExecutor{ classification: &sdlc.Classification{ Action: sdlc.ActionTransition, Feature: "auth-flow", TransitionTo: sdlc.PhaseSpecified, }, } _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.ExecuteRequest{Feature: "auth-flow"}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/execute", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Resolve(t *testing.T) { exec := &testSDLCExecutor{ classification: &sdlc.Classification{ Action: sdlc.ActionIdle, Feature: "auth-flow", }, } _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.ResolveRequest{Feature: "auth-flow"}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/resolve", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Resolve_MissingFeature(t *testing.T) { exec := &testSDLCExecutor{} _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.ResolveRequest{}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/resolve", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Commit(t *testing.T) { exec := &testSDLCExecutor{} _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.CommitRequest{Feature: "auth-flow", Message: "implement auth"}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/commit", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) // Expected 500 because git committer is nil in test setup if w.Code != http.StatusInternalServerError { t.Errorf("expected status 500 (no git committer), got %d: %s", w.Code, w.Body.String()) } } func TestSDLCOrchestratorHandler_Commit_MissingMessage(t *testing.T) { exec := &testSDLCExecutor{} _, router := setupOrchestratorHandler(exec) body, _ := json.Marshal(service.CommitRequest{Feature: "auth-flow"}) req := httptest.NewRequest(http.MethodPost, "/projects/test-project/sdlc/commit", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusBadRequest { t.Errorf("expected status 400, got %d: %s", w.Code, w.Body.String()) } }