- Updated main.go to initialize email service and include it in the dependency injection container. - Refactored handlers to utilize context in service method calls, improving consistency and error handling. - Introduced new service options for upload, security, and captcha services, enhancing modularity and testability. - Removed unused repository implementations to streamline the codebase. This commit continues the effort to improve the architecture by ensuring all services are properly injected and utilized across the application.
741 lines
17 KiB
Go
741 lines
17 KiB
Go
package service
|
||
|
||
import (
|
||
"carrotskin/internal/model"
|
||
"context"
|
||
"testing"
|
||
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// TestProfileService_Validation 测试Profile服务验证逻辑
|
||
func TestProfileService_Validation(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
userID int64
|
||
profileName string
|
||
wantValid bool
|
||
}{
|
||
{
|
||
name: "有效的用户ID和角色名",
|
||
userID: 1,
|
||
profileName: "TestProfile",
|
||
wantValid: true,
|
||
},
|
||
{
|
||
name: "用户ID为0时无效",
|
||
userID: 0,
|
||
profileName: "TestProfile",
|
||
wantValid: false,
|
||
},
|
||
{
|
||
name: "角色名为空时无效",
|
||
userID: 1,
|
||
profileName: "",
|
||
wantValid: false,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
isValid := tt.userID > 0 && tt.profileName != ""
|
||
if isValid != tt.wantValid {
|
||
t.Errorf("Validation failed: got %v, want %v", isValid, tt.wantValid)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestProfileService_StatusValidation 测试用户状态验证
|
||
func TestProfileService_StatusValidation(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
status int16
|
||
wantValid bool
|
||
}{
|
||
{
|
||
name: "状态为1(正常)时有效",
|
||
status: 1,
|
||
wantValid: true,
|
||
},
|
||
{
|
||
name: "状态为0(禁用)时无效",
|
||
status: 0,
|
||
wantValid: false,
|
||
},
|
||
{
|
||
name: "状态为-1(删除)时无效",
|
||
status: -1,
|
||
wantValid: false,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
isValid := tt.status == 1
|
||
if isValid != tt.wantValid {
|
||
t.Errorf("Status validation failed: got %v, want %v", isValid, tt.wantValid)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestProfileService_IsActiveDefault 测试Profile默认活跃状态
|
||
func TestProfileService_IsActiveDefault(t *testing.T) {
|
||
// 新创建的档案默认为活跃状态
|
||
isActive := true
|
||
if !isActive {
|
||
t.Error("新创建的Profile应该默认为活跃状态")
|
||
}
|
||
}
|
||
|
||
// TestUpdateProfile_PermissionCheck 测试更新Profile的权限检查逻辑
|
||
func TestUpdateProfile_PermissionCheck(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
profileUserID int64
|
||
requestUserID int64
|
||
wantErr bool
|
||
}{
|
||
{
|
||
name: "用户ID匹配,允许操作",
|
||
profileUserID: 1,
|
||
requestUserID: 1,
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "用户ID不匹配,拒绝操作",
|
||
profileUserID: 1,
|
||
requestUserID: 2,
|
||
wantErr: true,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
hasError := tt.profileUserID != tt.requestUserID
|
||
if hasError != tt.wantErr {
|
||
t.Errorf("Permission check failed: got %v, want %v", hasError, tt.wantErr)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestUpdateProfile_NameValidation 测试更新Profile时名称验证逻辑
|
||
func TestUpdateProfile_NameValidation(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
currentName string
|
||
newName *string
|
||
shouldCheck bool
|
||
}{
|
||
{
|
||
name: "名称未改变,不检查",
|
||
currentName: "TestProfile",
|
||
newName: stringPtr("TestProfile"),
|
||
shouldCheck: false,
|
||
},
|
||
{
|
||
name: "名称改变,需要检查",
|
||
currentName: "TestProfile",
|
||
newName: stringPtr("NewProfile"),
|
||
shouldCheck: true,
|
||
},
|
||
{
|
||
name: "名称为nil,不检查",
|
||
currentName: "TestProfile",
|
||
newName: nil,
|
||
shouldCheck: false,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
shouldCheck := tt.newName != nil && *tt.newName != tt.currentName
|
||
if shouldCheck != tt.shouldCheck {
|
||
t.Errorf("Name validation check failed: got %v, want %v", shouldCheck, tt.shouldCheck)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestDeleteProfile_PermissionCheck 测试删除Profile的权限检查
|
||
func TestDeleteProfile_PermissionCheck(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
profileUserID int64
|
||
requestUserID int64
|
||
wantErr bool
|
||
}{
|
||
{
|
||
name: "用户ID匹配,允许删除",
|
||
profileUserID: 1,
|
||
requestUserID: 1,
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "用户ID不匹配,拒绝删除",
|
||
profileUserID: 1,
|
||
requestUserID: 2,
|
||
wantErr: true,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
hasError := tt.profileUserID != tt.requestUserID
|
||
if hasError != tt.wantErr {
|
||
t.Errorf("Permission check failed: got %v, want %v", hasError, tt.wantErr)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestSetActiveProfile_PermissionCheck 测试设置活跃Profile的权限检查
|
||
func TestSetActiveProfile_PermissionCheck(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
profileUserID int64
|
||
requestUserID int64
|
||
wantErr bool
|
||
}{
|
||
{
|
||
name: "用户ID匹配,允许设置",
|
||
profileUserID: 1,
|
||
requestUserID: 1,
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "用户ID不匹配,拒绝设置",
|
||
profileUserID: 1,
|
||
requestUserID: 2,
|
||
wantErr: true,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
hasError := tt.profileUserID != tt.requestUserID
|
||
if hasError != tt.wantErr {
|
||
t.Errorf("Permission check failed: got %v, want %v", hasError, tt.wantErr)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestCheckProfileLimit_Logic 测试Profile数量限制检查逻辑
|
||
func TestCheckProfileLimit_Logic(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
count int
|
||
maxProfiles int
|
||
wantErr bool
|
||
}{
|
||
{
|
||
name: "未达到上限",
|
||
count: 5,
|
||
maxProfiles: 10,
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "达到上限",
|
||
count: 10,
|
||
maxProfiles: 10,
|
||
wantErr: true,
|
||
},
|
||
{
|
||
name: "超过上限",
|
||
count: 15,
|
||
maxProfiles: 10,
|
||
wantErr: true,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
hasError := tt.count >= tt.maxProfiles
|
||
if hasError != tt.wantErr {
|
||
t.Errorf("Limit check failed: got %v, want %v", hasError, tt.wantErr)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestValidateProfileByUserID_InputValidation 测试ValidateProfileByUserID输入验证
|
||
func TestValidateProfileByUserID_InputValidation(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
userID int64
|
||
uuid string
|
||
wantErr bool
|
||
}{
|
||
{
|
||
name: "有效输入",
|
||
userID: 1,
|
||
uuid: "test-uuid",
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "userID为0",
|
||
userID: 0,
|
||
uuid: "test-uuid",
|
||
wantErr: true,
|
||
},
|
||
{
|
||
name: "uuid为空",
|
||
userID: 1,
|
||
uuid: "",
|
||
wantErr: true,
|
||
},
|
||
{
|
||
name: "两者都无效",
|
||
userID: 0,
|
||
uuid: "",
|
||
wantErr: true,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
hasError := tt.userID == 0 || tt.uuid == ""
|
||
if hasError != tt.wantErr {
|
||
t.Errorf("Input validation failed: got %v, want %v", hasError, tt.wantErr)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestValidateProfileByUserID_UserIDMatching 测试用户ID匹配逻辑
|
||
func TestValidateProfileByUserID_UserIDMatching(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
profileUserID int64
|
||
requestUserID int64
|
||
wantValid bool
|
||
}{
|
||
{
|
||
name: "用户ID匹配",
|
||
profileUserID: 1,
|
||
requestUserID: 1,
|
||
wantValid: true,
|
||
},
|
||
{
|
||
name: "用户ID不匹配",
|
||
profileUserID: 1,
|
||
requestUserID: 2,
|
||
wantValid: false,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
isValid := tt.profileUserID == tt.requestUserID
|
||
if isValid != tt.wantValid {
|
||
t.Errorf("UserID matching failed: got %v, want %v", isValid, tt.wantValid)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestGenerateRSAPrivateKey 测试RSA私钥生成
|
||
func TestGenerateRSAPrivateKey(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
wantError bool
|
||
}{
|
||
{
|
||
name: "生成RSA私钥",
|
||
wantError: false,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
privateKey, err := generateRSAPrivateKeyInternal()
|
||
if (err != nil) != tt.wantError {
|
||
t.Errorf("generateRSAPrivateKeyInternal() error = %v, wantError %v", err, tt.wantError)
|
||
return
|
||
}
|
||
if !tt.wantError {
|
||
if privateKey == "" {
|
||
t.Error("generateRSAPrivateKeyInternal() 返回的私钥不应为空")
|
||
}
|
||
// 验证PEM格式
|
||
if len(privateKey) < 100 {
|
||
t.Errorf("generateRSAPrivateKeyInternal() 返回的私钥长度异常: %d", len(privateKey))
|
||
}
|
||
// 验证包含PEM头部
|
||
if !contains(privateKey, "BEGIN RSA PRIVATE KEY") {
|
||
t.Error("generateRSAPrivateKeyInternal() 返回的私钥应包含PEM头部")
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestGenerateRSAPrivateKey_Uniqueness 测试RSA私钥唯一性
|
||
func TestGenerateRSAPrivateKey_Uniqueness(t *testing.T) {
|
||
keys := make(map[string]bool)
|
||
for i := 0; i < 10; i++ {
|
||
key, err := generateRSAPrivateKeyInternal()
|
||
if err != nil {
|
||
t.Fatalf("generateRSAPrivateKeyInternal() 失败: %v", err)
|
||
}
|
||
if keys[key] {
|
||
t.Errorf("第%d次生成的密钥与之前重复", i+1)
|
||
}
|
||
keys[key] = true
|
||
}
|
||
}
|
||
|
||
// 辅助函数
|
||
func stringPtr(s string) *string {
|
||
return &s
|
||
}
|
||
|
||
func contains(s, substr string) bool {
|
||
return len(s) >= len(substr) && (s == substr ||
|
||
(len(s) > len(substr) && (s[:len(substr)] == substr ||
|
||
s[len(s)-len(substr):] == substr ||
|
||
containsMiddle(s, substr))))
|
||
}
|
||
|
||
func containsMiddle(s, substr string) bool {
|
||
for i := 0; i <= len(s)-len(substr); i++ {
|
||
if s[i:i+len(substr)] == substr {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// ============================================================================
|
||
// 使用 Mock 的集成测试
|
||
// ============================================================================
|
||
|
||
// TestProfileServiceImpl_Create 测试创建Profile
|
||
func TestProfileServiceImpl_Create(t *testing.T) {
|
||
profileRepo := NewMockProfileRepository()
|
||
userRepo := NewMockUserRepository()
|
||
logger := zap.NewNop()
|
||
|
||
// 预置用户
|
||
testUser := &model.User{
|
||
ID: 1,
|
||
Username: "testuser",
|
||
Email: "test@example.com",
|
||
Status: 1,
|
||
}
|
||
userRepo.Create(testUser)
|
||
|
||
cacheManager := NewMockCacheManager()
|
||
profileService := NewProfileService(profileRepo, userRepo, cacheManager, logger)
|
||
|
||
tests := []struct {
|
||
name string
|
||
userID int64
|
||
profileName string
|
||
wantErr bool
|
||
errMsg string
|
||
setupMocks func()
|
||
}{
|
||
{
|
||
name: "正常创建Profile",
|
||
userID: 1,
|
||
profileName: "TestProfile",
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "用户不存在",
|
||
userID: 999,
|
||
profileName: "TestProfile2",
|
||
wantErr: true,
|
||
errMsg: "用户不存在",
|
||
},
|
||
{
|
||
name: "角色名已存在",
|
||
userID: 1,
|
||
profileName: "ExistingProfile",
|
||
wantErr: true,
|
||
errMsg: "角色名已被使用",
|
||
setupMocks: func() {
|
||
profileRepo.Create(&model.Profile{
|
||
UUID: "existing-uuid",
|
||
UserID: 2,
|
||
Name: "ExistingProfile",
|
||
})
|
||
},
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
if tt.setupMocks != nil {
|
||
tt.setupMocks()
|
||
}
|
||
|
||
ctx := context.Background()
|
||
profile, err := profileService.Create(ctx, tt.userID, tt.profileName)
|
||
|
||
if tt.wantErr {
|
||
if err == nil {
|
||
t.Error("期望返回错误,但实际没有错误")
|
||
return
|
||
}
|
||
if tt.errMsg != "" && err.Error() != tt.errMsg {
|
||
t.Errorf("错误信息不匹配: got %v, want %v", err.Error(), tt.errMsg)
|
||
}
|
||
} else {
|
||
if err != nil {
|
||
t.Errorf("不期望返回错误: %v", err)
|
||
return
|
||
}
|
||
if profile == nil {
|
||
t.Error("返回的Profile不应为nil")
|
||
}
|
||
if profile.Name != tt.profileName {
|
||
t.Errorf("Profile名称不匹配: got %v, want %v", profile.Name, tt.profileName)
|
||
}
|
||
if profile.UUID == "" {
|
||
t.Error("Profile UUID不应为空")
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestProfileServiceImpl_GetByUUID 测试获取Profile
|
||
func TestProfileServiceImpl_GetByUUID(t *testing.T) {
|
||
profileRepo := NewMockProfileRepository()
|
||
userRepo := NewMockUserRepository()
|
||
logger := zap.NewNop()
|
||
|
||
// 预置Profile
|
||
testProfile := &model.Profile{
|
||
UUID: "test-uuid-123",
|
||
UserID: 1,
|
||
Name: "TestProfile",
|
||
}
|
||
profileRepo.Create(testProfile)
|
||
|
||
cacheManager := NewMockCacheManager()
|
||
profileService := NewProfileService(profileRepo, userRepo, cacheManager, logger)
|
||
|
||
tests := []struct {
|
||
name string
|
||
uuid string
|
||
wantErr bool
|
||
}{
|
||
{
|
||
name: "获取存在的Profile",
|
||
uuid: "test-uuid-123",
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "获取不存在的Profile",
|
||
uuid: "non-existent-uuid",
|
||
wantErr: true,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
ctx := context.Background()
|
||
profile, err := profileService.GetByUUID(ctx, tt.uuid)
|
||
|
||
if tt.wantErr {
|
||
if err == nil {
|
||
t.Error("期望返回错误,但实际没有错误")
|
||
}
|
||
} else {
|
||
if err != nil {
|
||
t.Errorf("不期望返回错误: %v", err)
|
||
return
|
||
}
|
||
if profile == nil {
|
||
t.Error("返回的Profile不应为nil")
|
||
}
|
||
if profile.UUID != tt.uuid {
|
||
t.Errorf("Profile UUID不匹配: got %v, want %v", profile.UUID, tt.uuid)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestProfileServiceImpl_Delete 测试删除Profile
|
||
func TestProfileServiceImpl_Delete(t *testing.T) {
|
||
profileRepo := NewMockProfileRepository()
|
||
userRepo := NewMockUserRepository()
|
||
logger := zap.NewNop()
|
||
|
||
// 预置Profile
|
||
testProfile := &model.Profile{
|
||
UUID: "delete-test-uuid",
|
||
UserID: 1,
|
||
Name: "DeleteTestProfile",
|
||
}
|
||
profileRepo.Create(testProfile)
|
||
|
||
cacheManager := NewMockCacheManager()
|
||
profileService := NewProfileService(profileRepo, userRepo, cacheManager, logger)
|
||
|
||
tests := []struct {
|
||
name string
|
||
uuid string
|
||
userID int64
|
||
wantErr bool
|
||
}{
|
||
{
|
||
name: "正常删除",
|
||
uuid: "delete-test-uuid",
|
||
userID: 1,
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "用户ID不匹配",
|
||
uuid: "delete-test-uuid",
|
||
userID: 2,
|
||
wantErr: true,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
ctx := context.Background()
|
||
err := profileService.Delete(ctx, tt.uuid, tt.userID)
|
||
|
||
if tt.wantErr {
|
||
if err == nil {
|
||
t.Error("期望返回错误,但实际没有错误")
|
||
}
|
||
} else {
|
||
if err != nil {
|
||
t.Errorf("不期望返回错误: %v", err)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestProfileServiceImpl_GetByUserID 测试按用户获取档案列表
|
||
func TestProfileServiceImpl_GetByUserID(t *testing.T) {
|
||
profileRepo := NewMockProfileRepository()
|
||
userRepo := NewMockUserRepository()
|
||
logger := zap.NewNop()
|
||
|
||
// 为用户 1 和 2 预置不同档案
|
||
profileRepo.Create(&model.Profile{UUID: "p1", UserID: 1, Name: "P1"})
|
||
profileRepo.Create(&model.Profile{UUID: "p2", UserID: 1, Name: "P2"})
|
||
profileRepo.Create(&model.Profile{UUID: "p3", UserID: 2, Name: "P3"})
|
||
|
||
cacheManager := NewMockCacheManager()
|
||
svc := NewProfileService(profileRepo, userRepo, cacheManager, logger)
|
||
|
||
ctx := context.Background()
|
||
list, err := svc.GetByUserID(ctx, 1)
|
||
if err != nil {
|
||
t.Fatalf("GetByUserID 失败: %v", err)
|
||
}
|
||
if len(list) != 2 {
|
||
t.Fatalf("GetByUserID 返回数量错误, got=%d, want=2", len(list))
|
||
}
|
||
}
|
||
|
||
// TestProfileServiceImpl_Update_And_SetActive 测试 Update 与 SetActive
|
||
func TestProfileServiceImpl_Update_And_SetActive(t *testing.T) {
|
||
profileRepo := NewMockProfileRepository()
|
||
userRepo := NewMockUserRepository()
|
||
logger := zap.NewNop()
|
||
|
||
profile := &model.Profile{
|
||
UUID: "u1",
|
||
UserID: 1,
|
||
Name: "OldName",
|
||
}
|
||
profileRepo.Create(profile)
|
||
|
||
cacheManager := NewMockCacheManager()
|
||
svc := NewProfileService(profileRepo, userRepo, cacheManager, logger)
|
||
|
||
ctx := context.Background()
|
||
|
||
// 正常更新名称与皮肤/披风
|
||
newName := "NewName"
|
||
var skinID int64 = 10
|
||
var capeID int64 = 20
|
||
updated, err := svc.Update(ctx, "u1", 1, &newName, &skinID, &capeID)
|
||
if err != nil {
|
||
t.Fatalf("Update 正常情况失败: %v", err)
|
||
}
|
||
if updated == nil || updated.Name != newName {
|
||
t.Fatalf("Update 未更新名称, got=%+v", updated)
|
||
}
|
||
|
||
// 用户无权限
|
||
if _, err := svc.Update(ctx, "u1", 2, &newName, nil, nil); err == nil {
|
||
t.Fatalf("Update 在无权限时应返回错误")
|
||
}
|
||
|
||
// 名称重复
|
||
profileRepo.Create(&model.Profile{
|
||
UUID: "u2",
|
||
UserID: 2,
|
||
Name: "Duplicate",
|
||
})
|
||
if _, err := svc.Update(ctx, "u1", 1, stringPtr("Duplicate"), nil, nil); err == nil {
|
||
t.Fatalf("Update 在名称重复时应返回错误")
|
||
}
|
||
|
||
// SetActive 正常
|
||
if err := svc.SetActive(ctx, "u1", 1); err != nil {
|
||
t.Fatalf("SetActive 正常情况失败: %v", err)
|
||
}
|
||
|
||
// SetActive 无权限
|
||
if err := svc.SetActive(ctx, "u1", 2); err == nil {
|
||
t.Fatalf("SetActive 在无权限时应返回错误")
|
||
}
|
||
}
|
||
|
||
// TestProfileServiceImpl_CheckLimit_And_GetByNames 测试 CheckLimit / GetByNames / GetByProfileName
|
||
func TestProfileServiceImpl_CheckLimit_And_GetByNames(t *testing.T) {
|
||
profileRepo := NewMockProfileRepository()
|
||
userRepo := NewMockUserRepository()
|
||
logger := zap.NewNop()
|
||
|
||
// 为用户 1 预置 2 个档案
|
||
profileRepo.Create(&model.Profile{UUID: "a", UserID: 1, Name: "A"})
|
||
profileRepo.Create(&model.Profile{UUID: "b", UserID: 1, Name: "B"})
|
||
|
||
cacheManager := NewMockCacheManager()
|
||
svc := NewProfileService(profileRepo, userRepo, cacheManager, logger)
|
||
|
||
ctx := context.Background()
|
||
|
||
// CheckLimit 未达上限
|
||
if err := svc.CheckLimit(ctx, 1, 3); err != nil {
|
||
t.Fatalf("CheckLimit 未达到上限时不应报错: %v", err)
|
||
}
|
||
|
||
// CheckLimit 达到上限
|
||
if err := svc.CheckLimit(ctx, 1, 2); err == nil {
|
||
t.Fatalf("CheckLimit 达到上限时应报错")
|
||
}
|
||
|
||
// GetByNames
|
||
list, err := svc.GetByNames(ctx, []string{"A", "B"})
|
||
if err != nil {
|
||
t.Fatalf("GetByNames 失败: %v", err)
|
||
}
|
||
if len(list) != 2 {
|
||
t.Fatalf("GetByNames 返回数量错误, got=%d, want=2", len(list))
|
||
}
|
||
|
||
// GetByProfileName 存在
|
||
p, err := svc.GetByProfileName(ctx, "A")
|
||
if err != nil || p == nil || p.Name != "A" {
|
||
t.Fatalf("GetByProfileName 返回错误, profile=%+v, err=%v", p, err)
|
||
}
|
||
}
|