package repository import ( "context" "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/gochat/gochat/internal/model" ) func TestWebhookSubscriptionRepo_FindByID(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) sub := &model.WebhookSubscription{ AccountID: 1, URL: "https://example.com/hook", Events: json.RawMessage(`["conversation_created"]`), Secret: "secret123", Active: true, } require.NoError(t, db.Create(sub).Error) found, err := repo.FindByID(context.Background(), sub.ID) assert.NoError(t, err) assert.Equal(t, sub.URL, found.URL) assert.Equal(t, sub.AccountID, found.AccountID) } func TestWebhookSubscriptionRepo_FindByID_NotFound(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) found, err := repo.FindByID(context.Background(), 9999) assert.Error(t, err) assert.Nil(t, found) } func TestWebhookSubscriptionRepo_GetByID(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) sub := &model.WebhookSubscription{ AccountID: 1, URL: "https://example.com/hook2", Events: json.RawMessage(`["message_created"]`), Secret: "secret456", Active: true, } require.NoError(t, db.Create(sub).Error) found, err := repo.GetByID(context.Background(), sub.ID) assert.NoError(t, err) assert.Equal(t, sub.ID, found.ID) } func TestWebhookSubscriptionRepo_ListByAccount(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) // Create an account to satisfy FK acct := &model.Account{Name: "WHListOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) activeSub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/active", Events: json.RawMessage(`["conversation_created"]`), Secret: "s1", Active: true, } inactiveSub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/inactive", Events: json.RawMessage(`["message_created"]`), Secret: "s2", Active: false, } require.NoError(t, db.Create(activeSub).Error) require.NoError(t, db.Create(inactiveSub).Error) // ListByAccount returns only active subscriptions subs, err := repo.ListByAccount(context.Background(), acct.ID) assert.NoError(t, err) assert.Len(t, subs, 1) assert.Equal(t, activeSub.ID, subs[0].ID) } func TestWebhookSubscriptionRepo_ListActiveByAccount(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHActiveOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) sub1 := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/a1", Events: json.RawMessage(`["conversation_created"]`), Secret: "s1", Active: true, } sub2 := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/a2", Events: json.RawMessage(`["message_updated"]`), Secret: "s2", Active: true, } inactive := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/a3", Events: json.RawMessage(`["message_created"]`), Secret: "s3", Active: false, } require.NoError(t, db.Create(sub1).Error) require.NoError(t, db.Create(sub2).Error) require.NoError(t, db.Create(inactive).Error) subs, err := repo.ListActiveByAccount(context.Background(), acct.ID) assert.NoError(t, err) assert.Len(t, subs, 2) } func TestWebhookSubscriptionRepo_ListByAccountAndEvent(t *testing.T) { skipIfSQLite(t) // uses PG jsonb @> operator db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHEvOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) subWithEvent := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/ev1", Events: json.RawMessage(`["conversation_created","message_created"]`), Secret: "s1", Active: true, } subWithoutEvent := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/ev2", Events: json.RawMessage(`["message_updated"]`), Secret: "s2", Active: true, } require.NoError(t, db.Create(subWithEvent).Error) require.NoError(t, db.Create(subWithoutEvent).Error) // Filter by event "conversation_created" subs, err := repo.ListByAccountAndEvent(context.Background(), acct.ID, `["conversation_created"]`) assert.NoError(t, err) assert.Len(t, subs, 1) assert.Equal(t, subWithEvent.ID, subs[0].ID) } func TestWebhookSubscriptionRepo_Create(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHCreateOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) sub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/new", Events: json.RawMessage(`["conversation_created"]`), Secret: "newsecret", Active: true, } err := repo.Create(context.Background(), sub) assert.NoError(t, err) assert.NotZero(t, sub.ID) // Verify persisted found, err := repo.FindByID(context.Background(), sub.ID) assert.NoError(t, err) assert.Equal(t, "https://example.com/new", found.URL) } func TestWebhookSubscriptionRepo_Update(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHUpdateOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) sub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/old", Events: json.RawMessage(`["conversation_created"]`), Secret: "oldsecret", Active: true, } require.NoError(t, repo.Create(context.Background(), sub)) sub.URL = "https://example.com/updated" sub.Active = false require.NoError(t, repo.Update(context.Background(), sub)) found, err := repo.FindByID(context.Background(), sub.ID) assert.NoError(t, err) assert.Equal(t, "https://example.com/updated", found.URL) assert.False(t, found.Active) } func TestWebhookSubscriptionRepo_Delete(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHDeleteOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) sub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/to-delete", Events: json.RawMessage(`["conversation_created"]`), Secret: "delsecret", Active: true, } require.NoError(t, repo.Create(context.Background(), sub)) err := repo.Delete(context.Background(), sub.ID) assert.NoError(t, err) // Soft-delete: normal query won't find it found, err := repo.FindByID(context.Background(), sub.ID) assert.Error(t, err) assert.Nil(t, found) } func TestWebhookSubscriptionRepo_CreateDelivery(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHDelOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) sub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/del-hook", Events: json.RawMessage(`["conversation_created"]`), Secret: "delsecret", Active: true, } require.NoError(t, repo.Create(context.Background(), sub)) delivery := &model.WebhookDelivery{ SubscriptionID: sub.ID, EventType: "conversation_created", Payload: json.RawMessage(`{"id":1}`), Status: model.WebhookDeliveryStatusPending, Attempts: 0, } err := repo.CreateDelivery(context.Background(), delivery) assert.NoError(t, err) assert.NotZero(t, delivery.ID) } func TestWebhookSubscriptionRepo_UpdateDelivery(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHDelUpOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) sub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/del-up-hook", Events: json.RawMessage(`["message_created"]`), Secret: "delsecret2", Active: true, } require.NoError(t, repo.Create(context.Background(), sub)) delivery := &model.WebhookDelivery{ SubscriptionID: sub.ID, EventType: "message_created", Payload: json.RawMessage(`{"id":2}`), Status: model.WebhookDeliveryStatusPending, Attempts: 0, } require.NoError(t, repo.CreateDelivery(context.Background(), delivery)) delivery.Status = model.WebhookDeliveryStatusSuccess delivery.Attempts = 1 delivery.ResponseCode = 200 require.NoError(t, repo.UpdateDelivery(context.Background(), delivery)) deliveries, err := repo.ListDeliveriesBySubscription(context.Background(), sub.ID, 10) assert.NoError(t, err) assert.Len(t, deliveries, 1) assert.Equal(t, model.WebhookDeliveryStatusSuccess, deliveries[0].Status) assert.Equal(t, 200, deliveries[0].ResponseCode) assert.Equal(t, 1, deliveries[0].Attempts) } func TestWebhookSubscriptionRepo_ListDeliveriesBySubscription(t *testing.T) { db := setupTestDB(t, &model.WebhookSubscription{}, &model.WebhookDelivery{}) repo := NewWebhookSubscriptionRepo(db) acct := &model.Account{Name: "WHDelListOrg", Locale: "en", Active: true} require.NoError(t, db.Create(acct).Error) sub := &model.WebhookSubscription{ AccountID: acct.ID, URL: "https://example.com/del-list-hook", Events: json.RawMessage(`["conversation_created","message_created"]`), Secret: "delsecret3", Active: true, } require.NoError(t, repo.Create(context.Background(), sub)) for i := 0; i < 5; i++ { delivery := &model.WebhookDelivery{ SubscriptionID: sub.ID, EventType: "conversation_created", Payload: json.RawMessage(`{"seq":` + json.Number(string(i+1)) + `}`), Status: model.WebhookDeliveryStatusPending, Attempts: 0, } require.NoError(t, repo.CreateDelivery(context.Background(), delivery)) } // List with limit 3 deliveries, err := repo.ListDeliveriesBySubscription(context.Background(), sub.ID, 3) assert.NoError(t, err) assert.Len(t, deliveries, 3) // List with limit 10 (all) allDeliveries, err := repo.ListDeliveriesBySubscription(context.Background(), sub.ID, 10) assert.NoError(t, err) assert.Len(t, allDeliveries, 5) }