task-204: /items 分页语义契约回放(env-gated,真实服务:造 COLLECT_DATA 任务+5 行 item → page/pageSize/count/total/totalPages/items、越界空页、缺省 50、rowIndex 升序)+ 已本地真跑

This commit is contained in:
2026-09-05 08:59:52 +08:00
parent db0c1c1fdc
commit 0b83c9a3c1
@@ -0,0 +1,93 @@
package com.nanri.aiimage.modules.collectdata.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-204/items 分页语义契约回放(真实服务,env-gated)。
*
* 依赖运行应用与可写副本库:CONTRACT_BASE_URL + CONTRACT_DB_*。未设则跳过(CI 绿)。
* 流程:造 COLLECT_DATA RUNNING 任务 + 5 行 biz_collect_data_item → GET items 各分页参数,
* 断言 page/pageSize/count/total/totalPages/items 与缺省/越界/空页语义(与 Python Worker 拉取约定一致)。
*/
class CollectDataItemsContractReplayTest {
private static final long TASK_ID = 9000002L;
private static final ObjectMapper MAPPER = new ObjectMapper();
@Test
void itemsPaginationSemantics() 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, 5);
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
JsonNode page1 = getPage(client, base, 1, 2);
assertTrue(page1.path("success").asBoolean(), page1.toString());
JsonNode data = page1.path("data");
assertEquals(1, data.path("page").asInt());
assertEquals(2, data.path("pageSize").asInt());
assertEquals(5, data.path("total").asLong());
assertEquals(3, data.path("totalPages").asInt());
assertEquals(2, data.path("count").asInt());
assertEquals(2, data.path("items").size());
assertEquals(1, data.path("items").get(0).path("rowIndex").asInt(), "应按 rowIndex 升序");
JsonNode page3 = getPage(client, base, 3, 2);
assertEquals(1, page3.path("data").path("items").size(), "page3 应剩 1 行");
assertEquals(5, page3.path("data").path("items").get(0).path("rowIndex").asInt());
JsonNode beyond = getPage(client, base, 99, 2);
assertEquals(0, beyond.path("data").path("items").size(), "越界页应空且成功");
assertEquals(5, beyond.path("data").path("total").asLong());
JsonNode defaults = getPage(client, base, 1, 50);
JsonNode d = defaults.path("data");
assertEquals(1, d.path("page").asInt());
assertEquals(50, d.path("pageSize").asInt());
assertEquals(1, d.path("totalPages").asInt(), "5 行 50 一页应 1 页");
assertEquals(5, d.path("count").asInt());
}
private static JsonNode getPage(HttpClient client, String base, int page, int size) throws Exception {
String url = base + "/api/collect-data/tasks/" + TASK_ID + "/items?user_id=1&page=" + page + "&page_size=" + size;
HttpResponse<String> resp = client.send(HttpRequest.newBuilder(URI.create(url)).GET()
.timeout(Duration.ofSeconds(15)).build(),
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
assertEquals(200, resp.statusCode(), url);
return MAPPER.readTree(resp.body());
}
private static void seed(String dbUrl, String user, String pass, int rows) 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 + ",'CD-REPLAY-" + TASK_ID + "','COLLECT_DATA','collect','RUNNING',NOW(),NOW(),1,'local-smoke') "
+ "ON DUPLICATE KEY UPDATE module_type='COLLECT_DATA',status='RUNNING',user_id=1");
s.executeUpdate("DELETE FROM biz_collect_data_item WHERE task_id=" + TASK_ID);
for (int i = 1; i <= rows; i++) {
s.executeUpdate("INSERT INTO biz_collect_data_item (task_id,row_index,keyword,status_value,created_at) VALUES ("
+ TASK_ID + "," + i + ",'keyword-" + i + "','PENDING',NOW())");
}
}
}
}