rdev/internal/handlers/diagnostics_test.go
jordan d69da6d627 feat: add structured logging infrastructure and SDLC extensions
Major changes:
- Add internal/logging package with field constants, context propagation,
  sensitive data auto-redaction, and per-component log levels
- Add worker timeout constants (TimeoutQuickOp, TimeoutHealthCheck, etc.)
- Extend SDLC with callback handlers, generate endpoints, and executor
- Add new cookbook trees for aeries and slackpath progression
- Add skeleton templates for queue, realtime, and microservices
- Add worker component template with async job processing
- Refactor services and handlers to use new logging infrastructure
- Split component.go into component_infra.go and component_listing.go

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 22:56:04 -07:00

149 lines
3.9 KiB
Go

package handlers
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/go-chi/chi/v5"
"github.com/orchard9/rdev/internal/domain"
)
// mockDiagnosticsGetter implements DiagnosticsGetter for testing.
type mockDiagnosticsGetter struct {
diagnostics *domain.ProjectDiagnostics
err error
}
func (m *mockDiagnosticsGetter) GetDiagnostics(_ context.Context, projectID string) (*domain.ProjectDiagnostics, error) {
if m.err != nil {
return nil, m.err
}
if m.diagnostics != nil {
return m.diagnostics, nil
}
// Return default healthy diagnostics
return &domain.ProjectDiagnostics{
ProjectID: projectID,
GeneratedAt: time.Now().UTC(),
Summary: domain.DiagnosticsSummaryHealthy,
Issues: []domain.DiagnosticIssue{},
}, nil
}
func TestDiagnosticsHandler_GetDiagnostics_Success(t *testing.T) {
getter := &mockDiagnosticsGetter{}
projects := newMockProjectRepo()
h := NewDiagnosticsHandler(getter, projects)
// Create router with chi to handle URL params
r := chi.NewRouter()
r.Use(testAdminAuth) // Add auth context for tests
h.Mount(r)
req := httptest.NewRequest("GET", "/projects/test-project/diagnostics/", nil)
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("GetDiagnostics() status = %d, want %d; body = %s", rec.Code, http.StatusOK, rec.Body.String())
}
var resp map[string]any
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
data, ok := resp["data"].(map[string]any)
if !ok {
t.Fatalf("response missing data field")
}
if data["project_id"] != "test-project" {
t.Errorf("project_id = %q, want %q", data["project_id"], "test-project")
}
if data["summary"] != domain.DiagnosticsSummaryHealthy {
t.Errorf("summary = %q, want %q", data["summary"], domain.DiagnosticsSummaryHealthy)
}
}
func TestDiagnosticsHandler_GetDiagnostics_WithIssues(t *testing.T) {
getter := &mockDiagnosticsGetter{
diagnostics: &domain.ProjectDiagnostics{
ProjectID: "unhealthy-project",
GeneratedAt: time.Now().UTC(),
Summary: domain.DiagnosticsSummaryUnhealthy,
Issues: []domain.DiagnosticIssue{
{
Severity: domain.DiagnosticSeverityError,
Source: domain.DiagnosticSourceCI,
Message: "CI build #42 failed",
},
{
Severity: domain.DiagnosticSeverityWarning,
Source: domain.DiagnosticSourceRegistry,
Message: "Container registry slow",
},
},
},
}
projects := newMockProjectRepo()
h := NewDiagnosticsHandler(getter, projects)
r := chi.NewRouter()
r.Use(testAdminAuth) // Add auth context for tests
h.Mount(r)
req := httptest.NewRequest("GET", "/projects/unhealthy-project/diagnostics/", nil)
rec := httptest.NewRecorder()
r.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("GetDiagnostics() status = %d, want %d", rec.Code, http.StatusOK)
}
var resp map[string]any
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
data, ok := resp["data"].(map[string]any)
if !ok {
t.Fatalf("response missing data field")
}
if data["summary"] != domain.DiagnosticsSummaryUnhealthy {
t.Errorf("summary = %q, want %q", data["summary"], domain.DiagnosticsSummaryUnhealthy)
}
issues, ok := data["issues"].([]any)
if !ok {
t.Fatalf("response missing issues field")
}
if len(issues) != 2 {
t.Errorf("issues count = %d, want %d", len(issues), 2)
}
}
func TestDiagnosticsHandler_GetDiagnostics_MissingProjectID(t *testing.T) {
getter := &mockDiagnosticsGetter{}
projects := newMockProjectRepo()
h := NewDiagnosticsHandler(getter, projects)
// Direct call without chi router to test missing projectId
req := httptest.NewRequest("GET", "/projects//diagnostics/", nil)
rec := httptest.NewRecorder()
h.GetDiagnostics(rec, req)
if rec.Code != http.StatusBadRequest {
t.Errorf("GetDiagnostics() status = %d, want %d", rec.Code, http.StatusBadRequest)
}
}