fix(test): rewrite DetailControllerIT seed to ExecutionChunk + REST-driven lookup
POST /api/v1/data/executions is owned by ChunkIngestionController (the legacy ExecutionController path is @ConditionalOnMissingBean(ChunkAccumulator) and never binds). The old RouteExecution-shaped seed was silently parsed as an empty ExecutionChunk and nothing landed in ClickHouse. Rewrote the seed as a single final ExecutionChunk with chunkSeq=0 / final=true and a flat processors[] carrying seq + parentSeq to preserve the 3-level tree (DetailService.buildTree reconstructs the nested shape for the API response). Execution-id lookup now goes through the search REST API filtered by correlationId, per the no-raw-SQL preference. Template for the other Cluster B ITs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,12 @@ class DetailControllerIT extends AbstractPostgresIT {
|
|||||||
/**
|
/**
|
||||||
* Seed a route execution with a 3-level processor tree:
|
* Seed a route execution with a 3-level processor tree:
|
||||||
* root -> [child1, child2], child2 -> [grandchild]
|
* root -> [child1, child2], child2 -> [grandchild]
|
||||||
|
*
|
||||||
|
* Uses the chunked ingestion envelope (POST /api/v1/data/executions →
|
||||||
|
* ChunkIngestionController), which is the only active ingestion path.
|
||||||
|
* The processor tree is flattened into FlatProcessorRecord[] with
|
||||||
|
* seq / parentSeq; DetailService.buildTree reconstructs the nested
|
||||||
|
* shape for the API response.
|
||||||
*/
|
*/
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
void seedTestData() {
|
void seedTestData() {
|
||||||
@@ -48,67 +54,66 @@ class DetailControllerIT extends AbstractPostgresIT {
|
|||||||
|
|
||||||
String json = """
|
String json = """
|
||||||
{
|
{
|
||||||
"routeId": "detail-test-route",
|
|
||||||
"exchangeId": "detail-ex-1",
|
"exchangeId": "detail-ex-1",
|
||||||
|
"applicationId": "test-group",
|
||||||
|
"instanceId": "test-agent-detail-it",
|
||||||
|
"routeId": "detail-test-route",
|
||||||
"correlationId": "detail-corr-1",
|
"correlationId": "detail-corr-1",
|
||||||
"status": "COMPLETED",
|
"status": "COMPLETED",
|
||||||
"startTime": "2026-03-10T10:00:00Z",
|
"startTime": "2026-03-10T10:00:00Z",
|
||||||
"endTime": "2026-03-10T10:00:01Z",
|
"endTime": "2026-03-10T10:00:01Z",
|
||||||
"durationMs": 1000,
|
"durationMs": 1000,
|
||||||
"errorMessage": "",
|
"chunkSeq": 0,
|
||||||
"errorStackTrace": "",
|
"final": true,
|
||||||
"processors": [
|
"processors": [
|
||||||
{
|
{
|
||||||
|
"seq": 1,
|
||||||
"processorId": "root-proc",
|
"processorId": "root-proc",
|
||||||
"processorType": "split",
|
"processorType": "split",
|
||||||
"status": "COMPLETED",
|
"status": "COMPLETED",
|
||||||
"startTime": "2026-03-10T10:00:00Z",
|
"startTime": "2026-03-10T10:00:00Z",
|
||||||
"endTime": "2026-03-10T10:00:01Z",
|
|
||||||
"durationMs": 1000,
|
"durationMs": 1000,
|
||||||
"inputBody": "root-input-body",
|
"inputBody": "root-input-body",
|
||||||
"outputBody": "root-output-body",
|
"outputBody": "root-output-body",
|
||||||
"inputHeaders": {"Content-Type": "application/json"},
|
"inputHeaders": {"Content-Type": "application/json"},
|
||||||
"outputHeaders": {"X-Result": "ok"},
|
"outputHeaders": {"X-Result": "ok"}
|
||||||
"children": [
|
},
|
||||||
{
|
{
|
||||||
"processorId": "child1-proc",
|
"seq": 2,
|
||||||
"processorType": "log",
|
"parentSeq": 1,
|
||||||
"status": "COMPLETED",
|
"parentProcessorId": "root-proc",
|
||||||
"startTime": "2026-03-10T10:00:00.100Z",
|
"processorId": "child1-proc",
|
||||||
"endTime": "2026-03-10T10:00:00.200Z",
|
"processorType": "log",
|
||||||
"durationMs": 100,
|
"status": "COMPLETED",
|
||||||
"inputBody": "child1-input",
|
"startTime": "2026-03-10T10:00:00.100Z",
|
||||||
"outputBody": "child1-output",
|
"durationMs": 100,
|
||||||
"inputHeaders": {},
|
"inputBody": "child1-input",
|
||||||
"outputHeaders": {}
|
"outputBody": "child1-output"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"processorId": "child2-proc",
|
"seq": 3,
|
||||||
"processorType": "bean",
|
"parentSeq": 1,
|
||||||
"status": "COMPLETED",
|
"parentProcessorId": "root-proc",
|
||||||
"startTime": "2026-03-10T10:00:00.200Z",
|
"processorId": "child2-proc",
|
||||||
"endTime": "2026-03-10T10:00:00.800Z",
|
"processorType": "bean",
|
||||||
"durationMs": 600,
|
"status": "COMPLETED",
|
||||||
"inputBody": "child2-input",
|
"startTime": "2026-03-10T10:00:00.200Z",
|
||||||
"outputBody": "child2-output",
|
"durationMs": 600,
|
||||||
"inputHeaders": {},
|
"inputBody": "child2-input",
|
||||||
"outputHeaders": {},
|
"outputBody": "child2-output"
|
||||||
"children": [
|
},
|
||||||
{
|
{
|
||||||
"processorId": "grandchild-proc",
|
"seq": 4,
|
||||||
"processorType": "to",
|
"parentSeq": 3,
|
||||||
"status": "COMPLETED",
|
"parentProcessorId": "child2-proc",
|
||||||
"startTime": "2026-03-10T10:00:00.300Z",
|
"processorId": "grandchild-proc",
|
||||||
"endTime": "2026-03-10T10:00:00.700Z",
|
"processorType": "to",
|
||||||
"durationMs": 400,
|
"status": "COMPLETED",
|
||||||
"inputBody": "gc-input",
|
"startTime": "2026-03-10T10:00:00.300Z",
|
||||||
"outputBody": "gc-output",
|
"durationMs": 400,
|
||||||
"inputHeaders": {"X-GC": "true"},
|
"inputBody": "gc-input",
|
||||||
"outputHeaders": {}
|
"outputBody": "gc-output",
|
||||||
}
|
"inputHeaders": {"X-GC": "true"}
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -116,17 +121,21 @@ class DetailControllerIT extends AbstractPostgresIT {
|
|||||||
|
|
||||||
ingest(json);
|
ingest(json);
|
||||||
|
|
||||||
// Wait for flush and get the execution_id
|
// Wait for async ingestion + flush, then pull the CH-assigned execution_id
|
||||||
await().atMost(10, SECONDS).untilAsserted(() -> {
|
// back through the REST search API. Executions live in ClickHouse; always
|
||||||
Integer count = jdbcTemplate.queryForObject(
|
// drive CH assertions through REST so the test still covers the full
|
||||||
"SELECT count(*) FROM executions WHERE route_id = 'detail-test-route'",
|
// controller→service→store wiring.
|
||||||
Integer.class);
|
await().atMost(20, SECONDS).untilAsserted(() -> {
|
||||||
assertThat(count).isGreaterThanOrEqualTo(1);
|
ResponseEntity<String> r = restTemplate.exchange(
|
||||||
|
"/api/v1/environments/default/executions?correlationId=detail-corr-1",
|
||||||
|
HttpMethod.GET,
|
||||||
|
new HttpEntity<>(securityHelper.authHeadersNoBody(viewerJwt)),
|
||||||
|
String.class);
|
||||||
|
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
JsonNode body = objectMapper.readTree(r.getBody());
|
||||||
|
assertThat(body.get("total").asLong()).isGreaterThanOrEqualTo(1);
|
||||||
|
seededExecutionId = body.get("data").get(0).get("executionId").asText();
|
||||||
});
|
});
|
||||||
|
|
||||||
seededExecutionId = jdbcTemplate.queryForObject(
|
|
||||||
"SELECT execution_id FROM executions WHERE route_id = 'detail-test-route' LIMIT 1",
|
|
||||||
String.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user