363 lines
12 KiB
Go
363 lines
12 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"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/search"
|
|
)
|
|
|
|
func createTestContact(t *testing.T, db *gorm.DB, accountID uint, name, email string) *model.Contact {
|
|
t.Helper()
|
|
contact := &model.Contact{
|
|
AccountID: accountID,
|
|
Name: name,
|
|
Email: email,
|
|
PhoneNumber: "",
|
|
}
|
|
require.NoError(t, db.Create(contact).Error)
|
|
return contact
|
|
}
|
|
|
|
func TestContactRepo_FindByID(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactFindOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contact := createTestContact(t, db, account.ID, "John Doe", "john@example.com")
|
|
|
|
found, err := repo.FindByID(context.Background(), contact.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, contact.ID, found.ID)
|
|
assert.Equal(t, "John Doe", found.Name)
|
|
assert.Equal(t, "john@example.com", found.Email)
|
|
}
|
|
|
|
func TestContactRepo_FindByID_NotFound(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
found, err := repo.FindByID(context.Background(), 9999)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
func TestContactRepo_FindByAccountAndID(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactScopedOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contact := createTestContact(t, db, account.ID, "Scoped", "scoped@example.com")
|
|
|
|
found, err := repo.FindByAccountAndID(context.Background(), account.ID, contact.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, contact.ID, found.ID)
|
|
}
|
|
|
|
func TestContactRepo_FindByAccountAndID_WrongAccount(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactScopedWrongOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contact := createTestContact(t, db, account.ID, "WrongScoped", "wrong@example.com")
|
|
|
|
found, err := repo.FindByAccountAndID(context.Background(), 9999, contact.ID)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
func TestContactRepo_FindByEmail(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactEmailOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contact := createTestContact(t, db, account.ID, "EmailUser", "unique@example.com")
|
|
|
|
found, err := repo.FindByEmail(context.Background(), account.ID, "unique@example.com")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, contact.ID, found.ID)
|
|
}
|
|
|
|
func TestContactRepo_FindByEmail_NotFound(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactEmailNotFoundOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
found, err := repo.FindByEmail(context.Background(), account.ID, "nonexistent@example.com")
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
func TestContactRepo_FindByAccount(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactListOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
for i := 0; i < 5; i++ {
|
|
createTestContact(t, db, account.ID, "Contact"+string(rune('A'+i)), "c"+string(rune('A'+i))+"@example.com")
|
|
}
|
|
|
|
contacts, total, err := repo.FindByAccount(context.Background(), account.ID, 0, 10, "")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(5), total)
|
|
assert.Len(t, contacts, 5)
|
|
}
|
|
|
|
func TestContactRepo_FindByAccount_Empty(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
contacts, total, err := repo.FindByAccount(context.Background(), 1, 0, 10, "")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(0), total)
|
|
assert.Len(t, contacts, 0)
|
|
}
|
|
|
|
func TestContactRepo_Create(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
contact := &model.Contact{
|
|
AccountID: 1,
|
|
Name: "New Contact",
|
|
Email: "new@example.com",
|
|
PhoneNumber: "1234567890",
|
|
}
|
|
|
|
err := repo.Create(context.Background(), contact)
|
|
assert.NoError(t, err)
|
|
assert.NotZero(t, contact.ID)
|
|
}
|
|
|
|
func TestContactRepo_Update(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactUpdateOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contact := createTestContact(t, db, account.ID, "Original", "original@example.com")
|
|
contact.Name = "Updated"
|
|
|
|
err := repo.Update(context.Background(), contact)
|
|
assert.NoError(t, err)
|
|
|
|
found, err := repo.FindByID(context.Background(), contact.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "Updated", found.Name)
|
|
}
|
|
|
|
func TestContactRepo_Delete(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactDeleteOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contact := createTestContact(t, db, account.ID, "DeleteMe", "delete@example.com")
|
|
|
|
err := repo.Delete(context.Background(), contact.ID)
|
|
assert.NoError(t, err)
|
|
|
|
found, err := repo.FindByID(context.Background(), contact.ID)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
func TestContactRepo_CountByAccount(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactCountOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
for i := 0; i < 3; i++ {
|
|
createTestContact(t, db, account.ID, "Count"+string(rune('A'+i)), "count"+string(rune('A'+i))+"@example.com")
|
|
}
|
|
|
|
total, err := repo.CountByAccount(context.Background(), account.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(3), total)
|
|
}
|
|
|
|
// Search uses ILIKE which SQLite does not support; skip when running SQLite
|
|
func TestContactRepo_Search(t *testing.T) {
|
|
skipIfSQLite(t)
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactSearchOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
createTestContact(t, db, account.ID, "Alice Smith", "alice@example.com")
|
|
createTestContact(t, db, account.ID, "Bob Jones", "bob@example.com")
|
|
createTestContact(t, db, account.ID, "Alice Jones", "alice.jones@example.com")
|
|
|
|
// Search by name
|
|
contacts, total, err := repo.Search(context.Background(), account.ID, "alice", 0, 10, "", search.SearchModeILike)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(2), total)
|
|
assert.Len(t, contacts, 2)
|
|
|
|
// Search by email
|
|
contacts, total, err = repo.Search(context.Background(), account.ID, "bob", 0, 10, "", search.SearchModeILike)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(1), total)
|
|
assert.Len(t, contacts, 1)
|
|
assert.Equal(t, "Bob Jones", contacts[0].Name)
|
|
}
|
|
|
|
func TestContactRepo_FindActive(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactActiveOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
// Create an active contact (with last_activity_at set)
|
|
activeContact := createTestContact(t, db, account.ID, "Active Alice", "active@example.com")
|
|
now := int64(1000000)
|
|
require.NoError(t, db.Model(activeContact).Update("last_activity_at", &now).Error)
|
|
|
|
// Create an inactive contact (no last_activity_at)
|
|
createTestContact(t, db, account.ID, "Inactive Bob", "inactive@example.com")
|
|
|
|
contacts, total, err := repo.FindActive(context.Background(), account.ID, 0, 10, "")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(1), total)
|
|
assert.Len(t, contacts, 1)
|
|
assert.Equal(t, "Active Alice", contacts[0].Name)
|
|
}
|
|
|
|
func TestContactRepo_FindActive_Empty(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactActiveEmptyOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
// Create only inactive contacts (no last_activity_at)
|
|
createTestContact(t, db, account.ID, "NoActivity", "noactivity@example.com")
|
|
|
|
contacts, total, err := repo.FindActive(context.Background(), account.ID, 0, 10, "")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(0), total)
|
|
assert.Len(t, contacts, 0)
|
|
}
|
|
|
|
func TestContactRepo_FindActive_Pagination(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactActivePageOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
// Create 5 active contacts
|
|
for i := 0; i < 5; i++ {
|
|
c := createTestContact(t, db, account.ID, "Active"+string(rune('A'+i)), "active"+string(rune('A'+i))+"@example.com")
|
|
ts := int64(1000000 + i)
|
|
require.NoError(t, db.Model(c).Update("last_activity_at", &ts).Error)
|
|
}
|
|
|
|
// Fetch first page (offset=0, limit=2)
|
|
contacts, total, err := repo.FindActive(context.Background(), account.ID, 0, 2, "")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(5), total)
|
|
assert.Len(t, contacts, 2)
|
|
|
|
// Fetch second page (offset=2, limit=2)
|
|
contacts2, total2, err2 := repo.FindActive(context.Background(), account.ID, 2, 2, "")
|
|
assert.NoError(t, err2)
|
|
assert.Equal(t, int64(5), total2)
|
|
assert.Len(t, contacts2, 2)
|
|
// Ensure different contacts returned
|
|
assert.NotEqual(t, contacts[0].ID, contacts2[0].ID)
|
|
}
|
|
|
|
func TestContactRepo_FindAllForExport(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactExportOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
c1 := createTestContact(t, db, account.ID, "Export Alice", "export1@example.com")
|
|
c2 := createTestContact(t, db, account.ID, "Export Bob", "export2@example.com")
|
|
c3 := createTestContact(t, db, account.ID, "Export Carol", "export3@example.com")
|
|
|
|
contacts, err := repo.FindAllForExport(context.Background(), account.ID)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, contacts, 3)
|
|
// Verify ordered by id ASC
|
|
assert.Equal(t, c1.ID, contacts[0].ID)
|
|
assert.Equal(t, c2.ID, contacts[1].ID)
|
|
assert.Equal(t, c3.ID, contacts[2].ID)
|
|
}
|
|
|
|
func TestContactRepo_FindAllForExport_Empty(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactExportEmptyOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contacts, err := repo.FindAllForExport(context.Background(), account.ID)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, contacts, 0)
|
|
}
|
|
|
|
func TestContactRepo_DeleteCustomAttributes(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
account := &model.Account{Name: "ContactDeleteAttrOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
contact := createTestContact(t, db, account.ID, "Attr User", "attr@example.com")
|
|
// Set custom attributes
|
|
require.NoError(t, db.Model(contact).Update("custom_attributes", datatypes.JSON(`{"key":"value"}`)).Error)
|
|
|
|
// Verify custom attributes are set
|
|
found, err := repo.FindByID(context.Background(), contact.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, datatypes.JSON(`{"key":"value"}`), found.CustomAttributes)
|
|
|
|
// Delete custom attributes
|
|
err = repo.DeleteCustomAttributes(context.Background(), contact.ID)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify custom attributes are now empty
|
|
found2, err := repo.FindByID(context.Background(), contact.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, datatypes.JSON(`{}`), found2.CustomAttributes)
|
|
}
|
|
|
|
func TestContactRepo_DeleteCustomAttributes_NotFound(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
repo := NewContactRepo(db)
|
|
|
|
// DeleteCustomAttributes on a non-existent id: GORM Update with Where returns nil
|
|
// (no ErrRecordNotFound) but RowsAffected is 0
|
|
err := repo.DeleteCustomAttributes(context.Background(), 9999)
|
|
// GORM's Update with Where clause on nonexistent record returns nil error
|
|
// (it just affects 0 rows), so we verify it doesn't crash and returns no error
|
|
assert.NoError(t, err)
|
|
} |