Adjust runtime mixing and vehicle unit extraction
This commit is contained in:
parent
829dc2e06a
commit
e78d7d6ea8
|
|
@ -143,6 +143,8 @@ public class RuntimeEventDescriptorFactory {
|
||||||
case POSITION -> prefix + "_POSITION";
|
case POSITION -> prefix + "_POSITION";
|
||||||
case PLACE -> prefix + "_PLACE";
|
case PLACE -> prefix + "_PLACE";
|
||||||
case BORDER_CROSSING -> prefix + "_BORDER_CROSSING";
|
case BORDER_CROSSING -> prefix + "_BORDER_CROSSING";
|
||||||
|
case LOAD_UNLOAD -> prefix + "_LOAD_UNLOAD";
|
||||||
|
case SPECIFIC_CONDITION -> prefix + "_SPECIFIC_CONDITION";
|
||||||
case SPEEDING -> Objects.equals("VU", prefix) ? "SPEEDING_EVENTS" : null;
|
case SPEEDING -> Objects.equals("VU", prefix) ? "SPEEDING_EVENTS" : null;
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
|
|
@ -203,7 +205,7 @@ public class RuntimeEventDescriptorFactory {
|
||||||
nullToEmpty(RuntimeEntityReferenceResolver.driverKey(event)),
|
nullToEmpty(RuntimeEntityReferenceResolver.driverKey(event)),
|
||||||
nullToEmpty(event == null || event.eventDomain() == null ? null : event.eventDomain().name()),
|
nullToEmpty(event == null || event.eventDomain() == null ? null : event.eventDomain().name()),
|
||||||
nullToEmpty(event == null || event.eventType() == null ? null : event.eventType().name()),
|
nullToEmpty(event == null || event.eventType() == null ? null : event.eventType().name()),
|
||||||
nullToEmpty(event == null || event.lifecycle() == null ? null : event.lifecycle().name()),
|
nullToEmpty(semanticSupportLifecycle(event)),
|
||||||
normalizeTime(event == null ? null : event.occurredAt()),
|
normalizeTime(event == null ? null : event.occurredAt()),
|
||||||
nullToEmpty(RuntimeEntityReferenceResolver.registrationKey(event)),
|
nullToEmpty(RuntimeEntityReferenceResolver.registrationKey(event)),
|
||||||
nullToEmpty(firstNonBlank(text(raw, "latitude"), position == null || position.latitude() == null ? null : position.latitude().toPlainString())),
|
nullToEmpty(firstNonBlank(text(raw, "latitude"), position == null || position.latitude() == null ? null : position.latitude().toPlainString())),
|
||||||
|
|
@ -217,6 +219,17 @@ public class RuntimeEventDescriptorFactory {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String semanticSupportLifecycle(EventHubEventDto event) {
|
||||||
|
if (event == null || event.lifecycle() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (event.eventDomain() == EventDomain.PLACE
|
||||||
|
&& (event.lifecycle() == EventLifecycle.START || event.lifecycle() == EventLifecycle.BEGIN)) {
|
||||||
|
return EventLifecycle.BEGIN.name();
|
||||||
|
}
|
||||||
|
return event.lifecycle().name();
|
||||||
|
}
|
||||||
|
|
||||||
private JsonNode rawPayload(EventHubEventDto event) {
|
private JsonNode rawPayload(EventHubEventDto event) {
|
||||||
return RuntimeEntityReferenceResolver.rawPayload(event);
|
return RuntimeEntityReferenceResolver.rawPayload(event);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,53 @@ import org.springframework.stereotype.Component;
|
||||||
@Component
|
@Component
|
||||||
public class RuntimeEventMixingRuleRegistry {
|
public class RuntimeEventMixingRuleRegistry {
|
||||||
|
|
||||||
|
private static final Set<EventDomain> SUPPORT_EVENT_DOMAINS = Set.of(
|
||||||
|
EventDomain.POSITION,
|
||||||
|
EventDomain.PLACE,
|
||||||
|
EventDomain.BORDER_CROSSING,
|
||||||
|
EventDomain.LOAD_UNLOAD,
|
||||||
|
EventDomain.SPECIFIC_CONDITION
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<EventType> SUPPORT_EVENT_TYPES = Set.of(
|
||||||
|
EventType.POSITION_RECORDED,
|
||||||
|
EventType.WORKING_DAY_PLACE_RECORDED,
|
||||||
|
EventType.BORDER_INBOUND,
|
||||||
|
EventType.BORDER_OUTBOUND,
|
||||||
|
EventType.BORDER_OUT_EU,
|
||||||
|
EventType.LOAD,
|
||||||
|
EventType.UNLOAD,
|
||||||
|
EventType.LOAD_UNLOAD,
|
||||||
|
EventType.OUT,
|
||||||
|
EventType.FERRY_TRAIN
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<EventLifecycle> SUPPORT_EVENT_LIFECYCLES = Set.of(
|
||||||
|
EventLifecycle.SNAPSHOT,
|
||||||
|
EventLifecycle.START,
|
||||||
|
EventLifecycle.BEGIN,
|
||||||
|
EventLifecycle.END,
|
||||||
|
EventLifecycle.INBOUND,
|
||||||
|
EventLifecycle.OUTBOUND,
|
||||||
|
EventLifecycle.OUT_EU
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> CARD_SUPPORT_EXTRACTION_CODES = Set.of(
|
||||||
|
"CARD_POSITION",
|
||||||
|
"CARD_PLACE",
|
||||||
|
"CARD_BORDER_CROSSING",
|
||||||
|
"CARD_LOAD_UNLOAD",
|
||||||
|
"CARD_SPECIFIC_CONDITION"
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> VU_SUPPORT_EXTRACTION_CODES = Set.of(
|
||||||
|
"VU_POSITION",
|
||||||
|
"VU_PLACE",
|
||||||
|
"VU_BORDER_CROSSING",
|
||||||
|
"VU_LOAD_UNLOAD",
|
||||||
|
"VU_SPECIFIC_CONDITION"
|
||||||
|
);
|
||||||
|
|
||||||
public List<RuntimeEventMixingRule> rulesForMode(String mode) {
|
public List<RuntimeEventMixingRule> rulesForMode(String mode) {
|
||||||
if (RuntimeEventMixingService.MODE_OFF.equals(mode)) {
|
if (RuntimeEventMixingService.MODE_OFF.equals(mode)) {
|
||||||
return List.of();
|
return List.of();
|
||||||
|
|
@ -61,12 +108,11 @@ public class RuntimeEventMixingRuleRegistry {
|
||||||
RuntimeEventMixingService.RULE_TACHOGRAPH_CARD_VU_SUPPORT_SAME_EVENT_KEY,
|
RuntimeEventMixingService.RULE_TACHOGRAPH_CARD_VU_SUPPORT_SAME_EVENT_KEY,
|
||||||
RuntimeEventMixingChannel.SUPPORT_EVIDENCE,
|
RuntimeEventMixingChannel.SUPPORT_EVIDENCE,
|
||||||
RuntimeEventMixingRule.EQUIVALENCE_EXACT_EVENT_KEY,
|
RuntimeEventMixingRule.EQUIVALENCE_EXACT_EVENT_KEY,
|
||||||
Set.of(EventDomain.POSITION, EventDomain.PLACE, EventDomain.BORDER_CROSSING),
|
SUPPORT_EVENT_DOMAINS,
|
||||||
Set.of(EventType.POSITION_RECORDED, EventType.WORKING_DAY_PLACE_RECORDED,
|
SUPPORT_EVENT_TYPES,
|
||||||
EventType.BORDER_INBOUND, EventType.BORDER_OUTBOUND, EventType.BORDER_OUT_EU),
|
SUPPORT_EVENT_LIFECYCLES,
|
||||||
Set.of(EventLifecycle.SNAPSHOT, EventLifecycle.INBOUND, EventLifecycle.OUTBOUND, EventLifecycle.OUT_EU),
|
CARD_SUPPORT_EXTRACTION_CODES,
|
||||||
Set.of("CARD_POSITION", "CARD_PLACE", "CARD_BORDER_CROSSING"),
|
VU_SUPPORT_EXTRACTION_CODES,
|
||||||
Set.of("VU_POSITION", "VU_PLACE", "VU_BORDER_CROSSING"),
|
|
||||||
RuntimeResolvedEventRole.FUSED_PRIMARY,
|
RuntimeResolvedEventRole.FUSED_PRIMARY,
|
||||||
RuntimeResolvedEventRole.SUPPRESSED_DUPLICATE,
|
RuntimeResolvedEventRole.SUPPRESSED_DUPLICATE,
|
||||||
"FUSED_PRIMARY_SELECTED",
|
"FUSED_PRIMARY_SELECTED",
|
||||||
|
|
@ -79,12 +125,11 @@ public class RuntimeEventMixingRuleRegistry {
|
||||||
RuntimeEventMixingService.RULE_TACHOGRAPH_CARD_VU_SUPPORT_COMPATIBLE_KEY,
|
RuntimeEventMixingService.RULE_TACHOGRAPH_CARD_VU_SUPPORT_COMPATIBLE_KEY,
|
||||||
RuntimeEventMixingChannel.SUPPORT_EVIDENCE,
|
RuntimeEventMixingChannel.SUPPORT_EVIDENCE,
|
||||||
RuntimeEventMixingRule.EQUIVALENCE_COMPATIBLE_SUPPORT_KEY,
|
RuntimeEventMixingRule.EQUIVALENCE_COMPATIBLE_SUPPORT_KEY,
|
||||||
Set.of(EventDomain.POSITION, EventDomain.PLACE, EventDomain.BORDER_CROSSING),
|
SUPPORT_EVENT_DOMAINS,
|
||||||
Set.of(EventType.POSITION_RECORDED, EventType.WORKING_DAY_PLACE_RECORDED,
|
SUPPORT_EVENT_TYPES,
|
||||||
EventType.BORDER_INBOUND, EventType.BORDER_OUTBOUND, EventType.BORDER_OUT_EU),
|
SUPPORT_EVENT_LIFECYCLES,
|
||||||
Set.of(EventLifecycle.SNAPSHOT, EventLifecycle.INBOUND, EventLifecycle.OUTBOUND, EventLifecycle.OUT_EU),
|
CARD_SUPPORT_EXTRACTION_CODES,
|
||||||
Set.of("CARD_POSITION", "CARD_PLACE", "CARD_BORDER_CROSSING"),
|
VU_SUPPORT_EXTRACTION_CODES,
|
||||||
Set.of("VU_POSITION", "VU_PLACE", "VU_BORDER_CROSSING"),
|
|
||||||
RuntimeResolvedEventRole.FUSED_PRIMARY,
|
RuntimeResolvedEventRole.FUSED_PRIMARY,
|
||||||
RuntimeResolvedEventRole.SUPPRESSED_DUPLICATE,
|
RuntimeResolvedEventRole.SUPPRESSED_DUPLICATE,
|
||||||
"FUSED_PRIMARY_SELECTED",
|
"FUSED_PRIMARY_SELECTED",
|
||||||
|
|
|
||||||
|
|
@ -215,22 +215,22 @@ public class DriverWorkingTimeRuntimeProcessingPlan implements RuntimeProcessing
|
||||||
boolean includeExecutionModuleResults = booleanParameter(
|
boolean includeExecutionModuleResults = booleanParameter(
|
||||||
request.parameters(),
|
request.parameters(),
|
||||||
INCLUDE_EXECUTION_MODULE_RESULTS_PARAMETER,
|
INCLUDE_EXECUTION_MODULE_RESULTS_PARAMETER,
|
||||||
true
|
false
|
||||||
);
|
);
|
||||||
boolean includePartitionMetadata = booleanParameter(
|
boolean includePartitionMetadata = booleanParameter(
|
||||||
request.parameters(),
|
request.parameters(),
|
||||||
INCLUDE_PARTITION_METADATA_PARAMETER,
|
INCLUDE_PARTITION_METADATA_PARAMETER,
|
||||||
true
|
false
|
||||||
);
|
);
|
||||||
boolean includePartitionModuleResults = booleanParameter(
|
boolean includePartitionModuleResults = booleanParameter(
|
||||||
request.parameters(),
|
request.parameters(),
|
||||||
INCLUDE_PARTITION_MODULE_RESULTS_PARAMETER,
|
INCLUDE_PARTITION_MODULE_RESULTS_PARAMETER,
|
||||||
true
|
false
|
||||||
);
|
);
|
||||||
boolean includeSupportEvidenceNormalization = booleanParameter(
|
boolean includeSupportEvidenceNormalization = booleanParameter(
|
||||||
request.parameters(),
|
request.parameters(),
|
||||||
INCLUDE_SUPPORT_EVIDENCE_NORMALIZATION_PARAMETER,
|
INCLUDE_SUPPORT_EVIDENCE_NORMALIZATION_PARAMETER,
|
||||||
true
|
false
|
||||||
);
|
);
|
||||||
int vehicleEvidencePaddingMinutes = resolveVehicleEvidencePaddingMinutes(
|
int vehicleEvidencePaddingMinutes = resolveVehicleEvidencePaddingMinutes(
|
||||||
request.sourceSelection(),
|
request.sourceSelection(),
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ class RuntimeEventMixingServiceTest {
|
||||||
"TACHOGRAPH:CARD_PLACE:1",
|
"TACHOGRAPH:CARD_PLACE:1",
|
||||||
EventDomain.PLACE,
|
EventDomain.PLACE,
|
||||||
EventType.WORKING_DAY_PLACE_RECORDED,
|
EventType.WORKING_DAY_PLACE_RECORDED,
|
||||||
EventLifecycle.SNAPSHOT,
|
EventLifecycle.START,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
EventHubEventDto vuPlace = supportEvidence(
|
EventHubEventDto vuPlace = supportEvidence(
|
||||||
|
|
@ -157,7 +157,7 @@ class RuntimeEventMixingServiceTest {
|
||||||
"TACHOGRAPH:VU_PLACE:2",
|
"TACHOGRAPH:VU_PLACE:2",
|
||||||
EventDomain.PLACE,
|
EventDomain.PLACE,
|
||||||
EventType.WORKING_DAY_PLACE_RECORDED,
|
EventType.WORKING_DAY_PLACE_RECORDED,
|
||||||
EventLifecycle.SNAPSHOT,
|
EventLifecycle.START,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
EventHubEventDto cardBorder = supportEvidence(
|
EventHubEventDto cardBorder = supportEvidence(
|
||||||
|
|
@ -188,6 +188,72 @@ class RuntimeEventMixingServiceTest {
|
||||||
assertThat(mixed.eventMixingDecisions()).hasSize(2);
|
assertThat(mixed.eventMixingDecisions()).hasSize(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void suppressesVuPlaceDuplicateForFileSessionBeginLifecycle() {
|
||||||
|
EventHubEventDto cardPlace = fileSessionSupportEvidence(
|
||||||
|
"DRIVER_CARD",
|
||||||
|
"TACHOGRAPH_FILE_SESSION:11111111-1111-1111-1111-111111111111:SUPPORT:card-place-1:BEGIN:2026-04-01T00:00:00Z",
|
||||||
|
EventDomain.PLACE,
|
||||||
|
EventType.WORKING_DAY_PLACE_RECORDED,
|
||||||
|
EventLifecycle.BEGIN,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuPlace = fileSessionSupportEvidence(
|
||||||
|
"VEHICLE_UNIT",
|
||||||
|
"TACHOGRAPH_FILE_SESSION:22222222-2222-2222-2222-222222222222:SUPPORT:vu-place-1:BEGIN:2026-04-01T00:00:00Z",
|
||||||
|
EventDomain.PLACE,
|
||||||
|
EventType.WORKING_DAY_PLACE_RECORDED,
|
||||||
|
EventLifecycle.BEGIN,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
RuntimeMixedEventBundle mixed = service.mix(
|
||||||
|
List.of(cardPlace, vuPlace),
|
||||||
|
RuntimeEventMixingService.MODE_TACHOGRAPH_SAME_SOURCE
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(mixed.supportEvidenceEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactly("TACHOGRAPH_FILE_SESSION:11111111-1111-1111-1111-111111111111:SUPPORT:card-place-1:BEGIN:2026-04-01T00:00:00Z");
|
||||||
|
assertThat(mixed.suppressedEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactly("TACHOGRAPH_FILE_SESSION:22222222-2222-2222-2222-222222222222:SUPPORT:vu-place-1:BEGIN:2026-04-01T00:00:00Z");
|
||||||
|
assertThat(mixed.eventMixingDecisions()).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void treatsStartAndBeginAsEquivalentPlaceLifecycles() {
|
||||||
|
EventHubEventDto cardPlace = supportEvidence(
|
||||||
|
"CARD_PLACE",
|
||||||
|
"DRIVER_CARD",
|
||||||
|
"TACHOGRAPH:CARD_PLACE:START",
|
||||||
|
EventDomain.PLACE,
|
||||||
|
EventType.WORKING_DAY_PLACE_RECORDED,
|
||||||
|
EventLifecycle.START,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuPlace = supportEvidence(
|
||||||
|
"VU_PLACE",
|
||||||
|
"VEHICLE_UNIT",
|
||||||
|
"TACHOGRAPH:VU_PLACE:BEGIN",
|
||||||
|
EventDomain.PLACE,
|
||||||
|
EventType.WORKING_DAY_PLACE_RECORDED,
|
||||||
|
EventLifecycle.BEGIN,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
RuntimeMixedEventBundle mixed = service.mix(
|
||||||
|
List.of(cardPlace, vuPlace),
|
||||||
|
RuntimeEventMixingService.MODE_TACHOGRAPH_SAME_SOURCE
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(mixed.supportEvidenceEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactly("TACHOGRAPH:CARD_PLACE:START");
|
||||||
|
assertThat(mixed.suppressedEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactly("TACHOGRAPH:VU_PLACE:BEGIN");
|
||||||
|
assertThat(mixed.eventMixingDecisions()).hasSize(1);
|
||||||
|
assertThat(mixed.eventMixingDecisions().getFirst().ruleId())
|
||||||
|
.isEqualTo(RuntimeEventMixingService.RULE_TACHOGRAPH_CARD_VU_SUPPORT_COMPATIBLE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void suppressesTachographFileSessionVuPositionDuplicateWhenNoExtractionCodeIsPresent() {
|
void suppressesTachographFileSessionVuPositionDuplicateWhenNoExtractionCodeIsPresent() {
|
||||||
EventHubEventDto card = fileSessionSupportEvidence(
|
EventHubEventDto card = fileSessionSupportEvidence(
|
||||||
|
|
@ -220,6 +286,143 @@ class RuntimeEventMixingServiceTest {
|
||||||
.containsExactly("VU_POSITION");
|
.containsExactly("VU_POSITION");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void suppressesVuDuplicatesForAllAdditionalSupportEventTypes() {
|
||||||
|
EventHubEventDto cardLoad = supportEvidence(
|
||||||
|
"CARD_LOAD_UNLOAD", "DRIVER_CARD", "TACHOGRAPH:CARD_LOAD_UNLOAD:LOAD",
|
||||||
|
EventDomain.LOAD_UNLOAD, EventType.LOAD, EventLifecycle.SNAPSHOT, false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuLoad = supportEvidence(
|
||||||
|
"VU_LOAD_UNLOAD", "VEHICLE_UNIT", "TACHOGRAPH:VU_LOAD_UNLOAD:LOAD",
|
||||||
|
EventDomain.LOAD_UNLOAD, EventType.LOAD, EventLifecycle.SNAPSHOT, true
|
||||||
|
);
|
||||||
|
EventHubEventDto cardUnload = supportEvidence(
|
||||||
|
"CARD_LOAD_UNLOAD", "DRIVER_CARD", "TACHOGRAPH:CARD_LOAD_UNLOAD:UNLOAD",
|
||||||
|
EventDomain.LOAD_UNLOAD, EventType.UNLOAD, EventLifecycle.SNAPSHOT, false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuUnload = supportEvidence(
|
||||||
|
"VU_LOAD_UNLOAD", "VEHICLE_UNIT", "TACHOGRAPH:VU_LOAD_UNLOAD:UNLOAD",
|
||||||
|
EventDomain.LOAD_UNLOAD, EventType.UNLOAD, EventLifecycle.SNAPSHOT, true
|
||||||
|
);
|
||||||
|
EventHubEventDto cardLoadUnload = supportEvidence(
|
||||||
|
"CARD_LOAD_UNLOAD", "DRIVER_CARD", "TACHOGRAPH:CARD_LOAD_UNLOAD:LOAD_UNLOAD",
|
||||||
|
EventDomain.LOAD_UNLOAD, EventType.LOAD_UNLOAD, EventLifecycle.SNAPSHOT, false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuLoadUnload = supportEvidence(
|
||||||
|
"VU_LOAD_UNLOAD", "VEHICLE_UNIT", "TACHOGRAPH:VU_LOAD_UNLOAD:LOAD_UNLOAD",
|
||||||
|
EventDomain.LOAD_UNLOAD, EventType.LOAD_UNLOAD, EventLifecycle.SNAPSHOT, true
|
||||||
|
);
|
||||||
|
EventHubEventDto cardOut = supportEvidence(
|
||||||
|
"CARD_SPECIFIC_CONDITION", "DRIVER_CARD", "TACHOGRAPH:CARD_SPECIFIC_CONDITION:OUT:BEGIN",
|
||||||
|
EventDomain.SPECIFIC_CONDITION, EventType.OUT, EventLifecycle.BEGIN, false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuOut = supportEvidence(
|
||||||
|
"VU_SPECIFIC_CONDITION", "VEHICLE_UNIT", "TACHOGRAPH:VU_SPECIFIC_CONDITION:OUT:BEGIN",
|
||||||
|
EventDomain.SPECIFIC_CONDITION, EventType.OUT, EventLifecycle.BEGIN, true
|
||||||
|
);
|
||||||
|
EventHubEventDto cardFerryTrain = supportEvidence(
|
||||||
|
"CARD_SPECIFIC_CONDITION", "DRIVER_CARD", "TACHOGRAPH:CARD_SPECIFIC_CONDITION:FERRY_TRAIN:END",
|
||||||
|
EventDomain.SPECIFIC_CONDITION, EventType.FERRY_TRAIN, EventLifecycle.END, false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuFerryTrain = supportEvidence(
|
||||||
|
"VU_SPECIFIC_CONDITION", "VEHICLE_UNIT", "TACHOGRAPH:VU_SPECIFIC_CONDITION:FERRY_TRAIN:END",
|
||||||
|
EventDomain.SPECIFIC_CONDITION, EventType.FERRY_TRAIN, EventLifecycle.END, true
|
||||||
|
);
|
||||||
|
|
||||||
|
RuntimeMixedEventBundle mixed = service.mix(
|
||||||
|
List.of(
|
||||||
|
cardLoad, vuLoad,
|
||||||
|
cardUnload, vuUnload,
|
||||||
|
cardLoadUnload, vuLoadUnload,
|
||||||
|
cardOut, vuOut,
|
||||||
|
cardFerryTrain, vuFerryTrain
|
||||||
|
),
|
||||||
|
RuntimeEventMixingService.MODE_TACHOGRAPH_SAME_SOURCE
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(mixed.supportEvidenceEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactlyInAnyOrder(
|
||||||
|
"TACHOGRAPH:CARD_LOAD_UNLOAD:LOAD",
|
||||||
|
"TACHOGRAPH:CARD_LOAD_UNLOAD:UNLOAD",
|
||||||
|
"TACHOGRAPH:CARD_LOAD_UNLOAD:LOAD_UNLOAD",
|
||||||
|
"TACHOGRAPH:CARD_SPECIFIC_CONDITION:OUT:BEGIN",
|
||||||
|
"TACHOGRAPH:CARD_SPECIFIC_CONDITION:FERRY_TRAIN:END"
|
||||||
|
);
|
||||||
|
assertThat(mixed.suppressedEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactlyInAnyOrder(
|
||||||
|
"TACHOGRAPH:VU_LOAD_UNLOAD:LOAD",
|
||||||
|
"TACHOGRAPH:VU_LOAD_UNLOAD:UNLOAD",
|
||||||
|
"TACHOGRAPH:VU_LOAD_UNLOAD:LOAD_UNLOAD",
|
||||||
|
"TACHOGRAPH:VU_SPECIFIC_CONDITION:OUT:BEGIN",
|
||||||
|
"TACHOGRAPH:VU_SPECIFIC_CONDITION:FERRY_TRAIN:END"
|
||||||
|
);
|
||||||
|
assertThat(mixed.eventMixingDecisions()).hasSize(5);
|
||||||
|
assertThat(mixed.eventMixingDecisions())
|
||||||
|
.allSatisfy(decision -> assertThat(decision.secondaryExtractionCodes()).hasSize(1));
|
||||||
|
assertThat(mixed.eventMixingDecisions())
|
||||||
|
.extracting(decision -> decision.secondaryExtractionCodes().getFirst())
|
||||||
|
.containsExactlyInAnyOrder(
|
||||||
|
"VU_LOAD_UNLOAD", "VU_LOAD_UNLOAD", "VU_LOAD_UNLOAD",
|
||||||
|
"VU_SPECIFIC_CONDITION", "VU_SPECIFIC_CONDITION"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void suppressesFileSessionVuLoadUnloadAndSpecificConditionDuplicatesWithoutExtractionCodes() {
|
||||||
|
EventHubEventDto cardLoad = fileSessionSupportEvidence(
|
||||||
|
"DRIVER_CARD",
|
||||||
|
"TACHOGRAPH_FILE_SESSION:11111111-1111-1111-1111-111111111111:SUPPORT:card-load-1:SNAPSHOT:2026-04-01T00:00:00Z",
|
||||||
|
EventDomain.LOAD_UNLOAD,
|
||||||
|
EventType.LOAD,
|
||||||
|
EventLifecycle.SNAPSHOT,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuLoad = fileSessionSupportEvidence(
|
||||||
|
"VEHICLE_UNIT",
|
||||||
|
"TACHOGRAPH_FILE_SESSION:22222222-2222-2222-2222-222222222222:SUPPORT:vu-load-1:SNAPSHOT:2026-04-01T00:00:00Z",
|
||||||
|
EventDomain.LOAD_UNLOAD,
|
||||||
|
EventType.LOAD,
|
||||||
|
EventLifecycle.SNAPSHOT,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
EventHubEventDto cardOut = fileSessionSupportEvidence(
|
||||||
|
"DRIVER_CARD",
|
||||||
|
"TACHOGRAPH_FILE_SESSION:11111111-1111-1111-1111-111111111111:SUPPORT:card-out-1:BEGIN:2026-04-01T00:00:00Z",
|
||||||
|
EventDomain.SPECIFIC_CONDITION,
|
||||||
|
EventType.OUT,
|
||||||
|
EventLifecycle.BEGIN,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
EventHubEventDto vuOut = fileSessionSupportEvidence(
|
||||||
|
"VEHICLE_UNIT",
|
||||||
|
"TACHOGRAPH_FILE_SESSION:22222222-2222-2222-2222-222222222222:SUPPORT:vu-out-1:BEGIN:2026-04-01T00:00:00Z",
|
||||||
|
EventDomain.SPECIFIC_CONDITION,
|
||||||
|
EventType.OUT,
|
||||||
|
EventLifecycle.BEGIN,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
RuntimeMixedEventBundle mixed = service.mix(
|
||||||
|
List.of(cardLoad, vuLoad, cardOut, vuOut),
|
||||||
|
RuntimeEventMixingService.MODE_TACHOGRAPH_SAME_SOURCE
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(mixed.supportEvidenceEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactlyInAnyOrder(
|
||||||
|
cardLoad.externalSourceEventId(),
|
||||||
|
cardOut.externalSourceEventId()
|
||||||
|
);
|
||||||
|
assertThat(mixed.suppressedEvents()).extracting(EventHubEventDto::externalSourceEventId)
|
||||||
|
.containsExactlyInAnyOrder(
|
||||||
|
vuLoad.externalSourceEventId(),
|
||||||
|
vuOut.externalSourceEventId()
|
||||||
|
);
|
||||||
|
assertThat(mixed.eventMixingDecisions()).hasSize(2);
|
||||||
|
assertThat(mixed.eventMixingDecisions())
|
||||||
|
.extracting(decision -> decision.secondaryExtractionCodes().getFirst())
|
||||||
|
.containsExactlyInAnyOrder("VU_LOAD_UNLOAD", "VU_SPECIFIC_CONDITION");
|
||||||
|
}
|
||||||
|
|
||||||
private EventHubEventDto activity(String extractionCode, String sourceKind, String externalId) {
|
private EventHubEventDto activity(String extractionCode, String sourceKind, String externalId) {
|
||||||
ObjectNode raw = baseRaw(extractionCode, sourceKind);
|
ObjectNode raw = baseRaw(extractionCode, sourceKind);
|
||||||
raw.put("activityType", "BREAK_REST");
|
raw.put("activityType", "BREAK_REST");
|
||||||
|
|
@ -264,6 +467,9 @@ class RuntimeEventMixingServiceTest {
|
||||||
raw.put("region", "W");
|
raw.put("region", "W");
|
||||||
raw.put("countryFrom", "AT");
|
raw.put("countryFrom", "AT");
|
||||||
raw.put("countryTo", "DE");
|
raw.put("countryTo", "DE");
|
||||||
|
if (domain == EventDomain.LOAD_UNLOAD) {
|
||||||
|
raw.put("operation", type.name());
|
||||||
|
}
|
||||||
ObjectNode payload = JsonNodeFactory.instance.objectNode();
|
ObjectNode payload = JsonNodeFactory.instance.objectNode();
|
||||||
payload.set("raw", raw);
|
payload.set("raw", raw);
|
||||||
ObjectNode attributes = JsonNodeFactory.instance.objectNode();
|
ObjectNode attributes = JsonNodeFactory.instance.objectNode();
|
||||||
|
|
@ -271,6 +477,9 @@ class RuntimeEventMixingServiceTest {
|
||||||
attributes.put("region", "W");
|
attributes.put("region", "W");
|
||||||
attributes.put("countryFrom", "AT");
|
attributes.put("countryFrom", "AT");
|
||||||
attributes.put("countryTo", "DE");
|
attributes.put("countryTo", "DE");
|
||||||
|
if (domain == EventDomain.LOAD_UNLOAD) {
|
||||||
|
attributes.put("operation", type.name());
|
||||||
|
}
|
||||||
VehicleRefDto vehicleRef = withVin
|
VehicleRefDto vehicleRef = withVin
|
||||||
? new VehicleRefDto("1:VEHICLE-ID", "WDB9634031L123456", "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"))
|
? new VehicleRefDto("1:VEHICLE-ID", "WDB9634031L123456", "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"))
|
||||||
: new VehicleRefDto(null, null, "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"));
|
: new VehicleRefDto(null, null, "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"));
|
||||||
|
|
@ -330,6 +539,9 @@ class RuntimeEventMixingServiceTest {
|
||||||
raw.put("region", "W");
|
raw.put("region", "W");
|
||||||
raw.put("countryFrom", "AT");
|
raw.put("countryFrom", "AT");
|
||||||
raw.put("countryTo", "DE");
|
raw.put("countryTo", "DE");
|
||||||
|
if (domain == EventDomain.LOAD_UNLOAD) {
|
||||||
|
raw.put("operation", type.name());
|
||||||
|
}
|
||||||
ObjectNode payload = JsonNodeFactory.instance.objectNode();
|
ObjectNode payload = JsonNodeFactory.instance.objectNode();
|
||||||
payload.set("raw", raw);
|
payload.set("raw", raw);
|
||||||
ObjectNode attributes = JsonNodeFactory.instance.objectNode();
|
ObjectNode attributes = JsonNodeFactory.instance.objectNode();
|
||||||
|
|
@ -337,6 +549,9 @@ class RuntimeEventMixingServiceTest {
|
||||||
attributes.put("region", "W");
|
attributes.put("region", "W");
|
||||||
attributes.put("countryFrom", "AT");
|
attributes.put("countryFrom", "AT");
|
||||||
attributes.put("countryTo", "DE");
|
attributes.put("countryTo", "DE");
|
||||||
|
if (domain == EventDomain.LOAD_UNLOAD) {
|
||||||
|
attributes.put("operation", type.name());
|
||||||
|
}
|
||||||
VehicleRefDto vehicleRef = withVin
|
VehicleRefDto vehicleRef = withVin
|
||||||
? new VehicleRefDto("1:VEHICLE-ID", "WDB9634031L123456", "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"))
|
? new VehicleRefDto("1:VEHICLE-ID", "WDB9634031L123456", "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"))
|
||||||
: new VehicleRefDto(null, null, "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"));
|
: new VehicleRefDto(null, null, "1:REG-ID", new VehicleRegistrationRefDto("1", 1, "LL-158TE"));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue