- Add new test files for auth, service, and handler modules - Improve test organization and coverage - Refactor code for better maintainability - Add captcha, settings, stats, and theme handler tests - Add auth module tests (CAS, OAuth, password, SSO, state) - Add service layer tests for auth, export, permissions, roles - All Go tests pass (exit code 0) - All frontend tests pass (325 tests in 59 files)
497 lines
13 KiB
Go
497 lines
13 KiB
Go
package service_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/user-management-system/internal/domain"
|
|
"github.com/user-management-system/internal/repository"
|
|
"github.com/user-management-system/internal/service"
|
|
gormsqlite "gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
// =============================================================================
|
|
// Custom Field Service Tests
|
|
// =============================================================================
|
|
|
|
func setupCustomFieldTestEnv(t *testing.T) (*service.CustomFieldService, *gorm.DB) {
|
|
t.Helper()
|
|
|
|
db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
|
|
DriverName: "sqlite",
|
|
DSN: "file:customfield_test?mode=memory&cache=shared",
|
|
}), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to connect database: %v", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(&domain.CustomField{}, &domain.UserCustomFieldValue{}); err != nil {
|
|
t.Fatalf("failed to migrate: %v", err)
|
|
}
|
|
|
|
fieldRepo := repository.NewCustomFieldRepository(db)
|
|
valueRepo := repository.NewUserCustomFieldValueRepository(db)
|
|
svc := service.NewCustomFieldService(fieldRepo, valueRepo)
|
|
|
|
return svc, db
|
|
}
|
|
|
|
func TestCustomFieldService_CreateField(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
t.Run("Create field success", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "测试字段",
|
|
FieldKey: "test_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
Required: false,
|
|
}
|
|
field, err := svc.CreateField(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("CreateField failed: %v", err)
|
|
}
|
|
if field.FieldKey != "test_field" {
|
|
t.Errorf("Expected field key 'test_field', got %s", field.FieldKey)
|
|
}
|
|
})
|
|
|
|
t.Run("Create field with duplicate key", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "重复字段",
|
|
FieldKey: "test_field", // duplicate
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
_, err := svc.CreateField(ctx, req)
|
|
if err == nil {
|
|
t.Error("Expected error for duplicate field key")
|
|
}
|
|
})
|
|
|
|
t.Run("Create number field", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "数字字段",
|
|
FieldKey: "number_field",
|
|
Type: int(domain.CustomFieldTypeNumber),
|
|
MinVal: 0,
|
|
MaxVal: 100,
|
|
}
|
|
field, err := svc.CreateField(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("CreateField failed: %v", err)
|
|
}
|
|
if field.Type != domain.CustomFieldTypeNumber {
|
|
t.Errorf("Expected type number, got %d", field.Type)
|
|
}
|
|
})
|
|
|
|
t.Run("Create boolean field", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "布尔字段",
|
|
FieldKey: "bool_field",
|
|
Type: int(domain.CustomFieldTypeBoolean),
|
|
}
|
|
_, err := svc.CreateField(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("CreateField failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Create date field", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "日期字段",
|
|
FieldKey: "date_field",
|
|
Type: int(domain.CustomFieldTypeDate),
|
|
}
|
|
_, err := svc.CreateField(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("CreateField failed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_UpdateField(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create test field
|
|
req := &service.CreateFieldRequest{
|
|
Name: "更新测试",
|
|
FieldKey: "update_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
field, _ := svc.CreateField(ctx, req)
|
|
|
|
t.Run("Update field name", func(t *testing.T) {
|
|
updateReq := &service.UpdateFieldRequest{
|
|
Name: "更新后名称",
|
|
}
|
|
updated, err := svc.UpdateField(ctx, field.ID, updateReq)
|
|
if err != nil {
|
|
t.Fatalf("UpdateField failed: %v", err)
|
|
}
|
|
if updated.Name != "更新后名称" {
|
|
t.Errorf("Expected name '更新后名称', got %s", updated.Name)
|
|
}
|
|
})
|
|
|
|
t.Run("Update field required", func(t *testing.T) {
|
|
required := true
|
|
updateReq := &service.UpdateFieldRequest{
|
|
Required: &required,
|
|
}
|
|
updated, err := svc.UpdateField(ctx, field.ID, updateReq)
|
|
if err != nil {
|
|
t.Fatalf("UpdateField failed: %v", err)
|
|
}
|
|
if !updated.Required {
|
|
t.Error("Expected required to be true")
|
|
}
|
|
})
|
|
|
|
t.Run("Update non-existent field", func(t *testing.T) {
|
|
updateReq := &service.UpdateFieldRequest{
|
|
Name: "不存在",
|
|
}
|
|
_, err := svc.UpdateField(ctx, 9999, updateReq)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent field")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_DeleteField(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
t.Run("Delete field success", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "待删除字段",
|
|
FieldKey: "delete_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
field, _ := svc.CreateField(ctx, req)
|
|
|
|
err := svc.DeleteField(ctx, field.ID)
|
|
if err != nil {
|
|
t.Fatalf("DeleteField failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Delete non-existent field", func(t *testing.T) {
|
|
err := svc.DeleteField(ctx, 9999)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent field")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_GetField(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateFieldRequest{
|
|
Name: "获取测试",
|
|
FieldKey: "get_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
created, _ := svc.CreateField(ctx, req)
|
|
|
|
t.Run("Get field success", func(t *testing.T) {
|
|
field, err := svc.GetField(ctx, created.ID)
|
|
if err != nil {
|
|
t.Fatalf("GetField failed: %v", err)
|
|
}
|
|
if field.FieldKey != "get_field" {
|
|
t.Errorf("Expected field key 'get_field', got %s", field.FieldKey)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_ListFields(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create test fields
|
|
for i := 0; i < 3; i++ {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "列表字段",
|
|
FieldKey: string(rune('a' + i)),
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
}
|
|
|
|
t.Run("List fields", func(t *testing.T) {
|
|
fields, err := svc.ListFields(ctx)
|
|
if err != nil {
|
|
t.Fatalf("ListFields failed: %v", err)
|
|
}
|
|
if len(fields) < 3 {
|
|
t.Errorf("Expected at least 3 fields, got %d", len(fields))
|
|
}
|
|
})
|
|
|
|
t.Run("List all fields", func(t *testing.T) {
|
|
fields, err := svc.ListAllFields(ctx)
|
|
if err != nil {
|
|
t.Fatalf("ListAllFields failed: %v", err)
|
|
}
|
|
if len(fields) < 3 {
|
|
t.Errorf("Expected at least 3 fields, got %d", len(fields))
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_SetUserFieldValue(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create test field
|
|
req := &service.CreateFieldRequest{
|
|
Name: "用户字段",
|
|
FieldKey: "user_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
|
|
t.Run("Set user field value success", func(t *testing.T) {
|
|
err := svc.SetUserFieldValue(ctx, 1, "user_field", "test value")
|
|
if err != nil {
|
|
t.Fatalf("SetUserFieldValue failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Set user field value with non-existent field", func(t *testing.T) {
|
|
err := svc.SetUserFieldValue(ctx, 1, "non_existent", "value")
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent field")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_GetUserFieldValues(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create test field
|
|
req := &service.CreateFieldRequest{
|
|
Name: "值字段",
|
|
FieldKey: "value_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
|
|
// Set value
|
|
svc.SetUserFieldValue(ctx, 1, "value_field", "test value")
|
|
|
|
t.Run("Get user field values", func(t *testing.T) {
|
|
values, err := svc.GetUserFieldValues(ctx, 1)
|
|
if err != nil {
|
|
t.Fatalf("GetUserFieldValues failed: %v", err)
|
|
}
|
|
if len(values) == 0 {
|
|
t.Error("Expected at least one field value")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_ValidateFieldValue(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
t.Run("Validate required field", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "必填字段",
|
|
FieldKey: "required_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
Required: true,
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
|
|
err := svc.SetUserFieldValue(ctx, 1, "required_field", "")
|
|
if err == nil {
|
|
t.Error("Expected error for empty required field")
|
|
}
|
|
})
|
|
|
|
t.Run("Validate number field", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "数字验证",
|
|
FieldKey: "num_validate",
|
|
Type: int(domain.CustomFieldTypeNumber),
|
|
MinVal: 0,
|
|
MaxVal: 100,
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
|
|
// Valid number
|
|
err := svc.SetUserFieldValue(ctx, 1, "num_validate", "50")
|
|
if err != nil {
|
|
t.Fatalf("SetUserFieldValue failed: %v", err)
|
|
}
|
|
|
|
// Invalid number
|
|
err = svc.SetUserFieldValue(ctx, 1, "num_validate", "not_a_number")
|
|
if err == nil {
|
|
t.Error("Expected error for invalid number")
|
|
}
|
|
|
|
// Number too large
|
|
err = svc.SetUserFieldValue(ctx, 1, "num_validate", "200")
|
|
if err == nil {
|
|
t.Error("Expected error for number too large")
|
|
}
|
|
})
|
|
|
|
t.Run("Validate boolean field", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "布尔验证",
|
|
FieldKey: "bool_validate",
|
|
Type: int(domain.CustomFieldTypeBoolean),
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
|
|
// Valid boolean
|
|
err := svc.SetUserFieldValue(ctx, 1, "bool_validate", "true")
|
|
if err != nil {
|
|
t.Fatalf("SetUserFieldValue failed: %v", err)
|
|
}
|
|
|
|
// Invalid boolean
|
|
err = svc.SetUserFieldValue(ctx, 1, "bool_validate", "yes")
|
|
if err == nil {
|
|
t.Error("Expected error for invalid boolean")
|
|
}
|
|
})
|
|
|
|
t.Run("Validate date field", func(t *testing.T) {
|
|
req := &service.CreateFieldRequest{
|
|
Name: "日期验证",
|
|
FieldKey: "date_validate",
|
|
Type: int(domain.CustomFieldTypeDate),
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
|
|
// Valid date
|
|
err := svc.SetUserFieldValue(ctx, 1, "date_validate", "2024-01-15")
|
|
if err != nil {
|
|
t.Fatalf("SetUserFieldValue failed: %v", err)
|
|
}
|
|
|
|
// Invalid date
|
|
err = svc.SetUserFieldValue(ctx, 1, "date_validate", "not_a_date")
|
|
if err == nil {
|
|
t.Error("Expected error for invalid date")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_DeleteUserFieldValue(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create test field
|
|
req := &service.CreateFieldRequest{
|
|
Name: "删除值字段",
|
|
FieldKey: "delete_value_field",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
}
|
|
svc.CreateField(ctx, req)
|
|
|
|
// Set value
|
|
svc.SetUserFieldValue(ctx, 1, "delete_value_field", "test")
|
|
|
|
t.Run("Delete user field value", func(t *testing.T) {
|
|
err := svc.DeleteUserFieldValue(ctx, 1, "delete_value_field")
|
|
if err != nil {
|
|
t.Fatalf("DeleteUserFieldValue failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Delete non-existent field value", func(t *testing.T) {
|
|
err := svc.DeleteUserFieldValue(ctx, 1, "non_existent")
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent field")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCustomFieldService_BatchSetUserFieldValues(t *testing.T) {
|
|
svc, _ := setupCustomFieldTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create test fields
|
|
svc.CreateField(ctx, &service.CreateFieldRequest{
|
|
Name: "批量字段1",
|
|
FieldKey: "batch_field1",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
})
|
|
svc.CreateField(ctx, &service.CreateFieldRequest{
|
|
Name: "批量字段2",
|
|
FieldKey: "batch_field2",
|
|
Type: int(domain.CustomFieldTypeString),
|
|
})
|
|
|
|
t.Run("Batch set user field values success", func(t *testing.T) {
|
|
values := map[string]string{
|
|
"batch_field1": "value1",
|
|
"batch_field2": "value2",
|
|
}
|
|
err := svc.BatchSetUserFieldValues(ctx, 1, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchSetUserFieldValues failed: %v", err)
|
|
}
|
|
|
|
// Verify values were set
|
|
userValues, err := svc.GetUserFieldValues(ctx, 1)
|
|
if err != nil {
|
|
t.Fatalf("GetUserFieldValues failed: %v", err)
|
|
}
|
|
if len(userValues) < 2 {
|
|
t.Errorf("Expected at least 2 field values, got %d", len(userValues))
|
|
}
|
|
})
|
|
|
|
t.Run("Batch set with non-existent field", func(t *testing.T) {
|
|
values := map[string]string{
|
|
"non_existent_field": "value",
|
|
}
|
|
err := svc.BatchSetUserFieldValues(ctx, 1, values)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent field")
|
|
}
|
|
})
|
|
|
|
t.Run("Batch set with empty map", func(t *testing.T) {
|
|
values := map[string]string{}
|
|
err := svc.BatchSetUserFieldValues(ctx, 1, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchSetUserFieldValues with empty map should succeed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Batch set with invalid value", func(t *testing.T) {
|
|
// Create a number field with validation
|
|
svc.CreateField(ctx, &service.CreateFieldRequest{
|
|
Name: "批量数字字段",
|
|
FieldKey: "batch_number",
|
|
Type: int(domain.CustomFieldTypeNumber),
|
|
MinVal: 0,
|
|
MaxVal: 100,
|
|
})
|
|
|
|
values := map[string]string{
|
|
"batch_number": "200", // exceeds max
|
|
}
|
|
err := svc.BatchSetUserFieldValues(ctx, 1, values)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid value")
|
|
}
|
|
})
|
|
}
|