package service import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/gochat/gochat/internal/model" ) // ========== ListByAccount ========== func TestConversationService_ListByAccount_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) // 创建2个对话 for i := 0; i < 2; i++ { conv := &model.Conversation{ AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", ChannelType: "对话" + string(rune('A'+i)), } require.NoError(t, db.Create(conv).Error) } conversations, total, err := svc.ListByAccount(context.Background(), account.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(2), total) assert.Len(t, conversations, 2) } func TestConversationService_ListByAccount_空列表(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) conversations, total, err := svc.ListByAccount(context.Background(), account.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(0), total) assert.Len(t, conversations, 0) } func TestConversationService_ListByAccount_分页(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) for i := 0; i < 5; i++ { conv := &model.Conversation{ AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", } require.NoError(t, db.Create(conv).Error) } // 第1页,limit=2 convs, total, err := svc.ListByAccount(context.Background(), account.ID, 0, 2) require.NoError(t, err) assert.Equal(t, int64(5), total) assert.Len(t, convs, 2) } // ========== GetByID ========== func TestConversationService_GetByID_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) result, err := svc.GetByID(context.Background(), conv.ID) require.NoError(t, err) assert.Equal(t, conv.ID, result.ID) assert.Equal(t, "open", result.Status) } func TestConversationService_GetByID_不存在(t *testing.T) { _, _, _, svc := setupConversationService(t) result, err := svc.GetByID(context.Background(), 9999) assert.Error(t, err) assert.Nil(t, result) } // ========== GetByAccountAndID ========== func TestConversationService_GetByAccountAndID_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) result, err := svc.GetByAccountAndID(context.Background(), account.ID, conv.ID) require.NoError(t, err) assert.Equal(t, conv.ID, result.ID) } func TestConversationService_GetByAccountAndID_账户不匹配(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) otherAccount := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) result, err := svc.GetByAccountAndID(context.Background(), otherAccount.ID, conv.ID) assert.Error(t, err) assert.Nil(t, result) } // ========== ListByInbox ========== func TestConversationService_ListByInbox_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) for i := 0; i < 3; i++ { conv := &model.Conversation{ AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", } require.NoError(t, db.Create(conv).Error) } conversations, total, err := svc.ListByInbox(context.Background(), account.ID, inbox.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(3), total) assert.Len(t, conversations, 3) } func TestConversationService_ListByInbox_空列表(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") conversations, total, err := svc.ListByInbox(context.Background(), account.ID, inbox.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(0), total) assert.Len(t, conversations, 0) } // ========== Create ========== func TestConversationService_Create_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) req := CreateConversationRequest{ InboxID: inbox.ID, ContactID: contact.ID, Status: "open", Priority: "medium", } result, err := svc.Create(context.Background(), account.ID, req) require.NoError(t, err) assert.Equal(t, inbox.ID, result.InboxID) assert.Equal(t, contact.ID, result.ContactID) assert.Equal(t, "open", result.Status) assert.Equal(t, "medium", result.Priority) assert.Equal(t, account.ID, result.AccountID) assert.NotZero(t, result.ID) } func TestConversationService_Create_验证失败_缺少InboxID(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) contact := createTestContact(t, db, account.ID) req := CreateConversationRequest{ InboxID: 0, // required ContactID: contact.ID, Status: "open", } result, err := svc.Create(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_Create_验证失败_缺少ContactID(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") req := CreateConversationRequest{ InboxID: inbox.ID, ContactID: 0, // required Status: "open", } result, err := svc.Create(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_Create_验证失败_无效Status(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) req := CreateConversationRequest{ InboxID: inbox.ID, ContactID: contact.ID, Status: "invalid_status", // oneof 校验 } result, err := svc.Create(context.Background(), account.ID, req) assert.Error(t, err) assert.Nil(t, result) } // ========== Update ========== func TestConversationService_Update_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) req := UpdateConversationRequest{ Status: "resolved", Priority: "high", } result, err := svc.Update(context.Background(), account.ID, conv.ID, req) require.NoError(t, err) assert.Equal(t, "resolved", result.Status) assert.Equal(t, "high", result.Priority) } func TestConversationService_Update_部分更新(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) req := UpdateConversationRequest{ Status: "pending", } result, err := svc.Update(context.Background(), account.ID, conv.ID, req) require.NoError(t, err) assert.Equal(t, "pending", result.Status) } func TestConversationService_Update_验证失败_无效Status(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) req := UpdateConversationRequest{ Status: "bad_status", } result, err := svc.Update(context.Background(), account.ID, conv.ID, req) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_Update_不存在(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) req := UpdateConversationRequest{ Status: "resolved", } result, err := svc.Update(context.Background(), account.ID, 9999, req) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_Update_账户不匹配(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) otherAccount := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) req := UpdateConversationRequest{ Status: "resolved", } result, err := svc.Update(context.Background(), otherAccount.ID, conv.ID, req) assert.Error(t, err) assert.Nil(t, result) } // ========== Delete ========== func TestConversationService_Delete_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) err := svc.Delete(context.Background(), account.ID, conv.ID) require.NoError(t, err) // 验证软删除后无法找到 result, err := svc.GetByID(context.Background(), conv.ID) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_Delete_不存在(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) err := svc.Delete(context.Background(), account.ID, 9999) assert.Error(t, err) } func TestConversationService_Delete_账户不匹配(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) otherAccount := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) err := svc.Delete(context.Background(), otherAccount.ID, conv.ID) assert.Error(t, err) } // ========== Assign ========== func TestConversationService_Assign_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) // 创建用户作为assignee user := createTestUser(t, db, account.ID) result, err := svc.AssignAgent(context.Background(), account.ID, conv.ID, user.ID) require.NoError(t, err) require.NotNil(t, result.AssigneeID) assert.Equal(t, user.ID, *result.AssigneeID) } func TestConversationService_Assign_验证失败_缺少AssigneeID(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) result, err := svc.AssignAgent(context.Background(), account.ID, conv.ID, 0) // assigneeID=0 不合法 assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_AssignAgent_不存在(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) user := createTestUser(t, db, account.ID) result, err := svc.AssignAgent(context.Background(), account.ID, 9999, user.ID) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_AssignAgent_账户不匹配(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) otherAccount := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) user := createTestUser(t, db, account.ID) result, err := svc.AssignAgent(context.Background(), otherAccount.ID, conv.ID, user.ID) assert.Error(t, err) assert.Nil(t, result) } // ========== ToggleStatus ========== func TestConversationService_ToggleStatus_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) result, err := svc.ToggleStatus(context.Background(), account.ID, conv.ID, "resolved") require.NoError(t, err) assert.Equal(t, "resolved", result.Status) } // ========== ListByStatus ========== func TestConversationService_ListByStatus_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) // 创建 open 和 resolved 对话 openConv := &model.Conversation{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open"} resolvedConv := &model.Conversation{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "resolved"} require.NoError(t, db.Create(openConv).Error) require.NoError(t, db.Create(resolvedConv).Error) convs, total, err := svc.ListByStatus(context.Background(), account.ID, "open", 0, 10) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, convs, 1) assert.Equal(t, "open", convs[0].Status) } func TestConversationService_ListByStatus_无匹配(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := &model.Conversation{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open"} require.NoError(t, db.Create(conv).Error) convs, total, err := svc.ListByStatus(context.Background(), account.ID, "resolved", 0, 10) require.NoError(t, err) assert.Equal(t, int64(0), total) assert.Len(t, convs, 0) } // ========== UpdateLabels ========== func TestConversationService_UpdateLabels_成功(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) result, err := svc.UpdateLabels(context.Background(), account.ID, conv.ID, []string{"bug", "feature"}) require.NoError(t, err) assert.Contains(t, result.Labels, "bug") assert.Contains(t, result.Labels, "feature") } func TestConversationService_UpdateLabels_不存在(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) result, err := svc.UpdateLabels(context.Background(), account.ID, 9999, []string{"bug"}) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_UpdateLabels_账户不匹配(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) otherAccount := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) result, err := svc.UpdateLabels(context.Background(), otherAccount.ID, conv.ID, []string{"bug"}) assert.Error(t, err) assert.Nil(t, result) } func TestConversationService_UpdateLabels_替换标签(t *testing.T) { db, _, _, svc := setupConversationService(t) account := createTestAccount(t, db) inbox := createTestInbox(t, db, account.ID, "web_widget") contact := createTestContact(t, db, account.ID) conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID) // 先设置标签 result, err := svc.UpdateLabels(context.Background(), account.ID, conv.ID, []string{"bug", "feature"}) require.NoError(t, err) assert.Contains(t, result.Labels, "bug") // 替换为不同标签 result, err = svc.UpdateLabels(context.Background(), account.ID, conv.ID, []string{"urgent"}) require.NoError(t, err) assert.Contains(t, result.Labels, "urgent") }