diff --git a/internal/http/handlers/ticket_handler_test.go b/internal/http/handlers/ticket_handler_test.go index da02067..d8f48fb 100644 --- a/internal/http/handlers/ticket_handler_test.go +++ b/internal/http/handlers/ticket_handler_test.go @@ -46,6 +46,7 @@ type mockTicketService struct { mu sync.Mutex tickets *memory.TicketStore auditRecorder *ticketAuditRecorder + listErr error calls []struct { method string args []string @@ -57,6 +58,9 @@ func newMockTicketService(auditRecorder *ticketAuditRecorder) *mockTicketService } func (m *mockTicketService) ListOpen(ctx context.Context, limit int) ([]ticket.Ticket, error) { + if m.listErr != nil { + return nil, m.listErr + } return m.tickets.ListOpen(ctx, limit) } @@ -511,3 +515,63 @@ func TestTicketHandlerClose_ReturnsConflictWhenTicketNotResolved(t *testing.T) { t.Fatalf("error code = %v, want CS_TICKET_4093", errPayload["code"]) } } + +func TestTicketHandlerList_Success(t *testing.T) { + auditRecorder := &ticketAuditRecorder{} + svc := newMockTicketService(auditRecorder) + now := time.Date(2026, 4, 29, 21, 0, 0, 0, time.UTC) + for i := 0; i < 2; i++ { + if err := svc.tickets.Create(context.Background(), &ticket.Ticket{ + ID: fmt.Sprintf("ticket-list-%d", i), + SessionID: fmt.Sprintf("session-%d", i), + Priority: ticket.PriorityP1, + Status: ticket.StatusOpen, + HandoffReason: "refund", + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("Create() error = %v", err) + } + } + h := NewTicketHandler(svc, auditRecorder) + req := httptest.NewRequest(http.MethodGet, "/api/v1/customer-service/tickets", nil) + resp := httptest.NewRecorder() + h.List(resp, req) + + if resp.Code != http.StatusOK { + t.Fatalf("status = %d, want 200", resp.Code) + } + var payload map[string]any + if err := json.Unmarshal(resp.Body.Bytes(), &payload); err != nil { + t.Fatalf("json decode error = %v", err) + } + items, ok := payload["items"].([]any) + if !ok { + t.Fatalf("items field missing or not an array: %v", payload) + } + if len(items) != 2 { + t.Fatalf("items count = %d, want 2", len(items)) + } +} + +func TestTicketHandlerList_ServiceError(t *testing.T) { + auditRecorder := &ticketAuditRecorder{} + svc := newMockTicketService(auditRecorder) + svc.listErr = fmt.Errorf("db down") + h := NewTicketHandler(svc, auditRecorder) + req := httptest.NewRequest(http.MethodGet, "/api/v1/customer-service/tickets", nil) + resp := httptest.NewRecorder() + h.List(resp, req) + + if resp.Code != http.StatusInternalServerError { + t.Fatalf("status = %d, want 500", resp.Code) + } + var payload map[string]any + if err := json.Unmarshal(resp.Body.Bytes(), &payload); err != nil { + t.Fatalf("json decode error = %v", err) + } + errPayload := payload["error"].(map[string]any) + if errPayload["code"] != "CS_SYS_5002" { + t.Fatalf("error code = %v, want CS_SYS_5002", errPayload["code"]) + } +}