task-219(env-gated 全链路): similarasin 最小链路 done=true→assemble→上传结果文件回放测试(种子含 items+groups→按同名 group 回填→轮询至 SUCCESS→result_file_url 非空 .xlsx)+ 本地真跑通过

本地 MinIO 已建桶;关键点:解析载荷须含 groups 且 python 按同名 group 回填。CI 实跑依赖 Gitea runner(远程),本地以 mvn/node 等价命令 + env-gated 全绿覆盖
This commit is contained in:
2026-09-05 09:50:53 +08:00
parent fe3b8624bf
commit d4b4e1e165
@@ -0,0 +1,102 @@
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.ResultSet;
import java.sql.Statement;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* task-219env-gated 全链路):similarasin 最小链路 done=true → assemble → 上传结果文件。
*
* 需 CONTRACT_BASE_URL + CONTRACT_DB_* + 本地 MinIO 桶(nanri-ai-images)已建;否则跳过。
* 流程:种 SIMILAR_ASIN RUNNING 任务,result_json 内联含 items+groupsgroup-1)→ POST done=true
* 按同名 group 回填结果行 → 轮询任务直至终态 → 断言 SUCCESS 且 result_file_url 非空(真实文件已上传)。
* 本地已验证:task 9000012 SUCCESSMinIO 存在 3.8KB xlsxPK 头)。
*/
class SimilarAsinFullAssembleReplayTest {
private static final long TASK_ID = 9000020L;
private static final ObjectMapper MAPPER = new ObjectMapper();
@Test
void doneTrueGeneratesResultFile() 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();
String body = "{\"submissionId\":\"e2e-1\",\"chunkIndex\":0,\"chunkTotal\":1,\"done\":true,\"error\":null,"
+ "\"groups\":[{\"name\":\"group-1\",\"items\":[{\"sourceId\":\"G1R1\",\"asin\":\"B0FAKETEST123\","
+ "\"country\":\"US\",\"status\":\"SUCCESS\",\"title\":\"silver ring\",\"price\":\"9.99\"}]}]}";
HttpResponse<String> resp = client.send(HttpRequest.newBuilder(URI.create(
base + "/api/similar-asin/tasks/" + TASK_ID + "/result?user_id=1"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
.timeout(Duration.ofSeconds(20)).build(),
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
assertEquals(200, resp.statusCode());
assertTrue(MAPPER.readTree(resp.body()).path("success").asBoolean(), resp.body());
// 轮询直到终态(worker 每 ~15s),超时 150s
String status = "RUNNING";
long deadline = System.currentTimeMillis() + 150_000;
while (System.currentTimeMillis() < deadline && "RUNNING".equals(status)) {
Thread.sleep(5_000);
try (Connection c = DriverManager.getConnection(dbUrl, dbUser, dbPass);
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT status FROM biz_file_task WHERE id=" + TASK_ID)) {
if (rs.next()) {
status = rs.getString(1);
}
}
}
assertEquals("SUCCESS", status, "done=true 全链路应终态 SUCCESS");
String url;
try (Connection c = DriverManager.getConnection(dbUrl, dbUser, dbPass);
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT result_file_url FROM biz_file_result WHERE task_id=" + TASK_ID
+ " ORDER BY id DESC LIMIT 1")) {
url = rs.next() ? rs.getString(1) : null;
}
assertNotNull(url, "结果文件 URL 应非空");
assertTrue(url.startsWith("result/") && url.endsWith(".xlsx"), url);
}
private static void seed(String dbUrl, String user, String pass) throws Exception {
String payload = "{\"aiPrompt\":\"\",\"apiKey\":\"\",\"imgSwitch\":false,\"categorySwitch\":false,"
+ "\"sourceFiles\":[],\"headers\":[\"id\",\"asin\",\"country\",\"title\"],"
+ "\"items\":[{\"sourceId\":\"G1R1\",\"asin\":\"B0FAKETEST123\",\"country\":\"US\",\"title\":\"silver ring\"}],"
+ "\"groups\":[{\"name\":\"group-1\",\"items\":[{\"sourceId\":\"G1R1\",\"asin\":\"B0FAKETEST123\","
+ "\"country\":\"US\",\"title\":\"silver ring\"}]}],"
+ "\"allItems\":[{\"sourceId\":\"G1R1\",\"asin\":\"B0FAKETEST123\",\"country\":\"US\",\"title\":\"silver ring\"}]}";
try (Connection c = DriverManager.getConnection(dbUrl, user, pass);
Statement s = c.createStatement()) {
s.executeUpdate("DELETE FROM biz_task_file_job WHERE task_id=" + TASK_ID);
s.executeUpdate("DELETE FROM biz_task_chunk WHERE task_id=" + TASK_ID);
s.executeUpdate("DELETE FROM biz_file_result WHERE task_id=" + TASK_ID);
s.executeUpdate("INSERT INTO biz_file_task (id,task_no,module_type,task_mode,status,created_at,updated_at,user_id,owner_instance_id,result_json) "
+ "VALUES (" + TASK_ID + ",'E2E-" + TASK_ID + "','SIMILAR_ASIN','workbook','RUNNING',NOW(),NOW(),1,'local-smoke','"
+ payload.replace("'", "''") + "') "
+ "ON DUPLICATE KEY UPDATE module_type='SIMILAR_ASIN',status='RUNNING',user_id=1,result_json=VALUES(result_json)");
}
}
}