package repository import ( "context" "testing" "time" "github.com/user-management-system/internal/domain" ) func setupWebhookRepository(t *testing.T) *WebhookRepository { t.Helper() db := openTestDB(t) if err := db.AutoMigrate(&domain.Webhook{}, &domain.WebhookDelivery{}); err != nil { t.Fatalf("migrate webhook tables failed: %v", err) } return NewWebhookRepository(db) } func newWebhookFixture(name string, createdBy int64, status domain.WebhookStatus) *domain.Webhook { return &domain.Webhook{ Name: name, URL: "https://example.com/webhook", Secret: "secret-demo", Events: `["user.registered"]`, Status: status, MaxRetries: 3, TimeoutSec: 10, CreatedBy: createdBy, } } func TestWebhookRepositoryCreateGetUpdateAndDelete(t *testing.T) { repo := setupWebhookRepository(t) ctx := context.Background() webhook := newWebhookFixture("alpha", 101, domain.WebhookStatusActive) if err := repo.Create(ctx, webhook); err != nil { t.Fatalf("Create failed: %v", err) } if webhook.ID == 0 { t.Fatal("expected webhook id to be assigned") } loaded, err := repo.GetByID(ctx, webhook.ID) if err != nil { t.Fatalf("GetByID failed: %v", err) } if loaded.Name != "alpha" { t.Fatalf("expected loaded webhook name alpha, got %q", loaded.Name) } if err := repo.Update(ctx, webhook.ID, map[string]interface{}{ "name": "alpha-updated", "status": domain.WebhookStatusInactive, }); err != nil { t.Fatalf("Update failed: %v", err) } updated, err := repo.GetByID(ctx, webhook.ID) if err != nil { t.Fatalf("GetByID after update failed: %v", err) } if updated.Name != "alpha-updated" { t.Fatalf("expected updated name alpha-updated, got %q", updated.Name) } if updated.Status != domain.WebhookStatusInactive { t.Fatalf("expected updated status inactive, got %d", updated.Status) } if err := repo.Delete(ctx, webhook.ID); err != nil { t.Fatalf("Delete failed: %v", err) } if _, err := repo.GetByID(ctx, webhook.ID); err == nil { t.Fatal("expected deleted webhook lookup to fail") } } func TestWebhookRepositoryListsByCreatorAndActiveStatus(t *testing.T) { repo := setupWebhookRepository(t) ctx := context.Background() fixtures := []*domain.Webhook{ newWebhookFixture("creator-1-active", 1, domain.WebhookStatusActive), newWebhookFixture("creator-1-inactive", 1, domain.WebhookStatusInactive), newWebhookFixture("creator-2-active", 2, domain.WebhookStatusActive), } for _, webhook := range fixtures { if err := repo.Create(ctx, webhook); err != nil { t.Fatalf("Create(%s) failed: %v", webhook.Name, err) } } creatorOneHooks, err := repo.ListByCreator(ctx, 1) if err != nil { t.Fatalf("ListByCreator(1) failed: %v", err) } if len(creatorOneHooks) != 2 { t.Fatalf("expected 2 hooks for creator 1, got %d", len(creatorOneHooks)) } allHooks, err := repo.ListByCreator(ctx, 0) if err != nil { t.Fatalf("ListByCreator(0) failed: %v", err) } if len(allHooks) != 3 { t.Fatalf("expected 3 hooks when listing all creators, got %d", len(allHooks)) } activeHooks, err := repo.ListActive(ctx) if err != nil { t.Fatalf("ListActive failed: %v", err) } if len(activeHooks) != 2 { t.Fatalf("expected 2 active hooks, got %d", len(activeHooks)) } for _, hook := range activeHooks { if hook.Status != domain.WebhookStatusActive { t.Fatalf("expected active hook status, got %d", hook.Status) } } } func TestWebhookRepositoryCreateAndListDeliveries(t *testing.T) { repo := setupWebhookRepository(t) ctx := context.Background() webhook := newWebhookFixture("delivery-hook", 7, domain.WebhookStatusActive) if err := repo.Create(ctx, webhook); err != nil { t.Fatalf("Create webhook failed: %v", err) } olderTime := time.Now().Add(-time.Minute) newerTime := time.Now() firstDelivery := &domain.WebhookDelivery{ WebhookID: webhook.ID, EventType: domain.EventUserRegistered, Payload: `{"user":"older"}`, StatusCode: 200, ResponseBody: `{"ok":true}`, Attempt: 1, Success: true, CreatedAt: olderTime, } secondDelivery := &domain.WebhookDelivery{ WebhookID: webhook.ID, EventType: domain.EventUserLogin, Payload: `{"user":"newer"}`, StatusCode: 500, ResponseBody: `{"ok":false}`, Attempt: 2, Success: false, Error: "delivery failed", CreatedAt: newerTime, } if err := repo.CreateDelivery(ctx, firstDelivery); err != nil { t.Fatalf("CreateDelivery(first) failed: %v", err) } if err := repo.CreateDelivery(ctx, secondDelivery); err != nil { t.Fatalf("CreateDelivery(second) failed: %v", err) } latestOnly, err := repo.ListDeliveries(ctx, webhook.ID, 1) if err != nil { t.Fatalf("ListDeliveries(limit=1) failed: %v", err) } if len(latestOnly) != 1 { t.Fatalf("expected 1 latest delivery, got %d", len(latestOnly)) } if latestOnly[0].ID != secondDelivery.ID { t.Fatalf("expected latest delivery id %d, got %d", secondDelivery.ID, latestOnly[0].ID) } allDeliveries, err := repo.ListDeliveries(ctx, webhook.ID, 10) if err != nil { t.Fatalf("ListDeliveries(limit=10) failed: %v", err) } if len(allDeliveries) != 2 { t.Fatalf("expected 2 deliveries, got %d", len(allDeliveries)) } if allDeliveries[0].ID != secondDelivery.ID || allDeliveries[1].ID != firstDelivery.ID { t.Fatal("expected deliveries to be returned in reverse created_at order") } }