Files
gochat/internal/service/company_service_test.go
T

619 lines
20 KiB
Go

package service
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/datatypes"
"gorm.io/gorm"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
"github.com/gochat/gochat/internal/search"
)
type mockCompanySearchReader struct {
results []search.SearchResult
total int64
filter *search.SearchFilter
query string
}
func (m *mockCompanySearchReader) SearchCompanies(ctx context.Context, accountID uint, query string, filter *search.SearchFilter) ([]search.SearchResult, int64, error) {
m.query = query
m.filter = filter
return m.results, m.total, nil
}
// ========== Test Setup ==========
func setupCompanyServiceTest(t *testing.T) (*gorm.DB, *repository.CompanyRepo, *repository.ContactRepo, *repository.ConversationRepo, *CompanyService) {
t.Helper()
db := setupServiceTestDB(t)
companyRepo := repository.NewCompanyRepo(db)
contactRepo := repository.NewContactRepo(db)
conversationRepo := repository.NewConversationRepo(db)
svc := NewCompanyService(companyRepo, contactRepo, conversationRepo)
return db, companyRepo, contactRepo, conversationRepo, svc
}
func createTestCompanySvc(t *testing.T, db *gorm.DB, accountID uint, name, domain string) *model.Company {
t.Helper()
company := &model.Company{
AccountID: accountID,
Name: name,
Domain: domain,
}
require.NoError(t, db.Create(company).Error)
return company
}
// ========== Create ==========
func TestCompanyService_Create(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{
Name: "Acme Corp",
Description: "A fictional company",
Domain: "acme.example.com",
WebsiteURL: "https://acme.example.com",
}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
assert.NotZero(t, company.ID)
assert.Equal(t, "Acme Corp", company.Name)
assert.Equal(t, account.ID, company.AccountID)
assert.Equal(t, "A fictional company", company.Description)
}
func TestCompanyService_Create_ValidationError(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{
Name: "", // required field, min=1
}
_, err := svc.Create(context.Background(), account.ID, req)
assert.Error(t, err)
}
// ========== Get ==========
func TestCompanyService_Get(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "TestCorp"}
created, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
company, err := svc.Get(context.Background(), created.ID, account.ID)
require.NoError(t, err)
assert.Equal(t, "TestCorp", company.Name)
}
func TestCompanyService_Get_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "TestCorp"}
created, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
_, err = svc.Get(context.Background(), created.ID, 9999)
assert.Error(t, err)
}
func TestCompanyService_Get_NotFound(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
_, err := svc.Get(context.Background(), 9999, account.ID)
assert.Error(t, err)
}
// ========== List ==========
func TestCompanyService_List(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
for i := 0; i < 3; i++ {
req := &CreateCompanyRequest{Name: fmt.Sprintf("Company%d", i)}
_, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
}
companies, total, err := svc.List(context.Background(), account.ID, 0, 10, "")
require.NoError(t, err)
assert.Equal(t, int64(3), total)
assert.Len(t, companies, 3)
}
func TestCompanyService_List_Empty(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
companies, total, err := svc.List(context.Background(), account.ID, 0, 10, "")
require.NoError(t, err)
assert.Equal(t, int64(0), total)
assert.Len(t, companies, 0)
}
func TestCompanyService_List_Pagination(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
for i := 0; i < 5; i++ {
req := &CreateCompanyRequest{Name: fmt.Sprintf("Company%d", i)}
_, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
}
companies, total, err := svc.List(context.Background(), account.ID, 0, 2, "")
require.NoError(t, err)
assert.Equal(t, int64(5), total)
assert.Len(t, companies, 2)
}
// ========== Update ==========
func TestCompanyService_Update(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp", Domain: "acme.com"}
created, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
updateReq := &UpdateCompanyRequest{
Name: "Acme Corp Updated",
Domain: "acme-updated.com",
}
updated, err := svc.Update(context.Background(), created.ID, account.ID, updateReq)
require.NoError(t, err)
assert.Equal(t, "Acme Corp Updated", updated.Name)
assert.Equal(t, "acme-updated.com", updated.Domain)
}
func TestCompanyService_Update_CustomAttributes(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
created, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
updateReq := &UpdateCompanyRequest{
CustomAttributes: datatypes.JSON(`{"industry":"tech","revenue":"1M"}`),
}
updated, err := svc.Update(context.Background(), created.ID, account.ID, updateReq)
require.NoError(t, err)
assert.NotNil(t, updated.CustomAttributes)
}
func TestCompanyService_Update_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
created, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
updateReq := &UpdateCompanyRequest{Name: "Updated"}
_, err = svc.Update(context.Background(), created.ID, 9999, updateReq)
assert.Error(t, err)
}
// ========== Delete ==========
func TestCompanyService_Delete(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
created, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
err = svc.Delete(context.Background(), created.ID, account.ID)
require.NoError(t, err)
_, err = svc.Get(context.Background(), created.ID, account.ID)
assert.Error(t, err)
}
func TestCompanyService_Delete_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
created, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
err = svc.Delete(context.Background(), created.ID, 9999)
assert.Error(t, err)
}
// ========== Search ==========
func TestCompanyService_Search(t *testing.T) {
skipIfSQLite(t)
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req1 := &CreateCompanyRequest{Name: "Acme Technologies", Domain: "acme.com"}
_, err := svc.Create(context.Background(), account.ID, req1)
require.NoError(t, err)
req2 := &CreateCompanyRequest{Name: "Beta Labs", Domain: "beta.com"}
_, err = svc.Create(context.Background(), account.ID, req2)
require.NoError(t, err)
companies, total, err := svc.Search(context.Background(), account.ID, "Acme", 0, 10, "", search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(1), total)
assert.Len(t, companies, 1)
assert.Equal(t, "Acme Technologies", companies[0].Name)
}
func TestCompanyService_Search_EmptyQuery(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
_, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
companies, total, err := svc.Search(context.Background(), account.ID, "", 0, 10, "", search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(1), total)
assert.Len(t, companies, 1)
}
func TestCompanyService_Search_UsesSearchReader(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
company := createTestCompanySvc(t, db, account.ID, "Meili Corp", "meili.example.com")
createTestCompanySvc(t, db, account.ID, "DB Corp", "db.example.com")
reader := &mockCompanySearchReader{
results: []search.SearchResult{{Type: search.ResultTypeCompany, ID: company.ID, AccountID: account.ID}},
total: 1,
}
svc.SetSearchReader(reader)
companies, total, err := svc.Search(context.Background(), account.ID, "meili", 0, 10, "", search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(1), total)
require.Len(t, companies, 1)
assert.Equal(t, company.ID, companies[0].ID)
assert.Equal(t, "meili", reader.query)
require.NotNil(t, reader.filter)
assert.Equal(t, []search.SearchResultType{search.ResultTypeCompany}, reader.filter.Types)
assert.Equal(t, 1, reader.filter.Page)
assert.Equal(t, 10, reader.filter.PerPage)
}
// ========== ListContacts ==========
func TestCompanyService_ListContacts(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
// Create company
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
// Create contacts
contact1 := createTestContact(t, db, account.ID)
contact2 := createTestContact(t, db, account.ID)
require.NoError(t, db.Model(&model.Contact{}).Where("id IN ?", []uint{contact1.ID, contact2.ID}).Update("company_id", company.ID).Error)
contacts, total, err := svc.ListContacts(context.Background(), company.ID, account.ID, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
assert.Len(t, contacts, 2)
}
func TestCompanyService_ListContacts_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
_, _, err = svc.ListContacts(context.Background(), company.ID, 9999, 0, 10)
assert.Error(t, err)
}
// ========== ListConversations ==========
func TestCompanyService_ListConversations(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
// Create company
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
// Create a contact and associate it with the company
contact := createTestContact(t, db, account.ID)
require.NoError(t, db.Model(&model.Contact{}).Where("id = ?", contact.ID).Update("company_id", company.ID).Error)
// Create an inbox and conversation for the contact
inbox := createTestInbox(t, db, account.ID, "web_widget")
conv := createTestConversation(t, db, account.ID, inbox.ID, contact.ID)
// ListConversations finds conversations for contacts associated with the company
conversations, total, err := svc.ListConversations(context.Background(), company.ID, account.ID, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(1), total)
assert.Len(t, conversations, 1)
assert.Equal(t, conv.ID, conversations[0].ID)
}
func TestCompanyService_ListConversations_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
_, _, err = svc.ListConversations(context.Background(), company.ID, 9999, 0, 10)
assert.Error(t, err)
}
// ========== ListNotes ==========
func TestCompanyService_ListNotes(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
// Create company
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
// Create notes directly
note1 := &model.CompanyNote{CompanyID: company.ID, UserID: user.ID, Content: "Note 1"}
require.NoError(t, db.Create(note1).Error)
note2 := &model.CompanyNote{CompanyID: company.ID, UserID: user.ID, Content: "Note 2"}
require.NoError(t, db.Create(note2).Error)
notes, total, err := svc.ListNotes(context.Background(), company.ID, account.ID, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
assert.Len(t, notes, 2)
}
func TestCompanyService_ListNotes_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
_, _, err = svc.ListNotes(context.Background(), company.ID, 9999, 0, 10)
assert.Error(t, err)
}
// ========== CreateNote ==========
func TestCompanyService_CreateNote(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
// Create company
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
noteReq := &CreateCompanyNoteRequest{
Content: "This is a test note",
}
note, err := svc.CreateNote(context.Background(), company.ID, account.ID, user.ID, noteReq)
require.NoError(t, err)
assert.NotZero(t, note.ID)
assert.Equal(t, company.ID, note.CompanyID)
assert.Equal(t, user.ID, note.UserID)
assert.Equal(t, "This is a test note", note.Content)
}
func TestCompanyService_CreateNote_ValidationError(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
noteReq := &CreateCompanyNoteRequest{
Content: "", // required field, min=1
}
_, err = svc.CreateNote(context.Background(), company.ID, account.ID, user.ID, noteReq)
assert.Error(t, err)
}
func TestCompanyService_CreateNote_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
noteReq := &CreateCompanyNoteRequest{Content: "Note"}
_, err = svc.CreateNote(context.Background(), company.ID, 9999, user.ID, noteReq)
assert.Error(t, err)
}
// ========== DeleteNote ==========
func TestCompanyService_DeleteNote(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
noteReq := &CreateCompanyNoteRequest{Content: "Note to delete"}
note, err := svc.CreateNote(context.Background(), company.ID, account.ID, user.ID, noteReq)
require.NoError(t, err)
err = svc.DeleteNote(context.Background(), note.ID, company.ID, account.ID)
assert.NoError(t, err)
// Verify note is gone
var count int64
db.Model(&model.CompanyNote{}).Where("id = ?", note.ID).Count(&count)
assert.Equal(t, int64(0), count)
}
func TestCompanyService_DeleteNote_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
noteReq := &CreateCompanyNoteRequest{Content: "Note"}
note, err := svc.CreateNote(context.Background(), company.ID, account.ID, user.ID, noteReq)
require.NoError(t, err)
// Deleting with wrong accountID should fail (company not found for that account)
err = svc.DeleteNote(context.Background(), note.ID, company.ID, 9999)
assert.Error(t, err)
}
// ========== AddContact ==========
func TestCompanyService_AddContact(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
contact := &model.Contact{AccountID: account.ID, Name: "Test Contact", Email: "contact@example.com"}
require.NoError(t, db.Create(contact).Error)
err = svc.AddContact(context.Background(), company.ID, account.ID, contact.ID)
assert.NoError(t, err)
var updated model.Contact
require.NoError(t, db.First(&updated, contact.ID).Error)
require.NotNil(t, updated.CompanyID)
assert.Equal(t, company.ID, *updated.CompanyID)
}
func TestCompanyService_AddContact_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
contact := &model.Contact{AccountID: account.ID, Name: "Contact", Email: "c@example.com"}
require.NoError(t, db.Create(contact).Error)
// Wrong accountID should fail (company not found for that account)
err = svc.AddContact(context.Background(), company.ID, 9999, contact.ID)
assert.Error(t, err)
}
func TestCompanyService_AddContact_ContactWrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account1 := createTestAccountWithName(t, db, "Account1")
account2 := createTestAccountWithName(t, db, "Account2")
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account1.ID, req)
require.NoError(t, err)
// Contact belongs to a different account
contact := &model.Contact{AccountID: account2.ID, Name: "Wrong Contact", Email: "wrong@example.com"}
require.NoError(t, db.Create(contact).Error)
err = svc.AddContact(context.Background(), company.ID, account1.ID, contact.ID)
assert.Error(t, err)
}
// ========== RemoveContact ==========
func TestCompanyService_RemoveContact(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
contact := &model.Contact{AccountID: account.ID, Name: "Test Contact", Email: "contact@example.com", CompanyID: &company.ID}
require.NoError(t, db.Create(contact).Error)
err = svc.RemoveContact(context.Background(), company.ID, account.ID, contact.ID)
assert.NoError(t, err)
var updated model.Contact
require.NoError(t, db.First(&updated, contact.ID).Error)
assert.Nil(t, updated.CompanyID)
}
func TestCompanyService_RemoveContact_WrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account := createTestAccount(t, db)
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account.ID, req)
require.NoError(t, err)
contact := &model.Contact{AccountID: account.ID, Name: "Contact", Email: "c@example.com"}
require.NoError(t, db.Create(contact).Error)
// Wrong accountID should fail
err = svc.RemoveContact(context.Background(), company.ID, 9999, contact.ID)
assert.Error(t, err)
}
func TestCompanyService_RemoveContact_ContactWrongAccount(t *testing.T) {
db, _, _, _, svc := setupCompanyServiceTest(t)
account1 := createTestAccountWithName(t, db, "Account1")
account2 := createTestAccountWithName(t, db, "Account2")
req := &CreateCompanyRequest{Name: "Acme Corp"}
company, err := svc.Create(context.Background(), account1.ID, req)
require.NoError(t, err)
// Contact belongs to a different account
contact := &model.Contact{AccountID: account2.ID, Name: "Wrong Contact", Email: "wrong@example.com"}
require.NoError(t, db.Create(contact).Error)
err = svc.RemoveContact(context.Background(), company.ID, account1.ID, contact.ID)
assert.Error(t, err)
}