feat: edu-search-service migriert, voice-service/geo-service entfernt
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 28s
CI / test-go-edu-search (push) Successful in 27s
CI / test-python-klausur (push) Successful in 1m45s
CI / test-python-agent-core (push) Successful in 16s
CI / test-nodejs-website (push) Successful in 21s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 28s
CI / test-go-edu-search (push) Successful in 27s
CI / test-python-klausur (push) Successful in 1m45s
CI / test-python-agent-core (push) Successful in 16s
CI / test-nodejs-website (push) Successful in 21s
- edu-search-service von breakpilot-pwa nach breakpilot-lehrer kopiert (ohne vendor) - opensearch + edu-search-service in docker-compose.yml hinzugefuegt - voice-service aus docker-compose.yml entfernt (jetzt in breakpilot-core) - geo-service aus docker-compose.yml entfernt (nicht mehr benoetigt) - CI/CD: edu-search-service zu Gitea Actions und Woodpecker hinzugefuegt (Go lint, test mit go mod download, build, SBOM) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,630 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/breakpilot/edu-search-service/internal/orchestrator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// MockAudienceRepository implements orchestrator.AudienceRepository for testing
|
||||
type MockAudienceRepository struct {
|
||||
audiences []orchestrator.Audience
|
||||
exports []orchestrator.AudienceExport
|
||||
members []orchestrator.AudienceMember
|
||||
}
|
||||
|
||||
func NewMockAudienceRepository() *MockAudienceRepository {
|
||||
return &MockAudienceRepository{
|
||||
audiences: make([]orchestrator.Audience, 0),
|
||||
exports: make([]orchestrator.AudienceExport, 0),
|
||||
members: make([]orchestrator.AudienceMember, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) CreateAudience(ctx context.Context, audience *orchestrator.Audience) error {
|
||||
audience.ID = uuid.New()
|
||||
audience.CreatedAt = time.Now()
|
||||
audience.UpdatedAt = time.Now()
|
||||
m.audiences = append(m.audiences, *audience)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) GetAudience(ctx context.Context, id uuid.UUID) (*orchestrator.Audience, error) {
|
||||
for i := range m.audiences {
|
||||
if m.audiences[i].ID == id {
|
||||
return &m.audiences[i], nil
|
||||
}
|
||||
}
|
||||
return nil, context.DeadlineExceeded // simulate not found
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) ListAudiences(ctx context.Context, activeOnly bool) ([]orchestrator.Audience, error) {
|
||||
if activeOnly {
|
||||
var active []orchestrator.Audience
|
||||
for _, a := range m.audiences {
|
||||
if a.IsActive {
|
||||
active = append(active, a)
|
||||
}
|
||||
}
|
||||
return active, nil
|
||||
}
|
||||
return m.audiences, nil
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) UpdateAudience(ctx context.Context, audience *orchestrator.Audience) error {
|
||||
for i := range m.audiences {
|
||||
if m.audiences[i].ID == audience.ID {
|
||||
m.audiences[i].Name = audience.Name
|
||||
m.audiences[i].Description = audience.Description
|
||||
m.audiences[i].Filters = audience.Filters
|
||||
m.audiences[i].IsActive = audience.IsActive
|
||||
m.audiences[i].UpdatedAt = time.Now()
|
||||
audience.UpdatedAt = m.audiences[i].UpdatedAt
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) DeleteAudience(ctx context.Context, id uuid.UUID) error {
|
||||
for i := range m.audiences {
|
||||
if m.audiences[i].ID == id {
|
||||
m.audiences[i].IsActive = false
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) GetAudienceMembers(ctx context.Context, id uuid.UUID, limit, offset int) ([]orchestrator.AudienceMember, int, error) {
|
||||
// Return mock members
|
||||
if len(m.members) == 0 {
|
||||
m.members = []orchestrator.AudienceMember{
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Name: "Prof. Dr. Test Person",
|
||||
Email: "test@university.de",
|
||||
Position: "professor",
|
||||
University: "Test Universität",
|
||||
Department: "Informatik",
|
||||
SubjectArea: "Informatik",
|
||||
PublicationCount: 42,
|
||||
},
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Name: "Dr. Another Person",
|
||||
Email: "another@university.de",
|
||||
Position: "researcher",
|
||||
University: "Test Universität",
|
||||
Department: "Mathematik",
|
||||
SubjectArea: "Mathematik",
|
||||
PublicationCount: 15,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
total := len(m.members)
|
||||
if offset >= total {
|
||||
return []orchestrator.AudienceMember{}, total, nil
|
||||
}
|
||||
|
||||
end := offset + limit
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
|
||||
return m.members[offset:end], total, nil
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) UpdateAudienceCount(ctx context.Context, id uuid.UUID) (int, error) {
|
||||
count := len(m.members)
|
||||
for i := range m.audiences {
|
||||
if m.audiences[i].ID == id {
|
||||
m.audiences[i].MemberCount = count
|
||||
now := time.Now()
|
||||
m.audiences[i].LastCountUpdate = &now
|
||||
}
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) CreateExport(ctx context.Context, export *orchestrator.AudienceExport) error {
|
||||
export.ID = uuid.New()
|
||||
export.CreatedAt = time.Now()
|
||||
m.exports = append(m.exports, *export)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockAudienceRepository) ListExports(ctx context.Context, audienceID uuid.UUID) ([]orchestrator.AudienceExport, error) {
|
||||
var exports []orchestrator.AudienceExport
|
||||
for _, e := range m.exports {
|
||||
if e.AudienceID == audienceID {
|
||||
exports = append(exports, e)
|
||||
}
|
||||
}
|
||||
return exports, nil
|
||||
}
|
||||
|
||||
func setupAudienceRouter(repo *MockAudienceRepository) *gin.Engine {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
|
||||
handler := NewAudienceHandler(repo)
|
||||
|
||||
v1 := router.Group("/v1")
|
||||
SetupAudienceRoutes(v1, handler)
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
func TestAudienceHandler_ListAudiences_Empty(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Audiences []orchestrator.Audience `json:"audiences"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.Count != 0 {
|
||||
t.Errorf("Expected 0 audiences, got %d", response.Count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_CreateAudience(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
body := CreateAudienceRequest{
|
||||
Name: "Test Audience",
|
||||
Description: "A test audience for professors",
|
||||
Filters: orchestrator.AudienceFilters{
|
||||
PositionTypes: []string{"professor"},
|
||||
States: []string{"BW", "BY"},
|
||||
},
|
||||
CreatedBy: "test-admin",
|
||||
}
|
||||
|
||||
bodyJSON, _ := json.Marshal(body)
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/audiences", bytes.NewBuffer(bodyJSON))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Errorf("Expected status %d, got %d: %s", http.StatusCreated, w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var response orchestrator.Audience
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.Name != "Test Audience" {
|
||||
t.Errorf("Expected name 'Test Audience', got '%s'", response.Name)
|
||||
}
|
||||
|
||||
if !response.IsActive {
|
||||
t.Errorf("Expected audience to be active")
|
||||
}
|
||||
|
||||
if len(repo.audiences) != 1 {
|
||||
t.Errorf("Expected 1 audience in repo, got %d", len(repo.audiences))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_CreateAudience_InvalidJSON(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/audiences", bytes.NewBuffer([]byte("invalid json")))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusBadRequest, w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_CreateAudience_MissingName(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
body := map[string]interface{}{
|
||||
"description": "Missing name field",
|
||||
}
|
||||
|
||||
bodyJSON, _ := json.Marshal(body)
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/audiences", bytes.NewBuffer(bodyJSON))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusBadRequest, w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_GetAudience(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
// Create an audience first
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "Test Audience",
|
||||
Description: "Test description",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences/"+audience.ID.String(), nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d: %s", http.StatusOK, w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var response orchestrator.Audience
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.Name != "Test Audience" {
|
||||
t.Errorf("Expected name 'Test Audience', got '%s'", response.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_GetAudience_InvalidID(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences/invalid-uuid", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusBadRequest, w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_GetAudience_NotFound(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences/"+uuid.New().String(), nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusNotFound, w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_UpdateAudience(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
// Create an audience first
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "Old Name",
|
||||
Description: "Old description",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
body := UpdateAudienceRequest{
|
||||
Name: "New Name",
|
||||
Description: "New description",
|
||||
IsActive: true,
|
||||
}
|
||||
|
||||
bodyJSON, _ := json.Marshal(body)
|
||||
req := httptest.NewRequest(http.MethodPut, "/v1/audiences/"+audience.ID.String(), bytes.NewBuffer(bodyJSON))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d: %s", http.StatusOK, w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// Verify the update
|
||||
if repo.audiences[0].Name != "New Name" {
|
||||
t.Errorf("Expected name 'New Name', got '%s'", repo.audiences[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_DeleteAudience(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
// Create an audience first
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "To Delete",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
req := httptest.NewRequest(http.MethodDelete, "/v1/audiences/"+audience.ID.String(), nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
// Verify soft delete
|
||||
if repo.audiences[0].IsActive {
|
||||
t.Errorf("Expected audience to be inactive after delete")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_GetAudienceMembers(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
// Create an audience first
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "Test Audience",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences/"+audience.ID.String()+"/members", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d: %s", http.StatusOK, w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Members []orchestrator.AudienceMember `json:"members"`
|
||||
Count int `json:"count"`
|
||||
TotalCount int `json:"total_count"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.TotalCount != 2 {
|
||||
t.Errorf("Expected 2 total members, got %d", response.TotalCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_GetAudienceMembers_WithPagination(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "Test Audience",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences/"+audience.ID.String()+"/members?limit=1&offset=0", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Members []orchestrator.AudienceMember `json:"members"`
|
||||
Count int `json:"count"`
|
||||
Limit int `json:"limit"`
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.Count != 1 {
|
||||
t.Errorf("Expected 1 member in response, got %d", response.Count)
|
||||
}
|
||||
|
||||
if response.Limit != 1 {
|
||||
t.Errorf("Expected limit 1, got %d", response.Limit)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_RefreshAudienceCount(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "Test Audience",
|
||||
IsActive: true,
|
||||
MemberCount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
// Pre-initialize members so count works correctly
|
||||
repo.members = []orchestrator.AudienceMember{
|
||||
{ID: uuid.New(), Name: "Test Person 1"},
|
||||
{ID: uuid.New(), Name: "Test Person 2"},
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/audiences/"+audience.ID.String()+"/refresh", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
var response struct {
|
||||
AudienceID string `json:"audience_id"`
|
||||
MemberCount int `json:"member_count"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.MemberCount != 2 {
|
||||
t.Errorf("Expected member_count 2, got %d", response.MemberCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_CreateExport(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "Test Audience",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
body := CreateExportRequest{
|
||||
ExportType: "csv",
|
||||
Purpose: "Newsletter December 2024",
|
||||
ExportedBy: "admin",
|
||||
}
|
||||
|
||||
bodyJSON, _ := json.Marshal(body)
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/audiences/"+audience.ID.String()+"/exports", bytes.NewBuffer(bodyJSON))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Errorf("Expected status %d, got %d: %s", http.StatusCreated, w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var response orchestrator.AudienceExport
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.ExportType != "csv" {
|
||||
t.Errorf("Expected export_type 'csv', got '%s'", response.ExportType)
|
||||
}
|
||||
|
||||
if response.RecordCount != 2 {
|
||||
t.Errorf("Expected record_count 2, got %d", response.RecordCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_ListExports(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
audience := orchestrator.Audience{
|
||||
ID: uuid.New(),
|
||||
Name: "Test Audience",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
repo.audiences = append(repo.audiences, audience)
|
||||
|
||||
// Add an export
|
||||
export := orchestrator.AudienceExport{
|
||||
ID: uuid.New(),
|
||||
AudienceID: audience.ID,
|
||||
ExportType: "csv",
|
||||
RecordCount: 100,
|
||||
Purpose: "Test export",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
repo.exports = append(repo.exports, export)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences/"+audience.ID.String()+"/exports", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Exports []orchestrator.AudienceExport `json:"exports"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.Count != 1 {
|
||||
t.Errorf("Expected 1 export, got %d", response.Count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudienceHandler_ListAudiences_ActiveOnly(t *testing.T) {
|
||||
repo := NewMockAudienceRepository()
|
||||
router := setupAudienceRouter(repo)
|
||||
|
||||
// Add active and inactive audiences
|
||||
repo.audiences = []orchestrator.Audience{
|
||||
{ID: uuid.New(), Name: "Active", IsActive: true, CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
{ID: uuid.New(), Name: "Inactive", IsActive: false, CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/audiences?active_only=true", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Audiences []orchestrator.Audience `json:"audiences"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
if response.Count != 1 {
|
||||
t.Errorf("Expected 1 active audience, got %d", response.Count)
|
||||
}
|
||||
|
||||
if response.Audiences[0].Name != "Active" {
|
||||
t.Errorf("Expected audience 'Active', got '%s'", response.Audiences[0].Name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user