package repository import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/gorm" "github.com/gochat/gochat/internal/model" ) // --- Helpers for CustomAttributeDefinition repo tests --- func setupCustomAttrDefTestDB(t *testing.T) *gorm.DB { t.Helper() return setupTestDB(t, &model.CustomAttributeDefinition{}) } func createCustomAttrDefTestAccount(t *testing.T, db *gorm.DB) *model.Account { t.Helper() account := &model.Account{Name: "Custom Attr Def Test Account"} err := db.Create(account).Error require.NoError(t, err, "failed to create test account") return account } // =========================================================================== // Create tests // =========================================================================== func TestCustomAttributeDefinitionRepo_Create(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: "priority", AttributeDisplayName: "Priority", AttributeType: "text", AttributeModel: "conversation", Description: "Conversation priority level", } err := repo.Create(ctx, def) require.NoError(t, err) assert.NotZero(t, def.ID) assert.Equal(t, account.ID, def.AccountID) assert.Equal(t, "priority", def.AttributeName) assert.Equal(t, "text", def.AttributeType) assert.Equal(t, "conversation", def.AttributeModel) } func TestCustomAttributeDefinitionRepo_Create_DuplicateAttributeName(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) def1 := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: "priority", AttributeDisplayName: "Priority", AttributeType: "text", AttributeModel: "conversation", } require.NoError(t, repo.Create(ctx, def1)) // Same attribute_name + same account + same model should fail (unique index) def2 := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: "priority", AttributeDisplayName: "Priority Level", AttributeType: "number", AttributeModel: "conversation", } err := repo.Create(ctx, def2) assert.Error(t, err, "duplicate attribute_name within same account+model should fail") } // =========================================================================== // GetByID tests // =========================================================================== func TestCustomAttributeDefinitionRepo_GetByID(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: "status", AttributeDisplayName: "Status", AttributeType: "list", AttributeModel: "contact", } require.NoError(t, repo.Create(ctx, def)) found, err := repo.GetByID(ctx, def.ID) require.NoError(t, err) assert.Equal(t, def.ID, found.ID) assert.Equal(t, "status", found.AttributeName) assert.Equal(t, "list", found.AttributeType) } func TestCustomAttributeDefinitionRepo_GetByID_NotFound(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) _, err := repo.GetByID(ctx, 9999) assert.ErrorIs(t, err, gorm.ErrRecordNotFound) } // =========================================================================== // FindByAccount tests // =========================================================================== func TestCustomAttributeDefinitionRepo_FindByAccount(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) // Create multiple definitions for the same account for i, name := range []string{"attr_a", "attr_b", "attr_c"} { def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: name, AttributeDisplayName: "Attr " + name, AttributeType: "text", AttributeModel: "conversation", Description: "Test desc " + string(rune('A'+i)), } require.NoError(t, repo.Create(ctx, def)) } defs, total, err := repo.FindByAccount(ctx, account.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(3), total) assert.Len(t, defs, 3) } func TestCustomAttributeDefinitionRepo_FindByAccount_Pagination(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) for i := 0; i < 5; i++ { def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: "paged_attr_" + string(rune('A'+i)), AttributeDisplayName: "Paged Attr", AttributeType: "text", AttributeModel: "conversation", } require.NoError(t, repo.Create(ctx, def)) } defs, total, err := repo.FindByAccount(ctx, account.ID, 0, 2) require.NoError(t, err) assert.Equal(t, int64(5), total) assert.Len(t, defs, 2) defs2, total2, err := repo.FindByAccount(ctx, account.ID, 2, 2) require.NoError(t, err) assert.Equal(t, int64(5), total2) assert.Len(t, defs2, 2) } func TestCustomAttributeDefinitionRepo_FindByAccount_EmptyAccount(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) defs, total, err := repo.FindByAccount(ctx, 9999, 0, 10) require.NoError(t, err) assert.Equal(t, int64(0), total) assert.Len(t, defs, 0) } // =========================================================================== // FindByAccountAndModel tests // =========================================================================== func TestCustomAttributeDefinitionRepo_FindByAccountAndModel(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) // Create conversation attributes for _, name := range []string{"conv_priority", "conv_status"} { def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: name, AttributeDisplayName: name, AttributeType: "text", AttributeModel: "conversation", } require.NoError(t, repo.Create(ctx, def)) } // Create contact attributes for _, name := range []string{"contact_level", "contact_source"} { def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: name, AttributeDisplayName: name, AttributeType: "text", AttributeModel: "contact", } require.NoError(t, repo.Create(ctx, def)) } convDefs, convTotal, err := repo.FindByAccountAndModel(ctx, account.ID, "conversation", 0, 10) require.NoError(t, err) assert.Equal(t, int64(2), convTotal) assert.Len(t, convDefs, 2) contactDefs, contactTotal, err := repo.FindByAccountAndModel(ctx, account.ID, "contact", 0, 10) require.NoError(t, err) assert.Equal(t, int64(2), contactTotal) assert.Len(t, contactDefs, 2) } // =========================================================================== // Update tests // =========================================================================== func TestCustomAttributeDefinitionRepo_Update(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: "priority", AttributeDisplayName: "Priority", AttributeType: "text", AttributeModel: "conversation", } require.NoError(t, repo.Create(ctx, def)) def.AttributeDisplayName = "Priority Level" def.Description = "Updated description" err := repo.Update(ctx, def) require.NoError(t, err) found, err := repo.GetByID(ctx, def.ID) require.NoError(t, err) assert.Equal(t, "Priority Level", found.AttributeDisplayName) assert.Equal(t, "Updated description", found.Description) } // =========================================================================== // Delete tests (soft delete) // =========================================================================== func TestCustomAttributeDefinitionRepo_Delete(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) account := createCustomAttrDefTestAccount(t, db) def := &model.CustomAttributeDefinition{ AccountID: account.ID, AttributeName: "temp_attr", AttributeDisplayName: "Temp", AttributeType: "text", AttributeModel: "conversation", } require.NoError(t, repo.Create(ctx, def)) err := repo.Delete(ctx, def.ID) require.NoError(t, err) // Should not be findable via GetByID (soft delete filters it) _, err = repo.GetByID(ctx, def.ID) assert.ErrorIs(t, err, gorm.ErrRecordNotFound) } func TestCustomAttributeDefinitionRepo_Delete_NotFound(t *testing.T) { db := setupCustomAttrDefTestDB(t) ctx := context.Background() repo := NewCustomAttributeDefinitionRepo(db) // Deleting a non-existent record should still succeed (GORM soft delete on zero rows) err := repo.Delete(ctx, 9999) // GORM Delete with a specific ID that doesn't exist may or may not error depending on version // In practice, GORM won't return an error even if the record doesn't exist for soft delete assert.NoError(t, err) }