Files
gochat/internal/service/contact_merge_service_test.go
T

125 lines
4.6 KiB
Go

package service
import (
"encoding/json"
"testing"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"gorm.io/datatypes"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type ContactMergeServiceTestSuite struct {
suite.Suite
db *gorm.DB
svc *ContactMergeService
}
func (s *ContactMergeServiceTestSuite) SetupTest() {
db, err := gorm.Open(sqlite.Open("file:merge_test?mode=memory&_busy_timeout=5000"), &gorm.Config{})
assert.NoError(s.T(), err)
s.db = db
s.db.AutoMigrate(
&model.Contact{},
&model.Conversation{},
&model.Message{},
&model.ContactInbox{},
&model.ContactNote{},
&model.Note{},
)
mergeRepo := repository.NewContactMergeRepo(db)
s.svc = NewContactMergeService(mergeRepo, db)
}
func (s *ContactMergeServiceTestSuite) TearDownTest() {
if s.db != nil {
sqlDB, _ := s.db.DB()
sqlDB.Close()
}
}
func TestContactMergeServiceSuite(t *testing.T) {
suite.Run(t, new(ContactMergeServiceTestSuite))
}
func (s *ContactMergeServiceTestSuite) TestMerge_SameContact() {
// Create a contact so same-ID merge can find it
s.db.Create(&model.Contact{Base: model.Base{}, AccountID: 1, Name: "same"})
_, err := s.svc.Merge(1, 1, 1)
// Same contact should succeed — Chatwoot returns base_contact if base.id == mergee.id
assert.NoError(s.T(), err)
}
func (s *ContactMergeServiceTestSuite) TestMerge_BaseNotFound() {
s.db.Create(&model.Contact{Base: model.Base{}, AccountID: 1, Name: "mergee"})
_, err := s.svc.Merge(1, 999, 2)
assert.Error(s.T(), err)
}
func (s *ContactMergeServiceTestSuite) TestMerge_Success() {
base := &model.Contact{
Base: model.Base{},
AccountID: 1,
Name: "base",
Email: "base@example.com",
Identifier: "base-id",
AdditionalAttributes: datatypes.JSON(`{"city":"base","nested":{"keep":"base"}}`),
CustomAttributes: datatypes.JSON(`{"tier":"gold","base_only":"yes"}`),
}
mergee := &model.Contact{
Base: model.Base{},
AccountID: 1,
Name: "mergee",
Email: "mergee@example.com",
PhoneNumber: "+12212345",
AdditionalAttributes: datatypes.JSON(`{"city":"mergee","mergee_only":"yes","nested":{"new":"mergee"}}`),
CustomAttributes: datatypes.JSON(`{"tier":"silver","mergee_only":"yes"}`),
}
s.db.Create(base)
s.db.Create(mergee)
s.db.Create(&model.Conversation{AccountID: 1, InboxID: 1, ContactID: mergee.ID, Status: "open", ChannelType: "Channel::WebWidget", Channel: "web_widget"})
s.db.Create(&model.ContactInbox{ContactID: mergee.ID, InboxID: 1, SourceID: "source-mergee"})
s.db.Create(&model.Note{AccountID: 1, ContactID: mergee.ID, Content: "mergee note"})
s.db.Create(&model.Message{AccountID: 1, InboxID: 1, ConversationID: 1, SenderID: &mergee.ID, SenderType: "contact", Content: "lowercase sender", ContentType: "text"})
s.db.Create(&model.Message{AccountID: 1, InboxID: 1, ConversationID: 1, SenderID: &mergee.ID, SenderType: string(model.SenderTypeContact), Content: "polymorphic sender", ContentType: "text"})
result, err := s.svc.Merge(1, base.ID, mergee.ID)
assert.NoError(s.T(), err)
assert.Equal(s.T(), "base", result.Name)
assert.Equal(s.T(), "base@example.com", result.Email)
assert.Equal(s.T(), "base-id", result.Identifier)
assert.Equal(s.T(), "+12212345", result.PhoneNumber)
var attrs map[string]any
assert.NoError(s.T(), json.Unmarshal(result.CustomAttributes, &attrs))
assert.Equal(s.T(), "gold", attrs["tier"])
assert.Equal(s.T(), "yes", attrs["base_only"])
assert.Equal(s.T(), "yes", attrs["mergee_only"])
var additional map[string]any
assert.NoError(s.T(), json.Unmarshal(result.AdditionalAttributes, &additional))
assert.Equal(s.T(), "base", additional["city"])
assert.Equal(s.T(), "yes", additional["mergee_only"])
nested := additional["nested"].(map[string]any)
assert.Equal(s.T(), "base", nested["keep"])
assert.Equal(s.T(), "mergee", nested["new"])
// Verify mergee is soft-deleted — GORM Delete sets deleted_at
var count int64
s.db.Model(&model.Contact{}).Where("id = ?", mergee.ID).Count(&count)
assert.Equal(s.T(), int64(0), count) // GORM soft-delete: filtered out by default
s.db.Model(&model.Conversation{}).Where("contact_id = ?", base.ID).Count(&count)
assert.Equal(s.T(), int64(1), count)
s.db.Model(&model.ContactInbox{}).Where("contact_id = ?", base.ID).Count(&count)
assert.Equal(s.T(), int64(1), count)
s.db.Model(&model.Note{}).Where("contact_id = ?", base.ID).Count(&count)
assert.Equal(s.T(), int64(1), count)
s.db.Model(&model.Message{}).Where("sender_id = ?", base.ID).Count(&count)
assert.Equal(s.T(), int64(2), count)
}