feat(02-04): populate diagram_content_hash during ingestion and fix test stability
- Inject DiagramRepository into ClickHouseExecutionRepository for hash lookup - Replace empty string placeholder with actual SHA-256 diagram hash in insertBatch - Add Surefire/Failsafe forkCount=1 reuseForks=false for classloader isolation - Add failsafe-plugin integration-test/verify goals for IT execution - Create DiagramLinkingIT with positive (hash populated) and negative (empty fallback) cases - Fix flaky awaitility assertions with ignoreExceptions for EmptyResultDataAccess - Increase IngestionSchemaIT timeouts to 30s for reliable batch flush waits - Adjust SearchControllerIT pagination assertion to match correct seed data count Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -90,6 +90,30 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkCount>1</forkCount>
|
||||
<reuseForks>false</reuseForks>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkCount>1</forkCount>
|
||||
<reuseForks>false</reuseForks>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.cameleer3.common.model.ExchangeSnapshot;
|
||||
import com.cameleer3.common.model.ProcessorExecution;
|
||||
import com.cameleer3.common.model.RouteExecution;
|
||||
import com.cameleer3.server.core.detail.RawExecutionRow;
|
||||
import com.cameleer3.server.core.storage.DiagramRepository;
|
||||
import com.cameleer3.server.core.storage.ExecutionRepository;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -53,9 +54,11 @@ public class ClickHouseExecutionRepository implements ExecutionRepository {
|
||||
""";
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final DiagramRepository diagramRepository;
|
||||
|
||||
public ClickHouseExecutionRepository(JdbcTemplate jdbcTemplate) {
|
||||
public ClickHouseExecutionRepository(JdbcTemplate jdbcTemplate, DiagramRepository diagramRepository) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
this.diagramRepository = diagramRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,7 +141,10 @@ public class ClickHouseExecutionRepository implements ExecutionRepository {
|
||||
ps.setObject(col++, inputHeaders); // processor_input_headers
|
||||
ps.setObject(col++, outputHeaders); // processor_output_headers
|
||||
ps.setObject(col++, diagramNodeIds); // processor_diagram_node_ids
|
||||
ps.setString(col++, ""); // diagram_content_hash (wired later)
|
||||
String diagramHash = diagramRepository
|
||||
.findContentHashForRoute(exec.getRouteId(), "")
|
||||
.orElse("");
|
||||
ps.setString(col++, diagramHash); // diagram_content_hash
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -327,12 +327,12 @@ class SearchControllerIT extends AbstractClickHouseIT {
|
||||
|
||||
@Test
|
||||
void pagination_worksCorrectly() throws Exception {
|
||||
// First, get total count of COMPLETED executions (8 from our seed data,
|
||||
// but may include data from other test classes)
|
||||
// First, get total count of COMPLETED executions (7 from our seed data:
|
||||
// exec 1 + execs 5-10; execs 2,4 are FAILED, exec 3 is RUNNING)
|
||||
ResponseEntity<String> countResponse = searchGet("?status=COMPLETED&limit=1");
|
||||
JsonNode countBody = objectMapper.readTree(countResponse.getBody());
|
||||
long totalCompleted = countBody.get("total").asLong();
|
||||
assertThat(totalCompleted).isGreaterThanOrEqualTo(8);
|
||||
assertThat(totalCompleted).isGreaterThanOrEqualTo(7);
|
||||
|
||||
// Now test pagination with offset=2, limit=3
|
||||
ResponseEntity<String> response = searchPost("""
|
||||
|
||||
@@ -91,7 +91,7 @@ class DiagramLinkingIT extends AbstractClickHouseIT {
|
||||
assertThat(execResponse.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
|
||||
// 4. Verify diagram_content_hash is a non-empty SHA-256 hash (64 hex chars)
|
||||
await().atMost(10, SECONDS).untilAsserted(() -> {
|
||||
await().atMost(10, SECONDS).ignoreExceptions().untilAsserted(() -> {
|
||||
String hash = jdbcTemplate.queryForObject(
|
||||
"SELECT diagram_content_hash FROM route_executions WHERE route_id = 'diagram-link-route'",
|
||||
String.class);
|
||||
@@ -140,7 +140,7 @@ class DiagramLinkingIT extends AbstractClickHouseIT {
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
|
||||
// Verify diagram_content_hash is empty string (graceful fallback)
|
||||
await().atMost(10, SECONDS).untilAsserted(() -> {
|
||||
await().atMost(10, SECONDS).ignoreExceptions().untilAsserted(() -> {
|
||||
String hash = jdbcTemplate.queryForObject(
|
||||
"SELECT diagram_content_hash FROM route_executions WHERE route_id = 'no-diagram-route'",
|
||||
String.class);
|
||||
|
||||
@@ -84,7 +84,7 @@ class IngestionSchemaIT extends AbstractClickHouseIT {
|
||||
|
||||
postExecution(json);
|
||||
|
||||
await().atMost(10, SECONDS).untilAsserted(() -> {
|
||||
await().atMost(30, SECONDS).ignoreExceptions().untilAsserted(() -> {
|
||||
// Use individual typed queries to avoid ClickHouse Array cast issues
|
||||
var depths = queryArray(
|
||||
"SELECT processor_depths FROM route_executions WHERE route_id = 'schema-test-tree'");
|
||||
@@ -160,7 +160,7 @@ class IngestionSchemaIT extends AbstractClickHouseIT {
|
||||
|
||||
postExecution(json);
|
||||
|
||||
await().atMost(10, SECONDS).untilAsserted(() -> {
|
||||
await().atMost(30, SECONDS).ignoreExceptions().untilAsserted(() -> {
|
||||
// Bodies should contain all sources
|
||||
String bodies = jdbcTemplate.queryForObject(
|
||||
"SELECT exchange_bodies FROM route_executions WHERE route_id = 'schema-test-bodies'",
|
||||
@@ -206,7 +206,7 @@ class IngestionSchemaIT extends AbstractClickHouseIT {
|
||||
|
||||
postExecution(json);
|
||||
|
||||
await().atMost(10, SECONDS).untilAsserted(() -> {
|
||||
await().atMost(30, SECONDS).ignoreExceptions().untilAsserted(() -> {
|
||||
// Empty but not null
|
||||
String bodies = jdbcTemplate.queryForObject(
|
||||
"SELECT exchange_bodies FROM route_executions WHERE route_id = 'schema-test-null-snap'",
|
||||
|
||||
Reference in New Issue
Block a user