package main import ( "bytes" "encoding/json" "io" "net/http" "testing" "git.x2erp.com/qdy/go-svc-configure/internal/service/dicmanagement" ) const ( batchTestBaseURL = "http://localhost:8080" batchTestTable1 = "batch_test_table_001" batchTestTable2 = "batch_test_table_002" batchTestTable3 = "batch_test_table_003" ) // getAuthToken 获取认证token func getAuthToken(t *testing.T) string { // 使用同一包中已存在的函数 userToken, err := getUserAuthToken(t) if err != nil { t.Fatalf("获取用户认证token失败: %v", err) } configToken, err := createConfigToken(t, userToken) if err != nil { t.Fatalf("创建配置token失败: %v", err) } return configToken } // getUserAuthToken 获取用户认证token // TestBatchSaveDicTables 测试批量保存数据库表字典 func TestBatchSaveDicTables(t *testing.T) { // 1. 批量创建多个表 t.Run("BatchCreateTables", testBatchCreateTables) // 2. 验证批量创建的表 t.Run("VerifyBatchCreatedTables", testVerifyBatchCreatedTables) // 3. 批量更新表(部分表更新,部分表新增) t.Run("BatchUpdateTables", testBatchUpdateTables) // 4. 验证批量更新结果 t.Run("VerifyBatchUpdateResults", testVerifyBatchUpdateResults) // 5. 清理测试数据 t.Run("CleanupBatchTestData", testCleanupBatchTestData) } func testBatchCreateTables(t *testing.T) { httpClient := &http.Client{} token := getAuthToken(t) url := batchTestBaseURL + "/api/dic-table/batch-save" // 创建批量保存请求 reqBody := dicmanagement.BatchSaveDicTablesRequest{ Tables: []dicmanagement.DicTableRequest{ { TableID: batchTestTable1, TableType: "实体表", Name: "批量测试表001", Description: "批量测试表001描述", }, { TableID: batchTestTable2, TableType: "视图", Name: "批量测试表002", Description: "批量测试表002描述", }, }, Fields: []dicmanagement.DicTableFieldRequest{ // 表1的字段 { FieldID: batchTestTable1 + ".id", TableID: batchTestTable1, FiledType: "实际字段", DataType: "数值型", FieldName: "id", FieldNameCN: "主键ID", Description: "表1主键字段", }, { FieldID: batchTestTable1 + ".name", TableID: batchTestTable1, FiledType: "实际字段", DataType: "字符型", FieldName: "name", FieldNameCN: "名称", Description: "表1名称字段", }, // 表2的字段 { FieldID: batchTestTable2 + ".code", TableID: batchTestTable2, FiledType: "实际字段", DataType: "字符型", FieldName: "code", FieldNameCN: "编码", Description: "表2编码字段", }, { FieldID: batchTestTable2 + ".value", TableID: batchTestTable2, FiledType: "计算字段", DataType: "数值型", FieldName: "value", FieldNameCN: "数值", Description: "表2数值字段", }, }, } jsonData, err := json.Marshal(reqBody) if err != nil { t.Fatalf("JSON序列化失败: %v", err) } req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) if err != nil { t.Fatalf("创建请求失败: %v", err) } // 使用Bearer Token认证 req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, err := httpClient.Do(req) if err != nil { t.Fatalf("请求失败: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("读取响应失败: %v", err) } var result map[string]interface{} if err := json.Unmarshal(body, &result); err != nil { t.Fatalf("JSON解析失败: %v", err) } if success, ok := result["success"].(bool); !ok || !success { t.Errorf("批量创建表失败: %v", result) } else { t.Logf("批量创建表成功: %s", string(body)) } } func testVerifyBatchCreatedTables(t *testing.T) { httpClient := &http.Client{} // 验证表1 verifyTable(t, httpClient, batchTestTable1, "实体表", "批量测试表001", "批量测试表001描述", 2) // 验证表2 verifyTable(t, httpClient, batchTestTable2, "视图", "批量测试表002", "批量测试表002描述", 2) } func verifyTable(t *testing.T, client *http.Client, tableID, expectedType, expectedName, expectedDesc string, expectedFieldCount int) { token := getAuthToken(t) url := batchTestBaseURL + "/api/dic-table/detail/" + tableID req, err := http.NewRequest("POST", url, nil) if err != nil { t.Errorf("创建请求失败: %v", err) return } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { t.Errorf("请求失败: %v", err) return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("读取响应失败: %v", err) return } var result map[string]interface{} if err := json.Unmarshal(body, &result); err != nil { t.Errorf("JSON解析失败: %v", err) return } if success, ok := result["success"].(bool); !ok || !success { t.Errorf("查询表 %s 详情失败: %v", tableID, result) return } // 验证表信息 if data, ok := result["data"].(map[string]interface{}); ok { if tableData, ok := data["table"].(map[string]interface{}); ok { if actualID, ok := tableData["tableID"].(string); !ok || actualID != tableID { t.Errorf("表ID不匹配: 期望 %s, 实际 %v", tableID, tableData["tableID"]) } if actualType, ok := tableData["tableType"].(string); !ok || actualType != expectedType { t.Errorf("表类型不匹配: 期望 %s, 实际 %v", expectedType, tableData["tableType"]) } if actualName, ok := tableData["name"].(string); !ok || actualName != expectedName { t.Errorf("表名称不匹配: 期望 %s, 实际 %v", expectedName, tableData["name"]) } if actualDesc, ok := tableData["description"].(string); !ok || actualDesc != expectedDesc { t.Errorf("表描述不匹配: 期望 %s, 实际 %v", expectedDesc, tableData["description"]) } } // 验证字段数量 if fields, ok := data["fields"].([]interface{}); ok { if len(fields) != expectedFieldCount { t.Errorf("表 %s 字段数量不匹配: 期望 %d, 实际 %d", tableID, expectedFieldCount, len(fields)) } } else { t.Errorf("表 %s 字段列表不存在", tableID) } } } func testBatchUpdateTables(t *testing.T) { httpClient := &http.Client{} token := getAuthToken(t) url := batchTestBaseURL + "/api/dic-table/batch-save" // 更新请求:更新表1,新增表3,表2保持不变(不在请求中) reqBody := dicmanagement.BatchSaveDicTablesRequest{ Tables: []dicmanagement.DicTableRequest{ { TableID: batchTestTable1, TableType: "实体表", Name: "更新后的批量测试表001", Description: "更新后的批量测试表001描述", }, { TableID: batchTestTable3, TableType: "物化视图", Name: "批量测试表003", Description: "批量测试表003描述", }, }, Fields: []dicmanagement.DicTableFieldRequest{ // 更新表1的字段(新增一个字段,修改一个字段) { FieldID: batchTestTable1 + ".id", TableID: batchTestTable1, FiledType: "实际字段", DataType: "数值型", FieldName: "id", FieldNameCN: "更新后的主键ID", Description: "表1更新后的主键字段", }, { FieldID: batchTestTable1 + ".status", TableID: batchTestTable1, FiledType: "实际字段", DataType: "字符型", FieldName: "status", FieldNameCN: "状态", Description: "表1新增的状态字段", }, // 表3的字段 { FieldID: batchTestTable3 + ".id", TableID: batchTestTable3, FiledType: "实际字段", DataType: "数值型", FieldName: "id", FieldNameCN: "主键ID", Description: "表3主键字段", }, }, } jsonData, err := json.Marshal(reqBody) if err != nil { t.Fatalf("JSON序列化失败: %v", err) } req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) if err != nil { t.Fatalf("创建请求失败: %v", err) } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, err := httpClient.Do(req) if err != nil { t.Fatalf("请求失败: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("读取响应失败: %v", err) } var result map[string]interface{} if err := json.Unmarshal(body, &result); err != nil { t.Fatalf("JSON解析失败: %v", err) } if success, ok := result["success"].(bool); !ok || !success { t.Errorf("批量更新表失败: %v", result) } else { t.Logf("批量更新表成功: %s", string(body)) } } func testVerifyBatchUpdateResults(t *testing.T) { httpClient := &http.Client{} // 验证表1已更新 verifyTable(t, httpClient, batchTestTable1, "实体表", "更新后的批量测试表001", "更新后的批量测试表001描述", 2) // 验证表2保持不变(不在批量更新请求中,应该保持原样) verifyTable(t, httpClient, batchTestTable2, "视图", "批量测试表002", "批量测试表002描述", 2) // 验证表3已创建 verifyTable(t, httpClient, batchTestTable3, "物化视图", "批量测试表003", "批量测试表003描述", 1) // 详细验证表1的字段更新 verifyTableFields(t, httpClient, batchTestTable1) } func verifyTableFields(t *testing.T, client *http.Client, tableID string) { token := getAuthToken(t) url := batchTestBaseURL + "/api/dic-table/detail/" + tableID req, err := http.NewRequest("POST", url, nil) if err != nil { t.Errorf("创建请求失败: %v", err) return } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { t.Errorf("请求失败: %v", err) return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("读取响应失败: %v", err) return } var result map[string]interface{} if err := json.Unmarshal(body, &result); err != nil { t.Errorf("JSON解析失败: %v", err) return } if success, ok := result["success"].(bool); !ok || !success { t.Errorf("查询表 %s 详情失败: %v", tableID, result) return } if data, ok := result["data"].(map[string]interface{}); ok { if fields, ok := data["fields"].([]interface{}); ok { // 检查特定字段是否存在 idFieldFound := false statusFieldFound := false nameFieldFound := false for _, field := range fields { fieldMap := field.(map[string]interface{}) if fieldName, ok := fieldMap["fieldName"].(string); ok { switch fieldName { case "id": idFieldFound = true if fieldNameCN, ok := fieldMap["fieldNameCN"].(string); !ok || fieldNameCN != "更新后的主键ID" { t.Errorf("表 %s id字段中文名称未更新", tableID) } case "status": statusFieldFound = true case "name": nameFieldFound = true } } } if tableID == batchTestTable1 { if !idFieldFound { t.Errorf("表 %s 缺少id字段", tableID) } if !statusFieldFound { t.Errorf("表 %s 缺少status字段", tableID) } if nameFieldFound { t.Errorf("表 %s 不应该有name字段(应该被删除)", tableID) } } } } } func testCleanupBatchTestData(t *testing.T) { httpClient := &http.Client{} // 删除测试表 tables := []string{batchTestTable1, batchTestTable2, batchTestTable3} for _, tableID := range tables { deleteTable(t, httpClient, tableID) } } func deleteTable(t *testing.T, client *http.Client, tableID string) { token := getAuthToken(t) url := batchTestBaseURL + "/api/dic-table/delete/" + tableID req, err := http.NewRequest("POST", url, nil) if err != nil { t.Errorf("创建删除请求失败: %v", err) return } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { t.Errorf("删除请求失败: %v", err) return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("读取响应失败: %v", err) return } var result map[string]interface{} if err := json.Unmarshal(body, &result); err != nil { t.Errorf("JSON解析失败: %v", err) return } if success, ok := result["success"].(bool); !ok || !success { t.Errorf("删除表 %s 失败: %v", tableID, result) } else { t.Logf("删除表 %s 成功", tableID) } } // TestBatchSaveValidation 测试批量保存的验证逻辑 func TestBatchSaveValidation(t *testing.T) { httpClient := &http.Client{} url := batchTestBaseURL + "/api/dic-table/batch-save" testCases := []struct { name string reqBody dicmanagement.BatchSaveDicTablesRequest expectError bool }{ { name: "空表集合", reqBody: dicmanagement.BatchSaveDicTablesRequest{ Tables: []dicmanagement.DicTableRequest{}, Fields: []dicmanagement.DicTableFieldRequest{ { FieldID: "test.id", TableID: "test", FiledType: "实际字段", DataType: "数值型", FieldName: "id", FieldNameCN: "主键", }, }, }, expectError: true, }, { name: "空字段集合", reqBody: dicmanagement.BatchSaveDicTablesRequest{ Tables: []dicmanagement.DicTableRequest{ { TableID: "test", TableType: "实体表", Name: "测试表", }, }, Fields: []dicmanagement.DicTableFieldRequest{}, }, expectError: true, }, { name: "字段引用不存在的表", reqBody: dicmanagement.BatchSaveDicTablesRequest{ Tables: []dicmanagement.DicTableRequest{ { TableID: "table1", TableType: "实体表", Name: "表1", }, }, Fields: []dicmanagement.DicTableFieldRequest{ { FieldID: "table2.id", TableID: "table2", // 这个表不在Tables中 FiledType: "实际字段", DataType: "数值型", FieldName: "id", FieldNameCN: "主键", }, }, }, expectError: true, }, { name: "字段ID格式错误", reqBody: dicmanagement.BatchSaveDicTablesRequest{ Tables: []dicmanagement.DicTableRequest{ { TableID: "test", TableType: "实体表", Name: "测试表", }, }, Fields: []dicmanagement.DicTableFieldRequest{ { FieldID: "wrong_format", // 应该为 test.id TableID: "test", FiledType: "实际字段", DataType: "数值型", FieldName: "id", FieldNameCN: "主键", }, }, }, expectError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { token := getAuthToken(t) jsonData, err := json.Marshal(tc.reqBody) if err != nil { t.Fatalf("JSON序列化失败: %v", err) } req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) if err != nil { t.Fatalf("创建请求失败: %v", err) } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, err := httpClient.Do(req) if err != nil { t.Fatalf("请求失败: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("读取响应失败: %v", err) } var result map[string]interface{} if err := json.Unmarshal(body, &result); err != nil { t.Fatalf("JSON解析失败: %v", err) } success, ok := result["success"].(bool) if !ok { t.Errorf("响应格式错误: %v", result) return } if tc.expectError && success { t.Errorf("期望验证失败但请求成功: %v", result) } else if !tc.expectError && !success { t.Errorf("期望请求成功但验证失败: %v", result) } else { t.Logf("验证测试通过: %s", tc.name) } }) } }