package com.rongyichuang.judge; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; import java.util.Collections; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; /** * 评委模块正确流程测试 * 按照正确的业务流程: * 1. 获取标签列表 * 2. 保存评委信息(包含majorIds) * 3. 获取COS上传凭证 * 4. 上传头像到COS * 5. 保存媒体记录(关联到评委) * 6. 验证数据完整性 */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class JudgeCorrectFlowTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Autowired private DataSource dataSource; private JdbcTemplate jdbcTemplate; private ObjectMapper objectMapper = new ObjectMapper(); @Test void testCorrectJudgeCreationFlow() throws Exception { jdbcTemplate = new JdbcTemplate(dataSource); System.out.println("=== 开始正确的评委创建流程测试 ==="); // 步骤1: 获取可用标签列表 System.out.println("\n步骤1: 获取标签列表"); List> availableTags = getAvailableTags(); assertTrue(availableTags.size() > 0, "应该有可用的标签"); System.out.println("✓ 获取到 " + availableTags.size() + " 个标签"); // 步骤2: 保存评委信息(包含majorIds) System.out.println("\n步骤2: 保存评委信息"); String judgeId = saveJudgeInfo(availableTags); assertNotNull(judgeId, "评委ID不应为空"); System.out.println("✓ 评委保存成功,ID: " + judgeId); // 步骤3: 获取COS上传凭证(模拟) System.out.println("\n步骤3: 获取COS上传凭证"); Map uploadCredentials = getUploadCredentials(); assertNotNull(uploadCredentials, "上传凭证不应为空"); System.out.println("✓ 获取上传凭证成功"); // 步骤4: 模拟上传头像到COS System.out.println("\n步骤4: 上传头像到COS"); String cosPath = simulateUploadToCOS(uploadCredentials); assertNotNull(cosPath, "COS路径不应为空"); System.out.println("✓ 头像上传到COS成功,路径: " + cosPath); // 步骤5: 保存媒体记录(关联到评委) System.out.println("\n步骤5: 保存媒体记录"); String mediaId = saveMediaRecord(cosPath, judgeId); assertNotNull(mediaId, "媒体ID不应为空"); System.out.println("✓ 媒体记录保存成功,ID: " + mediaId); // 步骤6: 验证数据完整性 System.out.println("\n步骤6: 验证数据完整性"); verifyDataIntegrity(judgeId, mediaId); System.out.println("✓ 数据完整性验证通过"); System.out.println("\n=== 正确流程测试成功 ==="); printTestSummary(judgeId, mediaId); } /** * 步骤1: 获取可用标签列表 */ private List> getAvailableTags() throws Exception { String query = """ query { tagsByCategory(category: "major") { id name code } } """; Map request = Collections.singletonMap("query", query); String response = postGraphQL(request); Map responseMap = objectMapper.readValue(response, Map.class); // 检查是否有错误 if (responseMap.containsKey("errors")) { System.out.println("GraphQL错误: " + responseMap.get("errors")); throw new RuntimeException("GraphQL查询失败: " + responseMap.get("errors")); } Map data = (Map) responseMap.get("data"); @SuppressWarnings("unchecked") List> tags = (List>) data.get("tagsByCategory"); if (tags == null || tags.isEmpty()) { // 如果没有专业标签,获取所有标签 String allTagsQuery = """ query { tags { id name code } } """; Map allTagsRequest = Collections.singletonMap("query", allTagsQuery); String allTagsResponse = postGraphQL(allTagsRequest); Map allTagsResponseMap = objectMapper.readValue(allTagsResponse, Map.class); Map allTagsData = (Map) allTagsResponseMap.get("data"); @SuppressWarnings("unchecked") List> allTags = (List>) allTagsData.get("tags"); return allTags != null ? allTags.stream().limit(3).toList() : Collections.emptyList(); } return tags; } /** * 步骤2: 保存评委信息(包含majorIds) */ private String saveJudgeInfo(List> availableTags) throws Exception { // 选择前2个标签作为专业标签 List selectedTagIds = availableTags.stream() .limit(2) .map(tag -> tag.get("id").toString()) .toList(); String tagIdsStr = "[" + String.join(", ", selectedTagIds) + "]"; // 使用时间戳生成唯一电话号码 String uniquePhone = "139" + String.valueOf(System.currentTimeMillis()).substring(5); String mutation = String.format(""" mutation { saveJudge(input: { name: "王五" phone: "%s" gender: 1 description: "高级技术专家,专注于云计算和大数据领域。" majorIds: %s }) { id name phone gender description specialties { id name code } } } """, uniquePhone, tagIdsStr); Map request = Collections.singletonMap("query", mutation); String response = postGraphQL(request); Map responseMap = objectMapper.readValue(response, Map.class); // 检查是否有错误 if (responseMap.containsKey("errors")) { System.out.println("GraphQL错误: " + responseMap.get("errors")); throw new RuntimeException("保存评委失败: " + responseMap.get("errors")); } @SuppressWarnings("unchecked") Map judgeData = (Map) ((Map) responseMap.get("data")).get("saveJudge"); Object idObj = judgeData.get("id"); return idObj != null ? idObj.toString() : null; } /** * 步骤3: 获取COS上传凭证(模拟) */ private Map getUploadCredentials() throws Exception { // 这里应该调用实际的获取上传凭证的GraphQL查询 // 目前模拟返回凭证信息 return Map.of( "secretId", "mock_secret_id", "secretKey", "mock_secret_key", "sessionToken", "mock_session_token", "bucket", "ryc-avatars", "region", "ap-beijing", "expiredTime", System.currentTimeMillis() + 3600000 ); } /** * 步骤4: 模拟上传头像到COS */ private String simulateUploadToCOS(Map credentials) { // 模拟上传logo.jpg到腾讯云COS // 实际应用中这里会使用腾讯云SDK上传文件 String timestamp = String.valueOf(System.currentTimeMillis()); return "avatars/judge_" + timestamp + "_logo.jpg"; } /** * 步骤5: 保存媒体记录(关联到评委) */ private String saveMediaRecord(String cosPath, String judgeId) throws Exception { String mutation = String.format(""" mutation { saveMedia(input: { name: "logo.jpg" path: "%s" fileSize: 2048 fileExt: "jpg" mediaType: 1 targetType: 1 targetId: %s }) { id name path targetType targetId } } """, cosPath, judgeId); Map request = Collections.singletonMap("query", mutation); String response = postGraphQL(request); Map responseMap = objectMapper.readValue(response, Map.class); // 检查是否有错误 if (responseMap.containsKey("errors")) { System.out.println("GraphQL错误: " + responseMap.get("errors")); throw new RuntimeException("保存媒体记录失败: " + responseMap.get("errors")); } @SuppressWarnings("unchecked") Map mediaData = (Map) ((Map) responseMap.get("data")).get("saveMedia"); Object idObj = mediaData.get("id"); return idObj != null ? idObj.toString() : null; } /** * 步骤6: 验证数据完整性 */ private void verifyDataIntegrity(String judgeId, String mediaId) { // 验证评委基本信息 String judgeSql = "SELECT * FROM t_judge WHERE id = ? AND state = 1"; Map judge = jdbcTemplate.queryForMap(judgeSql, Long.parseLong(judgeId)); assertEquals("王五", judge.get("name")); assertTrue(((String) judge.get("phone")).startsWith("139")); // 验证电话号码格式 assertEquals(1, judge.get("gender")); // 男性 assertTrue(((String) judge.get("description")).contains("高级技术专家")); // 验证媒体记录 String mediaSql = "SELECT * FROM t_media WHERE id = ? AND state = 1"; Map media = jdbcTemplate.queryForMap(mediaSql, Long.parseLong(mediaId)); assertEquals("logo.jpg", media.get("name")); assertEquals(1, media.get("target_type")); // 评委头像 assertEquals(Long.parseLong(judgeId), ((Number) media.get("target_id")).longValue()); assertTrue(((String) media.get("path")).contains("avatars/")); assertTrue(((String) media.get("path")).contains("logo.jpg")); // 验证标签关联 String tagSql = "SELECT COUNT(*) FROM t_judge_tag WHERE judge_id = ? AND state = 1"; Integer tagCount = jdbcTemplate.queryForObject(tagSql, Integer.class, Long.parseLong(judgeId)); assertTrue(tagCount >= 2, "应该至少有2个标签关联"); System.out.println(" ✓ 评委基本信息正确"); System.out.println(" ✓ 头像媒体记录正确,关联到评委ID: " + judgeId); System.out.println(" ✓ 标签关联记录正确 (" + tagCount + "个)"); } /** * 打印测试总结 */ private void printTestSummary(String judgeId, String mediaId) { System.out.println("\n=== 测试总结 ==="); System.out.println("评委ID: " + judgeId); System.out.println("媒体ID: " + mediaId); // 查询最终数据 String judgeSql = "SELECT * FROM t_judge WHERE id = ? AND state = 1"; Map judge = jdbcTemplate.queryForMap(judgeSql, Long.parseLong(judgeId)); String mediaSql = "SELECT * FROM t_media WHERE id = ? AND state = 1"; Map media = jdbcTemplate.queryForMap(mediaSql, Long.parseLong(mediaId)); System.out.println("评委姓名: " + judge.get("name")); System.out.println("联系电话: " + judge.get("phone")); System.out.println("性别: " + (Integer.valueOf(1).equals(judge.get("gender")) ? "男" : "女")); System.out.println("头像路径: " + media.get("path")); System.out.println("媒体关联: target_type=" + media.get("target_type") + ", target_id=" + media.get("target_id")); System.out.println("\n✅ 正确的业务流程测试成功!"); System.out.println("✅ 1. 先保存评委信息 ✓"); System.out.println("✅ 2. 再上传头像到COS ✓"); System.out.println("✅ 3. 最后保存媒体记录并关联评委 ✓"); } /** * 发送GraphQL请求 */ private String postGraphQL(Map requestBody) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity> entity = new HttpEntity<>(requestBody, headers); String url = "http://localhost:" + port + "/graphql"; var response = restTemplate.postForEntity(url, entity, String.class); if (response.getStatusCode().is2xxSuccessful() && response.hasBody()) { return response.getBody(); } else { throw new RuntimeException("GraphQL request failed with status: " + response.getStatusCode() + " and body: " + response.getBody()); } } }