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) }