package service import ( "context" "encoding/json" "testing" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/gorm" ) // setupWebhookSubscriptionService 创建 WebhookSubscriptionRepo + WebhookSubscriptionService 测试实例。 func setupWebhookSubscriptionService(t *testing.T) (*gorm.DB, *repository.WebhookSubscriptionRepo, *WebhookSubscriptionService) { t.Helper() db := setupServiceTestDB(t) repo := repository.NewWebhookSubscriptionRepo(db) svc := NewWebhookSubscriptionService(repo) return db, repo, svc } // createTestWebhookSubscription 在数据库中创建一个测试 WebhookSubscription 并返回。 func createTestWebhookSubscription(t *testing.T, db *gorm.DB, accountID uint, url string, events []string) *model.WebhookSubscription { t.Helper() eventsJSON, err := json.Marshal(events) if err != nil { t.Fatalf("无法序列化事件列表: %v", err) } sub := &model.WebhookSubscription{ AccountID: accountID, URL: url, Events: eventsJSON, Secret: "test-secret-key", Active: true, } if err := db.Create(sub).Error; err != nil { t.Fatalf("无法创建测试 Webhook 订阅: %v", err) } return sub } // ========== ListSubscriptions ========== func TestWebhookSubscriptionService_ListSubscriptions_成功(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) // 创建多个订阅 createTestWebhookSubscription(t, db, account.ID, "https://example.com/hook1", []string{"message_created"}) createTestWebhookSubscription(t, db, account.ID, "https://example.com/hook2", []string{"conversation_created"}) subs, err := svc.ListSubscriptions(context.Background(), account.ID) require.NoError(t, err) assert.Len(t, subs, 2) } func TestWebhookSubscriptionService_ListSubscriptions_无订阅(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) subs, err := svc.ListSubscriptions(context.Background(), account.ID) require.NoError(t, err) assert.Len(t, subs, 0) } // ========== CreateSubscription ========== func TestWebhookSubscriptionService_CreateSubscription_成功(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) events := []string{"message_created", "conversation_created"} sub, err := svc.CreateSubscription(context.Background(), account.ID, "https://example.com/webhook", events) require.NoError(t, err) assert.Equal(t, account.ID, sub.AccountID) assert.Equal(t, "https://example.com/webhook", sub.URL) assert.True(t, sub.Active) assert.NotZero(t, sub.ID) // 验证 secret 已自动生成 assert.NotEmpty(t, sub.Secret) assert.Len(t, sub.Secret, 64) // 32 bytes hex-encoded = 64 chars // 验证 Events 是有效的 JSON var parsedEvents []string err = json.Unmarshal(sub.Events, &parsedEvents) require.NoError(t, err) assert.Equal(t, events, parsedEvents) } // ========== UpdateSubscription ========== func TestWebhookSubscriptionService_UpdateSubscription_成功(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) sub := createTestWebhookSubscription(t, db, account.ID, "https://old.example.com/hook", []string{"message_created"}) newURL := "https://new.example.com/hook" newEvents := []string{"conversation_created", "message_updated"} updated, err := svc.UpdateSubscription(context.Background(), sub.ID, newURL, newEvents, true) require.NoError(t, err) assert.Equal(t, newURL, updated.URL) // 验证 Events 已更新 var parsedEvents []string err = json.Unmarshal(updated.Events, &parsedEvents) require.NoError(t, err) assert.Equal(t, newEvents, parsedEvents) assert.True(t, updated.Active) } func TestWebhookSubscriptionService_UpdateSubscription_仅URL(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) sub := createTestWebhookSubscription(t, db, account.ID, "https://old.example.com/hook", []string{"message_created"}) updated, err := svc.UpdateSubscription(context.Background(), sub.ID, "https://updated.example.com/hook", nil, true) require.NoError(t, err) assert.Equal(t, "https://updated.example.com/hook", updated.URL) // Events 应保持不变 var parsedEvents []string err = json.Unmarshal(updated.Events, &parsedEvents) require.NoError(t, err) assert.Equal(t, []string{"message_created"}, parsedEvents) } func TestWebhookSubscriptionService_UpdateSubscription_不存在(t *testing.T) { _, _, svc := setupWebhookSubscriptionService(t) updated, err := svc.UpdateSubscription(context.Background(), 9999, "https://example.com/hook", []string{"event"}, true) assert.Error(t, err) assert.Nil(t, updated) } // ========== DeleteSubscription ========== func TestWebhookSubscriptionService_DeleteSubscription_成功(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) sub := createTestWebhookSubscription(t, db, account.ID, "https://example.com/hook", []string{"message_created"}) err := svc.DeleteSubscription(context.Background(), sub.ID) require.NoError(t, err) // 验证订阅已被删除 var count int64 db.Model(&model.WebhookSubscription{}).Where("id = ?", sub.ID).Count(&count) assert.Equal(t, int64(0), count) } func TestWebhookSubscriptionService_DeleteSubscription_不存在(t *testing.T) { _, _, svc := setupWebhookSubscriptionService(t) err := svc.DeleteSubscription(context.Background(), 9999) assert.Error(t, err) } // ========== GetSubscription ========== func TestWebhookSubscriptionService_GetSubscription_成功(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) sub := createTestWebhookSubscription(t, db, account.ID, "https://example.com/hook", []string{"message_created"}) result, err := svc.GetSubscription(context.Background(), sub.ID) require.NoError(t, err) assert.Equal(t, sub.ID, result.ID) assert.Equal(t, sub.URL, result.URL) assert.Equal(t, account.ID, result.AccountID) } func TestWebhookSubscriptionService_GetSubscription_不存在(t *testing.T) { _, _, svc := setupWebhookSubscriptionService(t) result, err := svc.GetSubscription(context.Background(), 9999) assert.Error(t, err) assert.Nil(t, result) } // ========== ListDeliveries ========== func TestWebhookSubscriptionService_ListDeliveries_成功(t *testing.T) { db, repo, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) sub := createTestWebhookSubscription(t, db, account.ID, "https://example.com/hook", []string{"message_created"}) // 直接通过 repo 创建投递记录 ctx := context.Background() delivery1 := &model.WebhookDelivery{ SubscriptionID: sub.ID, EventType: "message_created", Payload: json.RawMessage(`{"id":1}`), Status: "success", Attempts: 1, } require.NoError(t, repo.CreateDelivery(ctx, delivery1)) delivery2 := &model.WebhookDelivery{ SubscriptionID: sub.ID, EventType: "conversation_created", Payload: json.RawMessage(`{"id":2}`), Status: "pending", Attempts: 0, } require.NoError(t, repo.CreateDelivery(ctx, delivery2)) deliveries, err := svc.ListDeliveries(context.Background(), sub.ID, 10) require.NoError(t, err) assert.Len(t, deliveries, 2) } func TestWebhookSubscriptionService_ListDeliveries_无投递记录(t *testing.T) { db, _, svc := setupWebhookSubscriptionService(t) account := createTestAccount(t, db) sub := createTestWebhookSubscription(t, db, account.ID, "https://example.com/hook", []string{"message_created"}) deliveries, err := svc.ListDeliveries(context.Background(), sub.ID, 10) require.NoError(t, err) assert.Len(t, deliveries, 0) }