暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

batch_performance_test.go 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "testing"
  9. "time"
  10. "git.x2erp.com/qdy/go-svc-configure/internal/service/dicmanagement"
  11. )
  12. const (
  13. performanceBaseURL = "http://localhost:8080"
  14. )
  15. // getPerfAuthToken 获取性能测试认证token
  16. func getPerfAuthToken(t *testing.T) string {
  17. // 使用同一包中已存在的函数
  18. userToken, err := getUserAuthToken(t)
  19. if err != nil {
  20. t.Fatalf("获取用户认证token失败: %v", err)
  21. }
  22. configToken, err := createConfigToken(t, userToken)
  23. if err != nil {
  24. t.Fatalf("创建配置token失败: %v", err)
  25. }
  26. return configToken
  27. }
  28. // TestBatchPerformance 测试批量保存性能 - 10个表,100个字段
  29. func TestBatchPerformance(t *testing.T) {
  30. // 1. 批量创建10个表,每个表10个字段
  31. t.Run("BatchCreate10Tables100Fields", func(t *testing.T) {
  32. testBatchCreateLargeDataset(t, 10, 10)
  33. })
  34. // 2. 批量更新部分数据
  35. t.Run("BatchUpdatePartialData", func(t *testing.T) {
  36. testBatchUpdatePartial(t, 10, 10)
  37. })
  38. // 3. 清理测试数据
  39. t.Run("CleanupPerformanceTestData", func(t *testing.T) {
  40. cleanupPerformanceTestData(t, 10)
  41. })
  42. }
  43. // testBatchCreateLargeDataset 测试创建大规模数据集
  44. func testBatchCreateLargeDataset(t *testing.T, tableCount, fieldsPerTable int) {
  45. httpClient := &http.Client{}
  46. token := getPerfAuthToken(t)
  47. url := performanceBaseURL + "/api/dic-table/batch-save"
  48. // 生成测试数据
  49. startTime := time.Now()
  50. reqBody := generateLargeBatchRequest(tableCount, fieldsPerTable)
  51. generateTime := time.Since(startTime)
  52. t.Logf("生成 %d 个表,%d 个字段数据耗时: %v", tableCount, tableCount*fieldsPerTable, generateTime)
  53. jsonData, err := json.Marshal(reqBody)
  54. if err != nil {
  55. t.Fatalf("JSON序列化失败: %v", err)
  56. }
  57. req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
  58. if err != nil {
  59. t.Fatalf("创建请求失败: %v", err)
  60. }
  61. req.Header.Set("Authorization", "Bearer "+token)
  62. req.Header.Set("Content-Type", "application/json")
  63. // 执行请求并计时
  64. startTime = time.Now()
  65. resp, err := httpClient.Do(req)
  66. if err != nil {
  67. t.Fatalf("请求失败: %v", err)
  68. }
  69. defer resp.Body.Close()
  70. body, err := io.ReadAll(resp.Body)
  71. if err != nil {
  72. t.Fatalf("读取响应失败: %v", err)
  73. }
  74. executeTime := time.Since(startTime)
  75. var result map[string]interface{}
  76. if err := json.Unmarshal(body, &result); err != nil {
  77. t.Fatalf("JSON解析失败: %v", err)
  78. }
  79. if success, ok := result["success"].(bool); !ok || !success {
  80. t.Errorf("批量创建表失败: %v", result)
  81. } else {
  82. t.Logf("批量创建 %d 个表,%d 个字段成功,耗时: %v", tableCount, tableCount*fieldsPerTable, executeTime)
  83. t.Logf("总数据量: %d bytes", len(jsonData))
  84. }
  85. }
  86. // testBatchUpdatePartial 测试批量更新部分数据
  87. func testBatchUpdatePartial(t *testing.T, tableCount, fieldsPerTable int) {
  88. httpClient := &http.Client{}
  89. token := getPerfAuthToken(t)
  90. url := performanceBaseURL + "/api/dic-table/batch-save"
  91. // 生成更新数据:更新前5个表,每个表更新5个字段,新增5个字段
  92. startTime := time.Now()
  93. reqBody := generateUpdateBatchRequest(tableCount, fieldsPerTable)
  94. generateTime := time.Since(startTime)
  95. t.Logf("生成更新数据耗时: %v", generateTime)
  96. jsonData, err := json.Marshal(reqBody)
  97. if err != nil {
  98. t.Fatalf("JSON序列化失败: %v", err)
  99. }
  100. req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
  101. if err != nil {
  102. t.Fatalf("创建请求失败: %v", err)
  103. }
  104. req.Header.Set("Authorization", "Bearer "+token)
  105. req.Header.Set("Content-Type", "application/json")
  106. // 执行请求并计时
  107. startTime = time.Now()
  108. resp, err := httpClient.Do(req)
  109. if err != nil {
  110. t.Fatalf("请求失败: %v", err)
  111. }
  112. defer resp.Body.Close()
  113. body, err := io.ReadAll(resp.Body)
  114. if err != nil {
  115. t.Fatalf("读取响应失败: %v", err)
  116. }
  117. executeTime := time.Since(startTime)
  118. var result map[string]interface{}
  119. if err := json.Unmarshal(body, &result); err != nil {
  120. t.Fatalf("JSON解析失败: %v", err)
  121. }
  122. if success, ok := result["success"].(bool); !ok || !success {
  123. t.Errorf("批量更新表失败: %v", result)
  124. } else {
  125. t.Logf("批量更新成功,耗时: %v", executeTime)
  126. t.Logf("更新数据量: %d bytes", len(jsonData))
  127. }
  128. }
  129. // generateLargeBatchRequest 生成大规模批量保存请求
  130. func generateLargeBatchRequest(tableCount, fieldsPerTable int) dicmanagement.BatchSaveDicTablesRequest {
  131. tables := make([]dicmanagement.DicTableRequest, 0, tableCount)
  132. fields := make([]dicmanagement.DicTableFieldRequest, 0, tableCount*fieldsPerTable)
  133. // 生成表数据
  134. for i := 1; i <= tableCount; i++ {
  135. tableID := fmt.Sprintf("perf_table_%03d", i)
  136. table := dicmanagement.DicTableRequest{
  137. TableID: tableID,
  138. TableType: "实体表",
  139. Name: fmt.Sprintf("性能测试表%03d", i),
  140. Description: fmt.Sprintf("性能测试表%03d的描述", i),
  141. }
  142. tables = append(tables, table)
  143. // 生成字段数据
  144. for j := 1; j <= fieldsPerTable; j++ {
  145. fieldID := fmt.Sprintf("%s.field_%03d", tableID, j)
  146. field := dicmanagement.DicTableFieldRequest{
  147. FieldID: fieldID,
  148. TableID: tableID,
  149. FiledType: "实际字段",
  150. DataType: getDataType(j),
  151. FieldName: fmt.Sprintf("field_%03d", j),
  152. FieldNameCN: fmt.Sprintf("字段%03d", j),
  153. Description: fmt.Sprintf("表%s的第%03d个字段", tableID, j),
  154. }
  155. fields = append(fields, field)
  156. }
  157. }
  158. return dicmanagement.BatchSaveDicTablesRequest{
  159. Tables: tables,
  160. Fields: fields,
  161. }
  162. }
  163. // generateUpdateBatchRequest 生成更新批量请求
  164. func generateUpdateBatchRequest(tableCount, fieldsPerTable int) dicmanagement.BatchSaveDicTablesRequest {
  165. tables := make([]dicmanagement.DicTableRequest, 0, tableCount/2)
  166. fields := make([]dicmanagement.DicTableFieldRequest, 0, (tableCount/2)*fieldsPerTable)
  167. // 只更新前5个表
  168. for i := 1; i <= 5 && i <= tableCount; i++ {
  169. tableID := fmt.Sprintf("perf_table_%03d", i)
  170. table := dicmanagement.DicTableRequest{
  171. TableID: tableID,
  172. TableType: "实体表",
  173. Name: fmt.Sprintf("更新后的性能测试表%03d", i),
  174. Description: fmt.Sprintf("更新后的性能测试表%03d的描述", i),
  175. }
  176. tables = append(tables, table)
  177. // 更新前5个字段,新增5个字段
  178. for j := 1; j <= fieldsPerTable; j++ {
  179. fieldID := fmt.Sprintf("%s.field_%03d", tableID, j)
  180. fieldNameCN := fmt.Sprintf("字段%03d", j)
  181. if j <= 5 {
  182. // 更新前5个字段的描述
  183. fieldNameCN = fmt.Sprintf("更新后的字段%03d", j)
  184. }
  185. field := dicmanagement.DicTableFieldRequest{
  186. FieldID: fieldID,
  187. TableID: tableID,
  188. FiledType: "实际字段",
  189. DataType: getDataType(j),
  190. FieldName: fmt.Sprintf("field_%03d", j),
  191. FieldNameCN: fieldNameCN,
  192. Description: fmt.Sprintf("表%s的第%03d个字段(已更新)", tableID, j),
  193. }
  194. fields = append(fields, field)
  195. }
  196. }
  197. return dicmanagement.BatchSaveDicTablesRequest{
  198. Tables: tables,
  199. Fields: fields,
  200. }
  201. }
  202. // getDataType 根据字段序号返回数据类型
  203. func getDataType(fieldNum int) string {
  204. dataTypes := []string{"字符型", "数值型", "日期型", "布尔型", "文本型"}
  205. return dataTypes[fieldNum%len(dataTypes)]
  206. }
  207. // cleanupPerformanceTestData 清理性能测试数据
  208. func cleanupPerformanceTestData(t *testing.T, tableCount int) {
  209. httpClient := &http.Client{}
  210. for i := 1; i <= tableCount; i++ {
  211. deletePerfTable(t, httpClient, fmt.Sprintf("perf_table_%03d", i))
  212. }
  213. }
  214. // deletePerfTable 删除性能测试表
  215. func deletePerfTable(t *testing.T, client *http.Client, tableID string) {
  216. token := getPerfAuthToken(t)
  217. url := performanceBaseURL + "/api/dic-table/delete/" + tableID
  218. req, err := http.NewRequest("POST", url, nil)
  219. if err != nil {
  220. t.Errorf("创建删除请求失败: %v", err)
  221. return
  222. }
  223. req.Header.Set("Authorization", "Bearer "+token)
  224. req.Header.Set("Content-Type", "application/json")
  225. resp, err := client.Do(req)
  226. if err != nil {
  227. t.Errorf("删除请求失败: %v", err)
  228. return
  229. }
  230. defer resp.Body.Close()
  231. body, err := io.ReadAll(resp.Body)
  232. if err != nil {
  233. t.Errorf("读取响应失败: %v", err)
  234. return
  235. }
  236. var result map[string]interface{}
  237. if err := json.Unmarshal(body, &result); err != nil {
  238. t.Errorf("JSON解析失败: %v", err)
  239. return
  240. }
  241. if success, ok := result["success"].(bool); !ok || !success {
  242. t.Errorf("删除表 %s 失败: %v", tableID, result)
  243. } else {
  244. t.Logf("删除表 %s 成功", tableID)
  245. }
  246. }
  247. // TestBatchPerformanceLarge 测试更大规模的批量保存性能 - 20个表,300个字段
  248. func TestBatchPerformanceLarge(t *testing.T) {
  249. // 跳过长时间测试,除非显式运行
  250. if testing.Short() {
  251. t.Skip("跳过大规模性能测试")
  252. }
  253. tableCount := 20
  254. fieldsPerTable := 15
  255. totalFields := tableCount * fieldsPerTable
  256. t.Run(fmt.Sprintf("BatchCreate%vTables%vFields", tableCount, totalFields), func(t *testing.T) {
  257. testBatchCreateLargeDataset(t, tableCount, fieldsPerTable)
  258. })
  259. t.Run(fmt.Sprintf("BatchUpdate%vTables", tableCount/2), func(t *testing.T) {
  260. testBatchUpdatePartial(t, tableCount, fieldsPerTable)
  261. })
  262. // 清理测试数据
  263. t.Run(fmt.Sprintf("Cleanup%vTables", tableCount), func(t *testing.T) {
  264. cleanupPerformanceTestData(t, tableCount)
  265. })
  266. }