116 lines
4.8 KiB
Java
116 lines
4.8 KiB
Java
package com.nanri.aiimage.config;
|
||
|
||
import com.fasterxml.jackson.databind.JsonNode;
|
||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||
import org.junit.jupiter.api.Test;
|
||
|
||
import java.io.IOException;
|
||
import java.nio.file.Files;
|
||
import java.nio.file.Path;
|
||
import java.util.ArrayList;
|
||
import java.util.List;
|
||
import java.util.Set;
|
||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||
|
||
/**
|
||
* task-202:Python-contract 夹具准备契约。
|
||
* 校验 python-contract/*.json 存在、为合法 JSON、顶层字段与真实 DTO 对齐、已脱敏(无真实凭据)、
|
||
* 可复现;字段来源与脱敏口径见同目录 README.md。
|
||
*/
|
||
class PythonContractFixtureTest {
|
||
|
||
private static final Path DIR = Path.of(System.getProperty("user.dir"),
|
||
"src/test/resources/python-contract");
|
||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||
|
||
private JsonNode json(String name) throws IOException {
|
||
return MAPPER.readTree(Files.readAllBytes(DIR.resolve(name)));
|
||
}
|
||
|
||
private static Set<String> keys(JsonNode node) {
|
||
List<String> names = new ArrayList<>();
|
||
node.fieldNames().forEachRemaining(names::add);
|
||
return Set.copyOf(names);
|
||
}
|
||
|
||
@Test
|
||
void fixtureResultRequestExists() throws IOException {
|
||
JsonNode n = json("result.request.json");
|
||
assertEquals("sim-20260905-0001", n.path("submissionId").asText());
|
||
}
|
||
|
||
@Test
|
||
void fixtureItemsExists() throws IOException {
|
||
JsonNode n = json("items.response.json");
|
||
assertTrue(n.path("items").isArray() && n.path("items").size() >= 1);
|
||
}
|
||
|
||
@Test
|
||
void fixtureParsedPayloadExists() throws IOException {
|
||
JsonNode n = json("parsed_payload.response.json");
|
||
assertTrue(n.has("allItems") && n.has("groups") && n.has("items"));
|
||
}
|
||
|
||
@Test
|
||
void fixtureHeartbeatExists() throws IOException {
|
||
JsonNode req = json("heartbeat.request.json");
|
||
JsonNode resp = json("heartbeat.response.json");
|
||
assertTrue(req.has("moduleType") && req.has("phase"));
|
||
assertTrue(resp.has("alive") && resp.has("status"));
|
||
}
|
||
|
||
@Test
|
||
void fixtureSanitizedNoRealCredentials() throws IOException {
|
||
String all = String.join("\n", List.of(
|
||
Files.readString(DIR.resolve("parsed_payload.response.json")),
|
||
Files.readString(DIR.resolve("result.request.json"))));
|
||
assertFalse(all.contains("WTFrb"), "不得出现真实 DB/内部凭据");
|
||
assertFalse(all.toLowerCase().contains("bearer "), "不得出现真实 token");
|
||
JsonNode parsed = json("parsed_payload.response.json");
|
||
assertEquals("<redacted>", parsed.path("apiKey").asText(), "apiKey 必须占位");
|
||
assertFalse(parsed.path("aiPrompt").asText().toLowerCase().contains("真实"),
|
||
"aiPrompt 不得含真实内容");
|
||
}
|
||
|
||
@Test
|
||
void fixtureShapeValidJson() throws IOException {
|
||
for (String name : List.of("heartbeat.request.json", "heartbeat.response.json",
|
||
"items.response.json", "result.request.json", "parsed_payload.response.json")) {
|
||
JsonNode n = json(name);
|
||
assertTrue(n.isContainerNode(), name + " 应为 JSON 对象/数组");
|
||
}
|
||
}
|
||
|
||
@Test
|
||
void fixtureFieldsDocumentedByReadme() throws IOException {
|
||
String readme = Files.readString(DIR.resolve("README.md"));
|
||
assertTrue(readme.contains("TaskHeartbeatRequest") && readme.contains("CollectDataItemsPageVo")
|
||
&& readme.contains("SimilarAsinSubmitResultRequest")
|
||
&& readme.contains("SimilarAsinParsedPayloadDto"), "README 应说明字段来源");
|
||
assertTrue(readme.contains("脱敏"), "README 应说明脱敏");
|
||
}
|
||
|
||
@Test
|
||
void fixtureHeartbeatTopKeysMatchDto() throws IOException {
|
||
assertEquals(Set.of("moduleType", "phase", "current", "total", "collectStage",
|
||
"currentKeyword", "searchCurrentPage", "searchTotalPages",
|
||
"detailProcessedAsins", "detailTotalAsins"),
|
||
keys(json("heartbeat.request.json")), "心跳请求顶层字段应与 TaskHeartbeatRequest 对齐");
|
||
assertEquals(Set.of("alive", "status", "moduleType", "message"),
|
||
keys(json("heartbeat.response.json")), "心跳响应应与 TaskHeartbeatVo 对齐");
|
||
}
|
||
|
||
@Test
|
||
void fixtureReproducibleStable() throws IOException {
|
||
for (String name : List.of("heartbeat.request.json", "items.response.json",
|
||
"result.request.json", "parsed_payload.response.json")) {
|
||
String a = Files.readString(DIR.resolve(name));
|
||
String b = Files.readString(DIR.resolve(name));
|
||
assertEquals(a, b, name + " 应可复现");
|
||
}
|
||
}
|
||
}
|