mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
6.4 KiB
Go
315 lines
6.4 KiB
Go
package tests
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
// TestConcurrentOrgCreation 测试并发创建组织
|
|
func TestConcurrentOrgCreation(t *testing.T) {
|
|
ensureUsers(t)
|
|
|
|
var wg sync.WaitGroup
|
|
errors := make(chan error, 10)
|
|
|
|
// 并发创建多个组织
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func(index int) {
|
|
defer wg.Done()
|
|
|
|
resp := doRequest(t, "POST", "/api/orgs", map[string]string{
|
|
"code": "concurrent_org_" + string(rune('a'+index)),
|
|
"name": "Concurrent Org " + string(rune('A'+index)),
|
|
}, User1Token)
|
|
|
|
if resp.Code != 200 && resp.Code != 400 {
|
|
// 400 可能是重复创建,其他错误码需要记录
|
|
errors <- nil
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
close(errors)
|
|
|
|
// 检查是否有错误
|
|
errorCount := 0
|
|
for range errors {
|
|
errorCount++
|
|
}
|
|
|
|
if errorCount > 0 {
|
|
t.Errorf("Got %d errors during concurrent org creation", errorCount)
|
|
}
|
|
}
|
|
|
|
// TestConcurrentMemberAddition 测试并发添加成员
|
|
func TestConcurrentMemberAddition(t *testing.T) {
|
|
ensureUsers(t)
|
|
|
|
var orgID string
|
|
|
|
// User1 创建组织
|
|
resp := doRequest(t, "POST", "/api/orgs", map[string]string{
|
|
"code": "concurrent_member_test",
|
|
"name": "Concurrent Member Test",
|
|
}, User1Token)
|
|
|
|
if resp.Code == 200 {
|
|
var data struct {
|
|
ID string `json:"id"`
|
|
}
|
|
decodeResponse(t, resp, &data)
|
|
orgID = data.ID
|
|
}
|
|
|
|
if orgID == "" {
|
|
t.Skip("Failed to create org")
|
|
}
|
|
|
|
// 先添加 User2 为成员
|
|
resp = doRequest(t, "POST", "/api/orgs/"+orgID+"/members", map[string]string{
|
|
"user_id": User2ID,
|
|
"role": "member",
|
|
}, User1Token)
|
|
|
|
if resp.Code != 200 {
|
|
t.Skip("Failed to add initial member")
|
|
}
|
|
|
|
// 并发获取组织详情
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
resp := doRequest(t, "GET", "/api/orgs/"+orgID, nil, User2Token)
|
|
if resp.Code != 200 {
|
|
t.Errorf("Concurrent access failed with code: %d", resp.Code)
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// 清理
|
|
doRequest(t, "DELETE", "/api/orgs/"+orgID, nil, User1Token)
|
|
}
|
|
|
|
// TestConcurrentRoleUpdate 测试并发角色更新
|
|
func TestConcurrentRoleUpdate(t *testing.T) {
|
|
ensureUsers(t)
|
|
|
|
// 创建测试角色
|
|
resp := doRequest(t, "POST", "/api/roles", map[string]string{
|
|
"code": "concurrent_role",
|
|
"name": "Concurrent Role",
|
|
"description": "Role for concurrent test",
|
|
}, AdminToken)
|
|
|
|
if resp.Code != 200 {
|
|
t.Skip("Failed to create role")
|
|
}
|
|
|
|
var data struct {
|
|
ID string `json:"id"`
|
|
}
|
|
decodeResponse(t, resp, &data)
|
|
roleID := data.ID
|
|
|
|
// 并发更新角色权限
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func(index int) {
|
|
defer wg.Done()
|
|
|
|
var perms []string
|
|
if index%2 == 0 {
|
|
perms = []string{"vb:org:read"}
|
|
} else {
|
|
perms = []string{"vb:org:create"}
|
|
}
|
|
|
|
resp := doRequest(t, "PUT", "/api/roles/"+roleID+"/permissions", map[string]any{
|
|
"permission_ids": perms,
|
|
}, AdminToken)
|
|
|
|
if resp.Code != 200 {
|
|
t.Errorf("Concurrent role update failed with code: %d", resp.Code)
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// 清理
|
|
doRequest(t, "DELETE", "/api/roles/"+roleID, nil, AdminToken)
|
|
}
|
|
|
|
// TestConcurrentUserUpdate 测试并发用户更新
|
|
func TestConcurrentUserUpdate(t *testing.T) {
|
|
ensureUsers(t)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// User1 并发更新自己的信息
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func(index int) {
|
|
defer wg.Done()
|
|
|
|
resp := doRequest(t, "PATCH", "/api/auth/me", map[string]string{
|
|
"nickname": "Concurrent Update " + string(rune('A'+index)),
|
|
}, User1Token)
|
|
|
|
if resp.Code != 200 {
|
|
t.Errorf("Concurrent user update failed with code: %d", resp.Code)
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
// TestConcurrentTokenRefresh 测试并发 Token 刷新
|
|
func TestConcurrentTokenRefresh(t *testing.T) {
|
|
ensureUsers(t)
|
|
|
|
// 先获取 refresh token
|
|
resp := doRequest(t, "POST", "/api/auth/login", map[string]string{
|
|
"username": "user1_test",
|
|
"password": "password123",
|
|
}, "")
|
|
|
|
if resp.Code != 200 {
|
|
t.Skip("Failed to login")
|
|
}
|
|
|
|
var data struct {
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
decodeResponse(t, resp, &data)
|
|
|
|
if data.RefreshToken == "" {
|
|
t.Skip("No refresh token available")
|
|
}
|
|
|
|
// 并发刷新 token
|
|
var wg sync.WaitGroup
|
|
tokens := make(chan string, 5)
|
|
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
resp := doRequest(t, "POST", "/api/auth/refresh", map[string]string{
|
|
"refresh_token": data.RefreshToken,
|
|
}, "")
|
|
|
|
if resp.Code == 200 {
|
|
var refreshData struct {
|
|
AccessToken string `json:"access_token"`
|
|
}
|
|
decodeResponse(t, resp, &refreshData)
|
|
if refreshData.AccessToken != "" {
|
|
tokens <- refreshData.AccessToken
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
close(tokens)
|
|
|
|
// 验证至少有一个成功
|
|
tokenCount := 0
|
|
for range tokens {
|
|
tokenCount++
|
|
}
|
|
|
|
if tokenCount == 0 {
|
|
t.Errorf("All concurrent token refreshes failed")
|
|
}
|
|
}
|
|
|
|
// TestConcurrentPermissionCheck 测试并发权限检查
|
|
func TestConcurrentPermissionCheck(t *testing.T) {
|
|
ensureUsers(t)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// 多个用户并发检查权限
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func(index int) {
|
|
defer wg.Done()
|
|
|
|
var token string
|
|
switch index % 3 {
|
|
case 0:
|
|
token = AdminToken
|
|
case 1:
|
|
token = User1Token
|
|
case 2:
|
|
token = User2Token
|
|
}
|
|
|
|
resp := doRequest(t, "GET", "/api/orgs", nil, token)
|
|
// 所有用户都应该能访问 org 列表
|
|
if resp.Code != 200 {
|
|
t.Errorf("Permission check failed with code: %d", resp.Code)
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
// TestConcurrentOAuthClientOps 测试并发 OAuth 客户端操作
|
|
func TestConcurrentOAuthClientOps(t *testing.T) {
|
|
ensureUsers(t)
|
|
|
|
// 创建测试客户端
|
|
resp := doRequest(t, "POST", "/api/oauth/clients", map[string]any{
|
|
"name": "Concurrent Test Client",
|
|
"redirect_uris": []string{"https://example.com/callback"},
|
|
"allowed_scopes": "openid",
|
|
}, AdminToken)
|
|
|
|
if resp.Code != 200 {
|
|
t.Skip("Failed to create OAuth client")
|
|
}
|
|
|
|
var data struct {
|
|
ClientID string `json:"client_id"`
|
|
}
|
|
decodeResponse(t, resp, &data)
|
|
clientID := data.ClientID
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// 并发更新客户端
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func(index int) {
|
|
defer wg.Done()
|
|
|
|
resp := doRequest(t, "PATCH", "/api/oauth/clients/"+clientID, map[string]string{
|
|
"name": "Updated Name " + string(rune('A'+index)),
|
|
}, AdminToken)
|
|
|
|
if resp.Code != 200 {
|
|
t.Errorf("Concurrent OAuth client update failed with code: %d", resp.Code)
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// 清理
|
|
doRequest(t, "DELETE", "/api/oauth/clients/"+clientID, nil, AdminToken)
|
|
}
|