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.http.ResponseEntity;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.test.context.ActiveProfiles;
|
|
import javax.sql.DataSource;
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.io.IOException;
|
import java.net.URI;
|
import java.net.http.HttpClient;
|
import java.net.http.HttpRequest;
|
import java.net.http.HttpResponse;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Map;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@ActiveProfiles("test")
|
public class JudgeRealFlowWithCOSTest {
|
|
@LocalServerPort
|
private int port;
|
|
@Autowired
|
private TestRestTemplate restTemplate;
|
|
@Autowired
|
private DataSource dataSource;
|
|
private JdbcTemplate jdbcTemplate;
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
|
@Test
|
void testCompleteJudgeFlowWithRealCOS() throws Exception {
|
jdbcTemplate = new JdbcTemplate(dataSource);
|
|
System.out.println("=== 完整评委创建流程(真实COS上传)===");
|
|
// 步骤1: 获取标签列表
|
System.out.println("\n步骤1: 获取标签列表");
|
List<Map<String, Object>> availableTags = getAvailableTags();
|
assertNotNull(availableTags, "标签列表不应为空");
|
assertFalse(availableTags.isEmpty(), "应该有可用的标签");
|
System.out.println("✅ 获取到 " + availableTags.size() + " 个标签");
|
|
// 步骤2: 保存评委信息
|
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<String, Object> uploadCredentials = getUploadCredentials();
|
assertNotNull(uploadCredentials, "上传凭证不应为空");
|
System.out.println("✅ 获取上传凭证成功");
|
|
// 步骤4: 真实上传头像到COS
|
System.out.println("\n步骤4: 上传头像到COS");
|
String cosPath = performRealCOSUpload(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, cosPath);
|
System.out.println("✅ 数据完整性验证通过");
|
|
System.out.println("\n🎉 完整流程测试成功!文件已真实上传到腾讯云COS!");
|
}
|
|
private List<Map<String, Object>> getAvailableTags() throws Exception {
|
String query = """
|
query {
|
tagsByCategory(category: "major") {
|
id
|
name
|
code
|
}
|
}
|
""";
|
|
Map<String, String> request = Collections.singletonMap("query", query);
|
String response = postGraphQL(request);
|
|
Map<String, Object> 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<String, Object> data = (Map<String, Object>) responseMap.get("data");
|
@SuppressWarnings("unchecked")
|
List<Map<String, Object>> tags = (List<Map<String, Object>>) data.get("tagsByCategory");
|
|
if (tags == null || tags.isEmpty()) {
|
// 如果没有专业标签,获取所有标签
|
String allTagsQuery = """
|
query {
|
tags {
|
id
|
name
|
code
|
}
|
}
|
""";
|
|
Map<String, String> allTagsRequest = Collections.singletonMap("query", allTagsQuery);
|
String allTagsResponse = postGraphQL(allTagsRequest);
|
Map<String, Object> allTagsResponseMap = objectMapper.readValue(allTagsResponse, Map.class);
|
Map<String, Object> allTagsData = (Map<String, Object>) allTagsResponseMap.get("data");
|
|
@SuppressWarnings("unchecked")
|
List<Map<String, Object>> allTags = (List<Map<String, Object>>) allTagsData.get("tags");
|
|
return allTags != null ? allTags.stream().limit(3).toList() : Collections.emptyList();
|
}
|
|
return tags;
|
}
|
|
private String saveJudgeInfo(List<Map<String, Object>> availableTags) throws Exception {
|
// 选择前2个标签作为专业标签
|
List<String> majorIds = availableTags.stream()
|
.limit(2)
|
.map(tag -> String.valueOf(tag.get("id")))
|
.toList();
|
|
String timestamp = String.valueOf(System.currentTimeMillis() % 100000);
|
String mutation = String.format("""
|
mutation {
|
saveJudge(input: {
|
name: "王五"
|
phone: "139%s"
|
gender: 1
|
description: "高级技术专家,拥有丰富的行业经验"
|
majorIds: [%s]
|
}) {
|
id
|
name
|
phone
|
}
|
}
|
""", timestamp, String.join(", ", majorIds));
|
|
Map<String, String> request = Collections.singletonMap("query", mutation);
|
String response = postGraphQL(request);
|
|
Map<String, Object> 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<String, Object> judgeData = (Map<String, Object>)
|
((Map<String, Object>) responseMap.get("data")).get("saveJudge");
|
|
Object idObj = judgeData.get("id");
|
return idObj != null ? idObj.toString() : null;
|
}
|
|
private Map<String, Object> getUploadCredentials() throws Exception {
|
String query = """
|
query {
|
getUploadCredentials {
|
bucket
|
region
|
key
|
presignedUrl
|
expiration
|
}
|
}
|
""";
|
|
Map<String, String> request = Collections.singletonMap("query", query);
|
String response = postGraphQL(request);
|
|
Map<String, Object> responseMap = objectMapper.readValue(response, Map.class);
|
|
if (responseMap.containsKey("errors")) {
|
System.out.println("GraphQL错误: " + responseMap.get("errors"));
|
throw new RuntimeException("获取上传凭证失败: " + responseMap.get("errors"));
|
}
|
|
Map<String, Object> data = (Map<String, Object>) responseMap.get("data");
|
return (Map<String, Object>) data.get("getUploadCredentials");
|
}
|
|
private String performRealCOSUpload(Map<String, Object> credentials) throws Exception {
|
// 查找logo文件
|
File logoFile = findLogoFile();
|
if (logoFile == null || !logoFile.exists()) {
|
throw new RuntimeException("找不到logo文件");
|
}
|
|
// 获取预签名URL
|
String presignedUrl = (String) credentials.get("presignedUrl");
|
String objectKey = (String) credentials.get("key");
|
|
if (presignedUrl == null || presignedUrl.isEmpty()) {
|
throw new RuntimeException("预签名URL为空");
|
}
|
|
// 读取文件内容
|
byte[] fileContent = readFileContent(logoFile);
|
|
// 使用预签名URL上传
|
HttpClient client = HttpClient.newHttpClient();
|
HttpRequest request = HttpRequest.newBuilder()
|
.uri(URI.create(presignedUrl))
|
.header("Content-Type", "image/jpeg")
|
.PUT(HttpRequest.BodyPublishers.ofByteArray(fileContent))
|
.build();
|
|
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
|
if (response.statusCode() == 200 || response.statusCode() == 201 || response.statusCode() == 204) {
|
return objectKey;
|
} else {
|
throw new RuntimeException("COS上传失败,状态码: " + response.statusCode() +
|
", 响应: " + response.body());
|
}
|
}
|
|
private File findLogoFile() {
|
String[] possiblePaths = {
|
"UI/logo.jpg",
|
"../UI/logo.jpg",
|
"../../UI/logo.jpg",
|
"UI/logo.png",
|
"../UI/logo.png",
|
"../../UI/logo.png"
|
};
|
|
for (String path : possiblePaths) {
|
File file = new File(path);
|
if (file.exists()) {
|
return file;
|
}
|
}
|
|
return null;
|
}
|
|
private byte[] readFileContent(File file) throws IOException {
|
try (FileInputStream fis = new FileInputStream(file)) {
|
return fis.readAllBytes();
|
}
|
}
|
|
private String saveMediaRecord(String cosPath, String judgeId) throws Exception {
|
String mutation = String.format("""
|
mutation {
|
saveMedia(input: {
|
name: "logo.jpg"
|
path: "%s"
|
fileSize: 67671
|
fileExt: "jpg"
|
mediaType: 1
|
targetType: 1
|
targetId: %s
|
}) {
|
id
|
name
|
path
|
targetType
|
targetId
|
}
|
}
|
""", cosPath, judgeId);
|
|
Map<String, String> request = Collections.singletonMap("query", mutation);
|
String response = postGraphQL(request);
|
|
Map<String, Object> 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<String, Object> mediaData = (Map<String, Object>)
|
((Map<String, Object>) responseMap.get("data")).get("saveMedia");
|
|
Object idObj = mediaData.get("id");
|
return idObj != null ? idObj.toString() : null;
|
}
|
|
private void verifyDataIntegrity(String judgeId, String mediaId, String cosPath) {
|
// 验证评委基本信息
|
String judgeSql = "SELECT * FROM t_judge WHERE id = ?";
|
Map<String, Object> judge = jdbcTemplate.queryForMap(judgeSql, Long.parseLong(judgeId));
|
|
assertEquals("王五", judge.get("name"));
|
assertTrue(((String) judge.get("phone")).startsWith("139"));
|
assertEquals(1, judge.get("gender"));
|
|
// 验证媒体记录
|
String mediaSql = "SELECT * FROM t_media WHERE id = ?";
|
Map<String, Object> media = jdbcTemplate.queryForMap(mediaSql, Long.parseLong(mediaId));
|
|
assertEquals("logo.jpg", media.get("name"));
|
assertEquals(cosPath, media.get("path")); // 验证真实的COS路径
|
assertEquals(1, media.get("target_type"));
|
assertEquals(Long.parseLong(judgeId), ((Number) media.get("target_id")).longValue());
|
|
// 验证标签关联
|
String tagSql = "SELECT COUNT(*) FROM t_judge_tag WHERE judge_id = ?";
|
Integer tagCount = jdbcTemplate.queryForObject(tagSql, Integer.class, Long.parseLong(judgeId));
|
assertTrue(tagCount >= 2, "应该至少有2个标签关联");
|
|
System.out.println("✅ 评委信息验证通过");
|
System.out.println("✅ 媒体记录验证通过,真实COS路径: " + cosPath);
|
System.out.println("✅ 标签关联验证通过,关联数: " + tagCount);
|
}
|
|
private String postGraphQL(Map<String, String> request) throws Exception {
|
HttpHeaders headers = new HttpHeaders();
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
HttpEntity<Map<String, String>> entity = new HttpEntity<>(request, headers);
|
|
ResponseEntity<String> response = restTemplate.postForEntity(
|
"http://localhost:" + port + "/graphql", entity, String.class);
|
|
if (response.getStatusCode().is2xxSuccessful()) {
|
return response.getBody();
|
} else {
|
throw new RuntimeException("GraphQL request failed with status: " +
|
response.getStatusCode() + " and body: " + response.getBody());
|
}
|
}
|
}
|