package service import ( "context" "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/gochat/gochat/internal/model" ) // ========== ListByAccount ========== func TestInboxService_ListByAccount_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) // 预先创建2个inbox createTestInbox(t, db, account.ID, "web_widget") createTestInbox(t, db, account.ID, "api") inboxes, total, err := svc.ListByAccount(context.Background(), account.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(2), total) assert.Len(t, inboxes, 2) } func TestInboxService_ListByAccount_空列表(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inboxes, total, err := svc.ListByAccount(context.Background(), account.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(0), total) assert.Len(t, inboxes, 0) } func TestInboxService_ListByAccount_分页(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) // 创建3个inbox for i := 0; i < 3; i++ { inbox := &model.Inbox{ AccountID: account.ID, Name: "收件箱" + string(rune('A'+i)), ChannelType: "web_widget", Enabled: true, } require.NoError(t, db.Create(inbox).Error) } // 第1页 limit=2 inboxes, total, err := svc.ListByAccount(context.Background(), account.ID, 0, 2) require.NoError(t, err) assert.Equal(t, int64(3), total) assert.Len(t, inboxes, 2) } // ========== GetByID ========== func TestInboxService_GetByID_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") result, err := svc.GetByID(context.Background(), inbox.ID) require.NoError(t, err) assert.Equal(t, inbox.ID, result.ID) assert.Equal(t, "web_widget", result.ChannelType) } func TestInboxService_GetByID_不存在(t *testing.T) { _, _, svc := setupInboxService(t) result, err := svc.GetByID(context.Background(), 9999) assert.Error(t, err) assert.Nil(t, result) } // ========== GetByAccountAndID ========== func TestInboxService_GetByAccountAndID_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") result, err := svc.GetByAccountAndID(context.Background(), account.ID, inbox.ID) require.NoError(t, err) assert.Equal(t, inbox.ID, result.ID) } func TestInboxService_GetByAccountAndID_账户不匹配(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") otherAccount := createTestAccount(t, db) result, err := svc.GetByAccountAndID(context.Background(), otherAccount.ID, inbox.ID) assert.Error(t, err) assert.Nil(t, result) } // ========== Create ========== func TestInboxService_Create_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateInboxRequest{ Name: "新建收件箱", ChannelType: "web_widget", Enabled: true, EnableAutoAssignment: false, } result, err := svc.Create(context.Background(), account.ID, req) require.NoError(t, err) assert.Equal(t, "新建收件箱", result.Name) assert.Equal(t, "web_widget", result.ChannelType) assert.Equal(t, account.ID, result.AccountID) assert.True(t, result.Enabled) assert.NotZero(t, result.ID) } func TestInboxService_Create_各种渠道类型(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) channelTypes := []string{"web_widget", "telegram", "facebook", "whatsapp", "email", "api"} for _, ct := range channelTypes { req := CreateInboxRequest{ Name: ct + "收件箱", ChannelType: ct, Enabled: true, } result, err := svc.Create(context.Background(), account.ID, req) require.NoError(t, err) assert.Equal(t, ct, result.ChannelType) } } func TestInboxService_Create_验证失败_名称过短(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateInboxRequest{ Name: "a", // min=2 不满足 ChannelType: "web_widget", } result, err := svc.Create(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_Create_验证失败_缺少渠道类型(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateInboxRequest{ Name: "有效名称", ChannelType: "", // required } result, err := svc.Create(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_Create_验证失败_无效渠道类型(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateInboxRequest{ Name: "有效名称", ChannelType: "invalid_channel", // oneof 校验失败 } result, err := svc.Create(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } // ========== Update ========== func TestInboxService_Update_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") enabled := false req := UpdateInboxRequest{ Name: "更新后的收件箱", Enabled: &enabled, } result, err := svc.Update(context.Background(), account.ID, inbox.ID, req) require.NoError(t, err) assert.Equal(t, "更新后的收件箱", result.Name) assert.False(t, result.Enabled) } func TestInboxService_Update_验证失败_名称过短(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") req := UpdateInboxRequest{ Name: "x", // min=2 不满足 } result, err := svc.Update(context.Background(), account.ID, inbox.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_Update_不存在(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := UpdateInboxRequest{ Name: "不存在", } result, err := svc.Update(context.Background(), account.ID, 9999, req) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_Update_账户不匹配(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) otherAccount := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") req := UpdateInboxRequest{ Name: "错误账户", } result, err := svc.Update(context.Background(), otherAccount.ID, inbox.ID, req) assert.Error(t, err) assert.Nil(t, result) } // ========== Delete ========== func TestInboxService_Delete_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") err := svc.Delete(context.Background(), inbox.ID) require.NoError(t, err) // 验证软删除后无法找到 result, err := svc.GetByID(context.Background(), inbox.ID) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_Delete_不存在(t *testing.T) { _, _, svc := setupInboxService(t) err := svc.Delete(context.Background(), 9999) assert.NoError(t, err) } // ========== DeleteByAccount ========== func TestInboxService_DeleteByAccount_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") err := svc.DeleteByAccount(context.Background(), account.ID, inbox.ID) require.NoError(t, err) result, err := svc.GetByID(context.Background(), inbox.ID) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_DeleteByAccount_账户不匹配(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) otherAccount := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") err := svc.DeleteByAccount(context.Background(), otherAccount.ID, inbox.ID) assert.Error(t, err) } // ========== WebWidget 相关 ========== func TestInboxService_CreateWebWidgetInbox_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateWebWidgetInboxRequest{ Name: "Widget收件箱", WidgetColor: "#1f73b7", WelcomeTitle: "你好!", WelcomeTagline: "欢迎咨询", GreetingEnabled: true, GreetingMessage: "有什么可以帮您?", ReplyTime: "a_few_minutes", PreChatMessage: "请输入您的姓名", PreChatFieldsEnabled: true, AutoAssignmentEnabled: false, ContinuityViaEmail: true, EnableAutoAssignment: false, } result, err := svc.CreateWebWidgetInbox(context.Background(), account.ID, req) require.NoError(t, err) assert.Equal(t, "Widget收件箱", result.Name) assert.Equal(t, "web_widget", result.ChannelType) assert.True(t, result.Enabled) assert.NotZero(t, result.ID) // 验证 ChannelConfig 包含正确的 JSON 配置 var config WebWidgetConfig err = json.Unmarshal([]byte(result.ChannelConfig), &config) require.NoError(t, err) assert.NotEmpty(t, config.WebsiteToken) assert.NotEmpty(t, config.HMACToken) assert.Equal(t, "#1f73b7", config.WidgetColor) assert.Equal(t, "你好!", config.WelcomeTitle) } func TestInboxService_CreateWebWidgetInbox_验证失败(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateWebWidgetInboxRequest{ Name: "a", // min=2 不满足 } result, err := svc.CreateWebWidgetInbox(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_GetWebWidgetConfig_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) // 先创建一个 web_widget inbox createReq := CreateWebWidgetInboxRequest{ Name: "WidgetConfig测试", WidgetColor: "#333", WelcomeTitle: "Hi", EnableAutoAssignment: false, } inbox, err := svc.CreateWebWidgetInbox(context.Background(), account.ID, createReq) require.NoError(t, err) config, err := svc.GetWebWidgetConfig(context.Background(), account.ID, inbox.ID) require.NoError(t, err) assert.Equal(t, "#333", config.WidgetColor) assert.Equal(t, "Hi", config.WelcomeTitle) assert.NotEmpty(t, config.WebsiteToken) } func TestInboxService_GetWebWidgetConfig_非web_widget渠道(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "api") config, err := svc.GetWebWidgetConfig(context.Background(), account.ID, inbox.ID) assert.Error(t, err) assert.Nil(t, config) assert.Contains(t, err.Error(), "not a web_widget") } func TestInboxService_GetWebWidgetConfig_不存在(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) config, err := svc.GetWebWidgetConfig(context.Background(), account.ID, 9999) assert.Error(t, err) assert.Nil(t, config) } func TestInboxService_UpdateWebWidgetConfig_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) // 先创建 createReq := CreateWebWidgetInboxRequest{ Name: "WidgetConfig更新测试", WidgetColor: "#000", EnableAutoAssignment: false, } inbox, err := svc.CreateWebWidgetInbox(context.Background(), account.ID, createReq) require.NoError(t, err) // 更新 widgetColor := "#fff" welcomeTitle := "新标题" updateReq := UpdateWebWidgetConfigRequest{ WidgetColor: &widgetColor, WelcomeTitle: &welcomeTitle, } result, err := svc.UpdateWebWidgetConfig(context.Background(), account.ID, inbox.ID, updateReq) require.NoError(t, err) assert.Equal(t, "web_widget", result.ChannelType) // 验证更新后的配置 var config WebWidgetConfig err = json.Unmarshal([]byte(result.ChannelConfig), &config) require.NoError(t, err) assert.Equal(t, "#fff", config.WidgetColor) assert.Equal(t, "新标题", config.WelcomeTitle) } func TestInboxService_UpdateWebWidgetConfig_非web_widget渠道(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "api") widgetColor := "#fff" updateReq := UpdateWebWidgetConfigRequest{ WidgetColor: &widgetColor, } result, err := svc.UpdateWebWidgetConfig(context.Background(), account.ID, inbox.ID, updateReq) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_UpdateWebWidgetConfig_不存在(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) widgetColor := "#fff" updateReq := UpdateWebWidgetConfigRequest{ WidgetColor: &widgetColor, } result, err := svc.UpdateWebWidgetConfig(context.Background(), account.ID, 9999, updateReq) assert.Error(t, err) assert.Nil(t, result) } // ========== Telegram 相关 ========== func TestInboxService_CreateTelegramInbox_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "Telegram收件箱", BotToken: "123456:ABC-DEF", WelcomeMessage: "欢迎!", EnableAutoAssignment: false, } result, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) require.NoError(t, err) assert.Equal(t, "Telegram收件箱", result.Name) assert.Equal(t, "telegram", result.ChannelType) assert.True(t, result.Enabled) // 验证 ChannelConfig 包含 Telegram 配置 var config TelegramInboxConfig err = json.Unmarshal([]byte(result.ChannelConfig), &config) require.NoError(t, err) assert.Equal(t, "123456:ABC-DEF", config.BotToken) assert.Equal(t, "欢迎!", config.WelcomeMessage) } func TestInboxService_CreateTelegramInbox_验证失败_缺少BotToken(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "Telegram收件箱", BotToken: "", // required } result, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_CreateTelegramInbox_验证失败_名称过短(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "x", BotToken: "123:abc", } result, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_GetTelegramInboxConfig_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "Telegram配置测试", BotToken: "789:XYZ", } inbox, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) require.NoError(t, err) config, inboxResult, err := svc.GetTelegramInboxConfig(context.Background(), account.ID, inbox.ID) require.NoError(t, err) assert.Equal(t, "789:XYZ", config.BotToken) assert.Equal(t, inbox.ID, inboxResult.ID) } func TestInboxService_GetTelegramInboxConfig_非telegram渠道(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") config, inboxResult, err := svc.GetTelegramInboxConfig(context.Background(), account.ID, inbox.ID) assert.Error(t, err) assert.Nil(t, config) assert.Nil(t, inboxResult) } func TestInboxService_DeleteTelegramInbox_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "Telegram删除测试", BotToken: "111:DEL", } inbox, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) require.NoError(t, err) err = svc.DeleteTelegramInbox(context.Background(), account.ID, inbox.ID) require.NoError(t, err) result, err := svc.GetByID(context.Background(), inbox.ID) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_DeleteTelegramInbox_非telegram渠道(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "api") err := svc.DeleteTelegramInbox(context.Background(), account.ID, inbox.ID) assert.Error(t, err) } func TestInboxService_UpdateTelegramInbox_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "Telegram更新测试", BotToken: "222:UPD", } inbox, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) require.NoError(t, err) newBotToken := "333:NEWUPD" newName := "更新名称" updateReq := UpdateTelegramInboxRequest{ BotToken: &newBotToken, Name: &newName, } result, err := svc.UpdateTelegramInbox(context.Background(), account.ID, inbox.ID, updateReq) require.NoError(t, err) assert.Equal(t, "更新名称", result.Name) var config TelegramInboxConfig err = json.Unmarshal([]byte(result.ChannelConfig), &config) require.NoError(t, err) assert.Equal(t, "333:NEWUPD", config.BotToken) } func TestInboxService_UpdateTelegramInbox_非telegram渠道(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "api") botToken := "123:abc" updateReq := UpdateTelegramInboxRequest{ BotToken: &botToken, } result, err := svc.UpdateTelegramInbox(context.Background(), account.ID, inbox.ID, updateReq) assert.Error(t, err) assert.Nil(t, result) } func TestInboxService_UpdateTelegramConfig_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "Telegram配置更新测试", BotToken: "444:CFGUPD", } inbox, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) require.NoError(t, err) newConfig := TelegramInboxConfig{ BotToken: "555:NEWCFG", WelcomeMessage: "新欢迎消息", WebhookURL: "https://example.com/webhook", } result, err := svc.UpdateTelegramConfig(context.Background(), account.ID, inbox.ID, newConfig) require.NoError(t, err) var parsedConfig TelegramInboxConfig err = json.Unmarshal([]byte(result.ChannelConfig), &parsedConfig) require.NoError(t, err) assert.Equal(t, "555:NEWCFG", parsedConfig.BotToken) assert.Equal(t, "新欢迎消息", parsedConfig.WelcomeMessage) assert.Equal(t, "https://example.com/webhook", parsedConfig.WebhookURL) } func TestInboxService_UpdateTelegramConfig_非telegram渠道(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "api") newConfig := TelegramInboxConfig{ BotToken: "123:abc", } result, err := svc.UpdateTelegramConfig(context.Background(), account.ID, inbox.ID, newConfig) assert.Error(t, err) assert.Nil(t, result) } // ========== FindTelegramInboxByBotToken ========== func TestInboxService_FindTelegramInboxByBotToken_成功(t *testing.T) { db, _, svc := setupInboxService(t) account := createTestAccount(t, db) req := CreateTelegramInboxRequest{ Name: "Telegram查找测试", BotToken: "666:FINDME", } inbox, err := svc.CreateTelegramInbox(context.Background(), account.ID, req) require.NoError(t, err) result, err := svc.FindTelegramInboxByBotToken(context.Background(), "666:FINDME") require.NoError(t, err) assert.Equal(t, inbox.ID, result.ID) assert.Equal(t, "telegram", result.ChannelType) } func TestInboxService_FindTelegramInboxByBotToken_不存在(t *testing.T) { _, _, svc := setupInboxService(t) result, err := svc.FindTelegramInboxByBotToken(context.Background(), "999:NOTEXIST") assert.Error(t, err) assert.Nil(t, result) }