feat: add server-side ExecutionChunk and FlatProcessorRecord DTOs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,11 @@
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.cameleer3.server.core.storage.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Chunk document: exchange envelope + list of FlatProcessorRecords.
|
||||
* Mirrors cameleer3-common ExecutionChunk — replace with common lib import when available.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record ExecutionChunk(
|
||||
String exchangeId,
|
||||
String applicationName,
|
||||
String agentId,
|
||||
String routeId,
|
||||
String correlationId,
|
||||
String status,
|
||||
Instant startTime,
|
||||
Instant endTime,
|
||||
Long durationMs,
|
||||
String engineLevel,
|
||||
String errorMessage,
|
||||
String errorStackTrace,
|
||||
String errorType,
|
||||
String errorCategory,
|
||||
String rootCauseType,
|
||||
String rootCauseMessage,
|
||||
Map<String, String> attributes,
|
||||
String traceId,
|
||||
String spanId,
|
||||
String originalExchangeId,
|
||||
String replayExchangeId,
|
||||
int chunkSeq,
|
||||
@JsonProperty("final") boolean isFinal,
|
||||
List<FlatProcessorRecord> processors
|
||||
) {}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.cameleer3.server.core.storage.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Flat processor execution record with seq/parentSeq for tree reconstruction.
|
||||
* Mirrors cameleer3-common FlatProcessorRecord — replace with common lib import when available.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public record FlatProcessorRecord(
|
||||
int seq,
|
||||
Integer parentSeq,
|
||||
String parentProcessorId,
|
||||
String processorId,
|
||||
String processorType,
|
||||
Integer iteration,
|
||||
Integer iterationSize,
|
||||
String status,
|
||||
Instant startTime,
|
||||
long durationMs,
|
||||
String resolvedEndpointUri,
|
||||
String inputBody,
|
||||
String outputBody,
|
||||
Map<String, String> inputHeaders,
|
||||
Map<String, String> outputHeaders,
|
||||
String errorMessage,
|
||||
String errorStackTrace,
|
||||
String errorType,
|
||||
String errorCategory,
|
||||
String rootCauseType,
|
||||
String rootCauseMessage,
|
||||
Map<String, String> attributes,
|
||||
String circuitBreakerState,
|
||||
Boolean fallbackTriggered,
|
||||
Boolean filterMatched,
|
||||
Boolean duplicateMessage
|
||||
) {}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.cameleer3.server.core.storage.model;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ExecutionChunkDeserializationTest {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||
|
||||
@Test
|
||||
void roundTrip_fullChunk() throws Exception {
|
||||
ExecutionChunk chunk = new ExecutionChunk(
|
||||
"ex-1", "order-service", "pod-1", "order-route",
|
||||
"corr-1", "COMPLETED",
|
||||
Instant.parse("2026-03-31T10:00:00Z"),
|
||||
Instant.parse("2026-03-31T10:00:01Z"), 1000L,
|
||||
"REGULAR",
|
||||
null, null, null, null, null, null,
|
||||
Map.of("orderId", "ORD-1"),
|
||||
"trace-1", "span-1", null, null,
|
||||
2, true,
|
||||
List.of(new FlatProcessorRecord(
|
||||
1, null, null, "log1", "log",
|
||||
null, null, "COMPLETED",
|
||||
Instant.parse("2026-03-31T10:00:00.100Z"), 5L,
|
||||
null, "body", null, null, null,
|
||||
null, null, null, null, null, null,
|
||||
null, null, null, null, null)));
|
||||
|
||||
String json = MAPPER.writeValueAsString(chunk);
|
||||
ExecutionChunk deserialized = MAPPER.readValue(json, ExecutionChunk.class);
|
||||
|
||||
assertThat(deserialized.exchangeId()).isEqualTo("ex-1");
|
||||
assertThat(deserialized.isFinal()).isTrue();
|
||||
assertThat(deserialized.chunkSeq()).isEqualTo(2);
|
||||
assertThat(deserialized.processors()).hasSize(1);
|
||||
assertThat(deserialized.processors().get(0).seq()).isEqualTo(1);
|
||||
assertThat(deserialized.processors().get(0).processorId()).isEqualTo("log1");
|
||||
assertThat(deserialized.attributes()).containsEntry("orderId", "ORD-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void roundTrip_runningChunkWithIterations() throws Exception {
|
||||
ExecutionChunk chunk = new ExecutionChunk(
|
||||
"ex-2", "app", "agent-1", "route-1",
|
||||
"ex-2", "RUNNING",
|
||||
Instant.parse("2026-03-31T10:00:00Z"),
|
||||
null, null, "REGULAR",
|
||||
null, null, null, null, null, null,
|
||||
null, null, null, null, null,
|
||||
0, false,
|
||||
List.of(
|
||||
new FlatProcessorRecord(
|
||||
1, null, null, "split1", "split",
|
||||
null, 3, "COMPLETED",
|
||||
Instant.parse("2026-03-31T10:00:00Z"), 100L,
|
||||
null, null, null, null, null,
|
||||
null, null, null, null, null, null,
|
||||
null, null, null, null, null),
|
||||
new FlatProcessorRecord(
|
||||
2, 1, "split1", "log1", "log",
|
||||
0, null, "COMPLETED",
|
||||
Instant.parse("2026-03-31T10:00:00Z"), 5L,
|
||||
null, "item-0", null, null, null,
|
||||
null, null, null, null, null, null,
|
||||
null, null, null, null, null),
|
||||
new FlatProcessorRecord(
|
||||
3, 1, "split1", "log1", "log",
|
||||
1, null, "COMPLETED",
|
||||
Instant.parse("2026-03-31T10:00:00Z"), 5L,
|
||||
null, "item-1", null, null, null,
|
||||
null, null, null, null, null, null,
|
||||
null, null, null, null, null)));
|
||||
|
||||
String json = MAPPER.writeValueAsString(chunk);
|
||||
ExecutionChunk deserialized = MAPPER.readValue(json, ExecutionChunk.class);
|
||||
|
||||
assertThat(deserialized.isFinal()).isFalse();
|
||||
assertThat(deserialized.processors()).hasSize(3);
|
||||
|
||||
FlatProcessorRecord split = deserialized.processors().get(0);
|
||||
assertThat(split.iterationSize()).isEqualTo(3);
|
||||
assertThat(split.parentSeq()).isNull();
|
||||
|
||||
FlatProcessorRecord child0 = deserialized.processors().get(1);
|
||||
assertThat(child0.parentSeq()).isEqualTo(1);
|
||||
assertThat(child0.parentProcessorId()).isEqualTo("split1");
|
||||
assertThat(child0.iteration()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deserialize_unknownFieldsIgnored() throws Exception {
|
||||
String json = """
|
||||
{"exchangeId":"ex-1","routeId":"r1","status":"COMPLETED",
|
||||
"startTime":"2026-03-31T10:00:00Z","chunkSeq":0,"final":true,
|
||||
"futureField":"ignored","processors":[]}
|
||||
""";
|
||||
ExecutionChunk chunk = MAPPER.readValue(json, ExecutionChunk.class);
|
||||
assertThat(chunk.exchangeId()).isEqualTo("ex-1");
|
||||
assertThat(chunk.isFinal()).isTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user