Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
//go:build unit
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAdminService_CreateUser_WithAdminRole(t *testing.T) {
|
||||
repo := &userRepoStub{nextID: 30}
|
||||
svc := &adminServiceImpl{userRepo: repo}
|
||||
|
||||
user, err := svc.CreateUser(context.Background(), &CreateUserInput{
|
||||
Email: "admin@test.com",
|
||||
Password: "strong-pass",
|
||||
Role: RoleAdmin,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, RoleAdmin, user.Role)
|
||||
}
|
||||
|
||||
func TestAdminService_CreateUser_DefaultsToUserRole(t *testing.T) {
|
||||
repo := &userRepoStub{nextID: 31}
|
||||
svc := &adminServiceImpl{userRepo: repo}
|
||||
|
||||
user, err := svc.CreateUser(context.Background(), &CreateUserInput{
|
||||
Email: "plain@test.com",
|
||||
Password: "strong-pass",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, RoleUser, user.Role)
|
||||
}
|
||||
|
||||
func TestAdminService_CreateUser_InvalidRoleRejected(t *testing.T) {
|
||||
repo := &userRepoStub{nextID: 32}
|
||||
svc := &adminServiceImpl{userRepo: repo}
|
||||
|
||||
_, err := svc.CreateUser(context.Background(), &CreateUserInput{
|
||||
Email: "bad@test.com",
|
||||
Password: "strong-pass",
|
||||
Role: "superuser",
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.Empty(t, repo.created, "非法角色不应写入用户")
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateUser_PromoteToAdmin(t *testing.T) {
|
||||
base := &userRepoStub{user: &User{ID: 42, Email: "u@example.com", Role: RoleUser}}
|
||||
repo := &rpmUserRepoStub{userRepoStub: base}
|
||||
invalidator := &authCacheInvalidatorStub{}
|
||||
svc := &adminServiceImpl{
|
||||
userRepo: repo,
|
||||
redeemCodeRepo: &redeemRepoStub{},
|
||||
authCacheInvalidator: invalidator,
|
||||
}
|
||||
|
||||
updated, err := svc.UpdateUser(context.Background(), 42, &UpdateUserInput{Role: RoleAdmin})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, RoleAdmin, updated.Role)
|
||||
require.Equal(t, []int64{42}, invalidator.userIDs, "角色变更应失效认证缓存")
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateUser_RoleOmittedKeepsExisting(t *testing.T) {
|
||||
base := &userRepoStub{user: &User{ID: 42, Email: "u@example.com", Role: RoleAdmin}}
|
||||
repo := &rpmUserRepoStub{userRepoStub: base}
|
||||
svc := &adminServiceImpl{userRepo: repo, redeemCodeRepo: &redeemRepoStub{}}
|
||||
|
||||
newName := "renamed"
|
||||
updated, err := svc.UpdateUser(context.Background(), 42, &UpdateUserInput{Username: &newName})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, RoleAdmin, updated.Role, "未提供 role 时不应改变现有角色")
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateUser_InvalidRoleRejected(t *testing.T) {
|
||||
base := &userRepoStub{user: &User{ID: 42, Email: "u@example.com", Role: RoleUser}}
|
||||
repo := &rpmUserRepoStub{userRepoStub: base}
|
||||
svc := &adminServiceImpl{userRepo: repo, redeemCodeRepo: &redeemRepoStub{}}
|
||||
|
||||
_, err := svc.UpdateUser(context.Background(), 42, &UpdateUserInput{Role: "root"})
|
||||
require.Error(t, err)
|
||||
require.Nil(t, repo.lastUpdated, "非法角色不应触发持久化")
|
||||
}
|
||||
|
||||
// roleGuardUserRepoStub 在 rpmUserRepoStub 之上提供可控的管理员计数,
|
||||
// 用于测试"最后一个管理员不可降级"守卫。
|
||||
type roleGuardUserRepoStub struct {
|
||||
*rpmUserRepoStub
|
||||
adminTotal int64
|
||||
listCalls int
|
||||
}
|
||||
|
||||
func (s *roleGuardUserRepoStub) ListWithFilters(_ context.Context, _ pagination.PaginationParams, _ UserListFilters) ([]User, *pagination.PaginationResult, error) {
|
||||
s.listCalls++
|
||||
return nil, &pagination.PaginationResult{Total: s.adminTotal}, nil
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateUser_DemoteLastAdminRejected(t *testing.T) {
|
||||
base := &userRepoStub{user: &User{ID: 42, Email: "a@example.com", Role: RoleAdmin}}
|
||||
repo := &roleGuardUserRepoStub{rpmUserRepoStub: &rpmUserRepoStub{userRepoStub: base}, adminTotal: 1}
|
||||
svc := &adminServiceImpl{userRepo: repo, redeemCodeRepo: &redeemRepoStub{}}
|
||||
|
||||
_, err := svc.UpdateUser(context.Background(), 42, &UpdateUserInput{Role: RoleUser})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "last admin")
|
||||
require.Nil(t, repo.lastUpdated, "最后一个管理员不应被降级持久化")
|
||||
require.Equal(t, 1, repo.listCalls, "降级路径应触发管理员计数")
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateUser_DemoteAdminAllowedWhenOthersExist(t *testing.T) {
|
||||
base := &userRepoStub{user: &User{ID: 42, Email: "a@example.com", Role: RoleAdmin}}
|
||||
repo := &roleGuardUserRepoStub{rpmUserRepoStub: &rpmUserRepoStub{userRepoStub: base}, adminTotal: 2}
|
||||
invalidator := &authCacheInvalidatorStub{}
|
||||
svc := &adminServiceImpl{
|
||||
userRepo: repo,
|
||||
redeemCodeRepo: &redeemRepoStub{},
|
||||
authCacheInvalidator: invalidator,
|
||||
}
|
||||
|
||||
updated, err := svc.UpdateUser(context.Background(), 42, &UpdateUserInput{Role: RoleUser})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, RoleUser, updated.Role)
|
||||
require.NotNil(t, repo.lastUpdated)
|
||||
require.Equal(t, RoleUser, repo.lastUpdated.Role, "存在其他管理员时允许降级")
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateUser_PromoteDoesNotCountAdmins(t *testing.T) {
|
||||
base := &userRepoStub{user: &User{ID: 42, Email: "u@example.com", Role: RoleUser}}
|
||||
repo := &roleGuardUserRepoStub{rpmUserRepoStub: &rpmUserRepoStub{userRepoStub: base}, adminTotal: 1}
|
||||
svc := &adminServiceImpl{
|
||||
userRepo: repo,
|
||||
redeemCodeRepo: &redeemRepoStub{},
|
||||
authCacheInvalidator: &authCacheInvalidatorStub{},
|
||||
}
|
||||
|
||||
updated, err := svc.UpdateUser(context.Background(), 42, &UpdateUserInput{Role: RoleAdmin})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, RoleAdmin, updated.Role)
|
||||
require.Equal(t, 0, repo.listCalls, "升级路径不应触发管理员计数")
|
||||
}
|
||||
Reference in New Issue
Block a user