lrj
2 天以前 c61d4fe27c97d2ecc907756aa571a4ef14a7b9b6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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.test.context.ActiveProfiles;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.Collections;
import java.util.Map;
 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public class JudgeRealCOSUploadTest {
 
    @LocalServerPort
    private int port;
 
    @Autowired
    private TestRestTemplate restTemplate;
 
    private final ObjectMapper objectMapper = new ObjectMapper();
 
    @Test
    void testRealCOSUpload() throws Exception {
        System.out.println("=== 真实COS上传测试 ===");
        
        // 步骤1: 获取真实的COS上传凭证
        System.out.println("\n步骤1: 获取COS上传凭证");
        Map<String, Object> credentials = getRealUploadCredentials();
        
        if (credentials == null || credentials.isEmpty()) {
            System.out.println("❌ 无法获取上传凭证,跳过真实上传测试");
            return;
        }
        
        System.out.println("✅ 获取到上传凭证:");
        credentials.forEach((key, value) -> {
            if (key.contains("secret") || key.contains("token")) {
                System.out.println("  " + key + ": " + maskSensitiveInfo(value.toString()));
            } else {
                System.out.println("  " + key + ": " + value);
            }
        });
        
        // 步骤2: 准备上传文件
        System.out.println("\n步骤2: 准备上传文件");
        File logoFile = findLogoFile();
        if (logoFile == null || !logoFile.exists()) {
            System.out.println("❌ 找不到logo.png文件,跳过上传测试");
            return;
        }
        
        System.out.println("✅ 找到logo文件: " + logoFile.getAbsolutePath());
        System.out.println("  文件大小: " + logoFile.length() + " bytes");
        
        // 步骤3: 执行真实的COS上传
        System.out.println("\n步骤3: 执行COS上传");
        String uploadResult = performRealCOSUpload(credentials, logoFile);
        
        if (uploadResult != null) {
            System.out.println("✅ 文件上传成功!");
            System.out.println("  上传路径: " + uploadResult);
        } else {
            System.out.println("❌ 文件上传失败!");
        }
    }
    
    /**
     * 获取真实的COS上传凭证
     */
    private Map<String, Object> getRealUploadCredentials() throws Exception {
        String query = """
            query {
                getUploadCredentials {
                    bucket
                    region
                    key
                    presignedUrl
                    expiration
                }
            }
            """;
        
        try {
            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"));
                return null;
            }
            
            Map<String, Object> data = (Map<String, Object>) responseMap.get("data");
            return (Map<String, Object>) data.get("getUploadCredentials");
            
        } catch (Exception e) {
            System.out.println("❌ 获取上传凭证失败: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 查找logo文件
     */
    private File findLogoFile() {
        // 尝试多个可能的路径
        String[] possiblePaths = {
            "UI/logo.png",
            "../UI/logo.png",
            "../../UI/logo.png",
            "UI/logo.jpg",
            "../UI/logo.jpg",
            "../../UI/logo.jpg"
        };
        
        for (String path : possiblePaths) {
            File file = new File(path);
            if (file.exists()) {
                return file;
            }
        }
        
        return null;
    }
    
    /**
     * 执行真实的COS上传(使用预签名URL)
     */
    private String performRealCOSUpload(Map<String, Object> credentials, File file) {
        try {
            // 获取预签名URL
            String presignedUrl = (String) credentials.get("presignedUrl");
            String objectKey = (String) credentials.get("key");
            
            if (presignedUrl == null || presignedUrl.isEmpty()) {
                System.out.println("❌ 预签名URL为空");
                return null;
            }
            
            System.out.println("预签名URL: " + presignedUrl);
            System.out.println("对象键: " + objectKey);
            
            // 读取文件内容
            byte[] fileContent = readFileContent(file);
            System.out.println("文件内容大小: " + fileContent.length + " bytes");
            
            // 使用预签名URL直接上传,不需要额外的认证头部
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(presignedUrl))
                .header("Content-Type", getContentType(file))
                .PUT(HttpRequest.BodyPublishers.ofByteArray(fileContent))
                .build();
            
            // 发送请求
            System.out.println("发送上传请求...");
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            
            System.out.println("响应状态码: " + response.statusCode());
            System.out.println("响应头: " + response.headers().map());
            if (!response.body().isEmpty()) {
                System.out.println("响应体: " + response.body());
            }
            
            if (response.statusCode() == 200 || response.statusCode() == 201 || response.statusCode() == 204) {
                System.out.println("✅ 文件上传成功!");
                return objectKey;
            } else {
                System.out.println("❌ 上传失败,状态码: " + response.statusCode());
                if (!response.body().isEmpty()) {
                    System.out.println("❌ 响应内容: " + response.body());
                }
                return null;
            }
            
        } catch (Exception e) {
            System.out.println("❌ COS上传异常: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 读取文件内容
     */
    private byte[] readFileContent(File file) throws IOException {
        try (FileInputStream fis = new FileInputStream(file)) {
            return fis.readAllBytes();
        }
    }
    
    /**
     * 获取文件内容类型
     */
    private String getContentType(File file) {
        String fileName = file.getName().toLowerCase();
        if (fileName.endsWith(".png")) {
            return "image/png";
        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
            return "image/jpeg";
        } else {
            return "application/octet-stream";
        }
    }
    
 
    
    /**
     * 发送GraphQL请求
     */
    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());
        }
    }
    
    /**
     * 掩码敏感信息
     */
    private String maskSensitiveInfo(String info) {
        if (info == null || info.length() <= 8) {
            return "****";
        }
        return info.substring(0, 4) + "****" + info.substring(info.length() - 4);
    }
}