350 lines
11 KiB
Go
350 lines
11 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
)
|
|
|
|
// ========== Test Setup ==========
|
|
|
|
func setupCustomAttrDefServiceTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to open SQLite test database: %v", err)
|
|
}
|
|
if err := db.AutoMigrate(
|
|
&model.Account{},
|
|
&model.User{},
|
|
&model.CustomAttributeDefinition{},
|
|
); err != nil {
|
|
t.Fatalf("failed to auto-migrate models: %v", err)
|
|
}
|
|
t.Cleanup(func() {
|
|
sqlDB, _ := db.DB()
|
|
sqlDB.Close()
|
|
})
|
|
return db
|
|
}
|
|
|
|
func setupCustomAttrDefService(t *testing.T) (*CustomAttributeDefinitionService, uint) {
|
|
t.Helper()
|
|
db := setupCustomAttrDefServiceTestDB(t)
|
|
repo := repository.NewCustomAttributeDefinitionRepo(db)
|
|
svc := NewCustomAttributeDefinitionService(repo)
|
|
account := createTestAccount(t, db)
|
|
return svc, account.ID
|
|
}
|
|
|
|
// ========== Create ==========
|
|
|
|
func TestCustomAttributeDefinitionService_Create(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "custom_priority_score",
|
|
AttributeDisplayName: "Custom Priority Score",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
AttributeDescription: "Conversation priority level",
|
|
}
|
|
|
|
def, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err)
|
|
assert.NotZero(t, def.ID)
|
|
assert.Equal(t, accountID, def.AccountID)
|
|
assert.Equal(t, "custom_priority_score", def.AttributeName)
|
|
assert.Equal(t, "Custom Priority Score", def.AttributeDisplayName)
|
|
assert.Equal(t, "text", def.AttributeType)
|
|
assert.Equal(t, "conversation", def.AttributeModel)
|
|
assert.Equal(t, "Conversation priority level", def.Description)
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Create_InvalidType(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "bad_type",
|
|
AttributeDisplayName: "Bad Type",
|
|
AttributeDisplayType: "invalid_type",
|
|
AttributeModel: "conversation",
|
|
}
|
|
|
|
_, err := svc.Create(context.Background(), accountID, req)
|
|
assert.Error(t, err, "invalid attribute_type should fail validation")
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Create_InvalidModel(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "bad_model",
|
|
AttributeDisplayName: "Bad Model",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "invalid_model",
|
|
}
|
|
|
|
_, err := svc.Create(context.Background(), accountID, req)
|
|
assert.Error(t, err, "invalid attribute_model should fail validation")
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Create_EmptyName(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "",
|
|
AttributeDisplayName: "Empty Name",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
|
|
_, err := svc.Create(context.Background(), accountID, req)
|
|
assert.Error(t, err, "empty attribute_name should fail validation")
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Create_AllValidTypes(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
validTypes := []string{"text", "number", "date", "checkbox", "list", "link"}
|
|
for _, attrType := range validTypes {
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "attr_" + attrType,
|
|
AttributeDisplayName: "Attr " + attrType,
|
|
AttributeDisplayType: attrType,
|
|
AttributeModel: "conversation",
|
|
}
|
|
def, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err, "attribute_type=%s should be valid", attrType)
|
|
assert.Equal(t, attrType, def.AttributeType)
|
|
}
|
|
}
|
|
|
|
// ========== Get ==========
|
|
|
|
func TestCustomAttributeDefinitionService_Get(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "status",
|
|
AttributeDisplayName: "Status",
|
|
AttributeDisplayType: "list",
|
|
AttributeModel: "contact",
|
|
}
|
|
def, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err)
|
|
|
|
found, err := svc.Get(context.Background(), accountID, def.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, def.ID, found.ID)
|
|
assert.Equal(t, "status", found.AttributeName)
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Get_WrongAccount(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "private_attr",
|
|
AttributeDisplayName: "Private",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
def, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err)
|
|
|
|
// Trying to get from a different account should fail
|
|
_, err = svc.Get(context.Background(), 9999, def.ID)
|
|
assert.Error(t, err, "should not find definition belonging to different account")
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Get_NotFound(t *testing.T) {
|
|
svc, _ := setupCustomAttrDefService(t)
|
|
|
|
_, err := svc.Get(context.Background(), 1, 9999)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
// ========== List ==========
|
|
|
|
func TestCustomAttributeDefinitionService_List_All(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
for _, name := range []string{"attr_a", "attr_b"} {
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: name,
|
|
AttributeDisplayName: name,
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
_, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Create a contact attribute
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "contact_level",
|
|
AttributeDisplayName: "Contact Level",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "contact",
|
|
}
|
|
_, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err)
|
|
|
|
defs, total, err := svc.List(context.Background(), accountID, "", 0, 10)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(3), total)
|
|
assert.Len(t, defs, 3)
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_List_FilterByModel(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
// Create conversation attributes
|
|
for _, name := range []string{"conv_a", "conv_b"} {
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: name,
|
|
AttributeDisplayName: name,
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
_, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Create contact attribute
|
|
req := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "contact_c",
|
|
AttributeDisplayName: "Contact C",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "contact",
|
|
}
|
|
_, err := svc.Create(context.Background(), accountID, req)
|
|
require.NoError(t, err)
|
|
|
|
convDefs, convTotal, err := svc.List(context.Background(), accountID, "conversation", 0, 10)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(2), convTotal)
|
|
assert.Len(t, convDefs, 2)
|
|
|
|
contactDefs, contactTotal, err := svc.List(context.Background(), accountID, "contact", 0, 10)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1), contactTotal)
|
|
assert.Len(t, contactDefs, 1)
|
|
}
|
|
|
|
// ========== Update ==========
|
|
|
|
func TestCustomAttributeDefinitionService_Update(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
createReq := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "custom_priority_score",
|
|
AttributeDisplayName: "Custom Priority Score",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
def, err := svc.Create(context.Background(), accountID, createReq)
|
|
require.NoError(t, err)
|
|
|
|
updateReq := &UpdateCustomAttributeDefinitionRequest{
|
|
AttributeDisplayName: "Priority Level",
|
|
AttributeDisplayType: "number",
|
|
AttributeDescription: "Updated description",
|
|
}
|
|
|
|
updated, err := svc.Update(context.Background(), accountID, def.ID, updateReq)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Priority Level", updated.AttributeDisplayName)
|
|
assert.Equal(t, "number", updated.AttributeType)
|
|
assert.Equal(t, "Updated description", updated.Description)
|
|
// Name and model should stay unchanged
|
|
assert.Equal(t, "custom_priority_score", updated.AttributeName)
|
|
assert.Equal(t, "conversation", updated.AttributeModel)
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Update_WrongAccount(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
createReq := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "private_attr",
|
|
AttributeDisplayName: "Private",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
def, err := svc.Create(context.Background(), accountID, createReq)
|
|
require.NoError(t, err)
|
|
|
|
updateReq := &UpdateCustomAttributeDefinitionRequest{
|
|
AttributeDisplayName: "Hacked",
|
|
}
|
|
|
|
_, err = svc.Update(context.Background(), 9999, def.ID, updateReq)
|
|
assert.Error(t, err, "should not update definition belonging to different account")
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Update_NotFound(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
updateReq := &UpdateCustomAttributeDefinitionRequest{
|
|
AttributeDisplayName: "Nonexistent",
|
|
}
|
|
|
|
_, err := svc.Update(context.Background(), accountID, 9999, updateReq)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
// ========== Delete ==========
|
|
|
|
func TestCustomAttributeDefinitionService_Delete(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
createReq := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "temp_attr",
|
|
AttributeDisplayName: "Temp",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
def, err := svc.Create(context.Background(), accountID, createReq)
|
|
require.NoError(t, err)
|
|
|
|
err = svc.Delete(context.Background(), accountID, def.ID)
|
|
require.NoError(t, err)
|
|
|
|
// Should no longer be accessible via Get
|
|
_, err = svc.Get(context.Background(), accountID, def.ID)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Delete_WrongAccount(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
createReq := &CreateCustomAttributeDefinitionRequest{
|
|
AttributeKey: "private_attr",
|
|
AttributeDisplayName: "Private",
|
|
AttributeDisplayType: "text",
|
|
AttributeModel: "conversation",
|
|
}
|
|
def, err := svc.Create(context.Background(), accountID, createReq)
|
|
require.NoError(t, err)
|
|
|
|
err = svc.Delete(context.Background(), 9999, def.ID)
|
|
assert.Error(t, err, "should not delete definition belonging to different account")
|
|
}
|
|
|
|
func TestCustomAttributeDefinitionService_Delete_NotFound(t *testing.T) {
|
|
svc, accountID := setupCustomAttrDefService(t)
|
|
|
|
err := svc.Delete(context.Background(), accountID, 9999)
|
|
assert.Error(t, err)
|
|
}
|