diff --git a/backend-java/src/test/java/com/nanri/aiimage/modules/similarasin/service/SimilarAsinProgressBatchContractReplayTest.java b/backend-java/src/test/java/com/nanri/aiimage/modules/similarasin/service/SimilarAsinProgressBatchContractReplayTest.java new file mode 100644 index 00000000..404352a5 --- /dev/null +++ b/backend-java/src/test/java/com/nanri/aiimage/modules/similarasin/service/SimilarAsinProgressBatchContractReplayTest.java @@ -0,0 +1,81 @@ +package com.nanri.aiimage.modules.similarasin.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * task-214:progress/batch(轻量)响应契约回放(env-gated)。 + * CONTRACT_BASE_URL + CONTRACT_DB_* 设则跑、否则跳过(CI 绿)。 + * 造 SIMILAR_ASIN RUNNING 任务 → POST progress/batch 与 progress/light, + * 断言 items/missingTaskIds 结构、task 轻量字段(id/taskNo/status)、items 文件字段存在。 + */ +class SimilarAsinProgressBatchContractReplayTest { + + private static final long TASK_ID = 9000005L; + private static final ObjectMapper MAPPER = new ObjectMapper(); + + @Test + void progressBatchAndLightContract() throws Exception { + String base = System.getenv("CONTRACT_BASE_URL"); + String dbUrl = System.getenv("CONTRACT_DB_URL"); + String dbUser = System.getenv("CONTRACT_DB_USER"); + String dbPass = System.getenv("CONTRACT_DB_PASSWORD"); + Assumptions.assumeTrue(base != null && dbUrl != null && dbUser != null, "未设 CONTRACT_* 跳过"); + + seed(dbUrl, dbUser, dbPass); + HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build(); + + HttpResponse batch = post(client, base + "/api/similar-asin/tasks/progress/batch?user_id=1", + "{\"taskIds\":[" + TASK_ID + "]}"); + assertEquals(200, batch.statusCode()); + JsonNode b = MAPPER.readTree(batch.body()); + assertTrue(b.path("success").asBoolean(), batch.body()); + JsonNode data = b.path("data"); + assertTrue(data.has("items") && data.has("missingTaskIds"), "batch 应含 items/missingTaskIds"); + assertTrue(data.path("items").isArray() && data.path("items").size() >= 1, "应在跑任务出现在 items"); + JsonNode first = data.path("items").get(0); + JsonNode task = first.path("task"); + assertTrue(task.path("id").asLong() == TASK_ID, "task.id 应对"); + assertTrue(task.has("taskNo") && task.has("status"), "task 轻量字段缺失"); + assertTrue(first.has("items") && first.path("items").isArray(), "task 下应有文件/明细 items"); + + HttpResponse light = post(client, base + "/api/similar-asin/tasks/progress/light?user_id=1", + "{\"taskIds\":[" + TASK_ID + "]}"); + JsonNode l = MAPPER.readTree(light.body()); + assertTrue(l.path("success").asBoolean(), light.body()); + assertTrue(l.path("data").has("items") && l.path("data").has("missingTaskIds"), + "light 应含 items/missingTaskIds"); + } + + private static void seed(String dbUrl, String user, String pass) throws Exception { + try (Connection c = DriverManager.getConnection(dbUrl, user, pass); + Statement s = c.createStatement()) { + s.executeUpdate("INSERT INTO biz_file_task (id,task_no,module_type,task_mode,status,created_at,updated_at,user_id,owner_instance_id) " + + "VALUES (" + TASK_ID + ",'PB-REPLAY-" + TASK_ID + "','SIMILAR_ASIN','workbook','RUNNING',NOW(),NOW(),1,'local-smoke') " + + "ON DUPLICATE KEY UPDATE module_type='SIMILAR_ASIN',status='RUNNING',user_id=1"); + } + } + + private static HttpResponse post(HttpClient client, String url, String body) throws Exception { + return client.send(HttpRequest.newBuilder(URI.create(url)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8)) + .timeout(Duration.ofSeconds(15)).build(), + HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + } +}