[feature/backend] registration control

This commit is contained in:
CDN 2025-02-21 04:38:47 +08:00
parent 86ab334bc9
commit a853374009
Signed by: CDN
GPG key ID: 0C656827F9F80080
5 changed files with 142 additions and 49 deletions

View file

@ -33,6 +33,15 @@ func (s *AuthHandlerTestSuite) SetupTest() {
JWT: config.JWTConfig{
Secret: "test-secret",
},
Auth: config.AuthConfig{
Registration: struct {
Enabled bool `yaml:"enabled"`
Message string `yaml:"message"`
}{
Enabled: true,
Message: "Registration is disabled",
},
},
}, s.service)
s.router = gin.New()
}
@ -45,6 +54,13 @@ func TestAuthHandlerSuite(t *testing.T) {
suite.Run(t, new(AuthHandlerTestSuite))
}
type ErrorResponse struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
func (s *AuthHandlerTestSuite) TestRegister() {
testCases := []struct {
name string
@ -52,6 +68,7 @@ func (s *AuthHandlerTestSuite) TestRegister() {
setupMock func()
expectedStatus int
expectedError string
registration bool
}{
{
name: "成功注册",
@ -74,6 +91,20 @@ func (s *AuthHandlerTestSuite) TestRegister() {
Return([]*ent.Role{{ID: 1, Name: "contributor"}}, nil)
},
expectedStatus: http.StatusCreated,
registration: true,
},
{
name: "注册功能已禁用",
request: RegisterRequest{
Username: "testuser",
Email: "test@example.com",
Password: "password123",
Role: "contributor",
},
setupMock: func() {},
expectedStatus: http.StatusForbidden,
expectedError: "Registration is disabled",
registration: false,
},
{
name: "无效的邮箱格式",
@ -86,6 +117,7 @@ func (s *AuthHandlerTestSuite) TestRegister() {
setupMock: func() {},
expectedStatus: http.StatusBadRequest,
expectedError: "Key: 'RegisterRequest.Email' Error:Field validation for 'Email' failed on the 'email' tag",
registration: true,
},
{
name: "密码太短",
@ -98,6 +130,7 @@ func (s *AuthHandlerTestSuite) TestRegister() {
setupMock: func() {},
expectedStatus: http.StatusBadRequest,
expectedError: "Key: 'RegisterRequest.Password' Error:Field validation for 'Password' failed on the 'min' tag",
registration: true,
},
{
name: "无效的角色",
@ -110,11 +143,15 @@ func (s *AuthHandlerTestSuite) TestRegister() {
setupMock: func() {},
expectedStatus: http.StatusBadRequest,
expectedError: "Key: 'RegisterRequest.Role' Error:Field validation for 'Role' failed on the 'oneof' tag",
registration: true,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
// 设置注册功能状态
s.handler.config.Auth.Registration.Enabled = tc.registration
// 设置 mock
tc.setupMock()
@ -132,10 +169,10 @@ func (s *AuthHandlerTestSuite) TestRegister() {
// 验证响应
s.Equal(tc.expectedStatus, w.Code)
if tc.expectedError != "" {
var response map[string]string
var response ErrorResponse
err := json.Unmarshal(w.Body.Bytes(), &response)
s.NoError(err)
s.Contains(response["error"], tc.expectedError)
s.Contains(response.Error.Message, tc.expectedError)
} else {
var response AuthResponse
err := json.Unmarshal(w.Body.Bytes(), &response)
@ -147,6 +184,8 @@ func (s *AuthHandlerTestSuite) TestRegister() {
}
func (s *AuthHandlerTestSuite) TestLogin() {
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost)
testCases := []struct {
name string
request LoginRequest
@ -161,35 +200,28 @@ func (s *AuthHandlerTestSuite) TestLogin() {
Password: "password123",
},
setupMock: func() {
// 使用 bcrypt 生成正确的密码哈希
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost)
user := &ent.User{
ID: 1,
Username: "testuser",
PasswordHash: string(hashedPassword),
}
s.service.EXPECT().
GetUserByUsername(gomock.Any(), "testuser").
Return(user, nil)
Return(&ent.User{
ID: 1,
Username: "testuser",
PasswordHash: string(hashedPassword),
}, nil)
s.service.EXPECT().
GetUserRoles(gomock.Any(), user.ID).
Return([]*ent.Role{{Name: "admin"}}, nil)
GetUserRoles(gomock.Any(), 1).
Return([]*ent.Role{{ID: 1, Name: "contributor"}}, nil)
},
expectedStatus: http.StatusOK,
},
{
name: "无效的用户名",
request: LoginRequest{
Username: "invalid",
Username: "te",
Password: "password123",
},
setupMock: func() {
s.service.EXPECT().
GetUserByUsername(gomock.Any(), "invalid").
Return(nil, fmt.Errorf("user not found"))
},
expectedStatus: http.StatusUnauthorized,
expectedError: "Invalid username or password",
setupMock: func() {},
expectedStatus: http.StatusBadRequest,
expectedError: "Key: 'LoginRequest.Username' Error:Field validation for 'Username' failed on the 'min' tag",
},
{
name: "用户不存在",
@ -209,19 +241,16 @@ func (s *AuthHandlerTestSuite) TestLogin() {
name: "密码错误",
request: LoginRequest{
Username: "testuser",
Password: "wrong-password",
Password: "wrongpassword",
},
setupMock: func() {
// 使用 bcrypt 生成正确的密码哈希
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost)
user := &ent.User{
ID: 1,
Username: "testuser",
PasswordHash: string(hashedPassword),
}
s.service.EXPECT().
GetUserByUsername(gomock.Any(), "testuser").
Return(user, nil)
Return(&ent.User{
ID: 1,
Username: "testuser",
PasswordHash: string(hashedPassword),
}, nil)
},
expectedStatus: http.StatusUnauthorized,
expectedError: "Invalid username or password",
@ -233,18 +262,15 @@ func (s *AuthHandlerTestSuite) TestLogin() {
Password: "password123",
},
setupMock: func() {
// 使用 bcrypt 生成正确的密码哈希
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost)
user := &ent.User{
ID: 1,
Username: "testuser",
PasswordHash: string(hashedPassword),
}
s.service.EXPECT().
GetUserByUsername(gomock.Any(), "testuser").
Return(user, nil)
Return(&ent.User{
ID: 1,
Username: "testuser",
PasswordHash: string(hashedPassword),
}, nil)
s.service.EXPECT().
GetUserRoles(gomock.Any(), user.ID).
GetUserRoles(gomock.Any(), 1).
Return(nil, fmt.Errorf("failed to get roles"))
},
expectedStatus: http.StatusInternalServerError,
@ -271,10 +297,10 @@ func (s *AuthHandlerTestSuite) TestLogin() {
// 验证响应
s.Equal(tc.expectedStatus, w.Code)
if tc.expectedError != "" {
var response map[string]string
var response ErrorResponse
err := json.Unmarshal(w.Body.Bytes(), &response)
s.NoError(err)
s.Contains(response["error"], tc.expectedError)
s.Contains(response.Error.Message, tc.expectedError)
} else {
var response AuthResponse
err := json.Unmarshal(w.Body.Bytes(), &response)