Files
gochat/backend/internal/service/conversation_service_test.go_BAK
T
rogee aeddedf2a3 Reorganize repo: backend/, deploy/, docs/ layout + AGENTS.md
Restructure the monorepo into clear top-level directories:
- backend/: Go module root (cmd, internal, pkg, configs, migrations,
  docs/swagger, scripts, tests, go.mod, Makefile, .air.toml)
- deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd
- docs/: project documentation + reports/ (moved from repo root)
- AGENTS.md: new AI coding-agent guide at repo root

Update all references to the new layout:
- Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root)
- docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile,
  env_file ../../.env, volume mounts ../../backend:/app
- deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile
- CI: working-directory: backend for go commands, file deploy/docker/Dockerfile,
  coverage path backend/coverage.out, health_check backend/scripts/
- backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../
- README: architecture tree, quickstart, config paths updated

Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh,
gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to
preserve history. Build, vet, SQLite tests, and docker compose config verified.
2026-07-07 14:44:12 +08:00

507 lines
17 KiB
Plaintext

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")
}