diff --git a/src/main/java/at/procon/eventhub/tachographfilesession/dto/TachographEsperDriverProcessingResultDto.java b/src/main/java/at/procon/eventhub/tachographfilesession/dto/TachographEsperDriverProcessingResultDto.java index c2cde83..60d2869 100644 --- a/src/main/java/at/procon/eventhub/tachographfilesession/dto/TachographEsperDriverProcessingResultDto.java +++ b/src/main/java/at/procon/eventhub/tachographfilesession/dto/TachographEsperDriverProcessingResultDto.java @@ -21,6 +21,7 @@ public record TachographEsperDriverProcessingResultDto( int drivingIntervalCount, int drivingInterruptionIntervalCount, int drivingInterruptionVehicleChangeIntervalCount, + int dailyWeeklyRestCandidateIntervalCount, int potentialHomeOvernightStayIntervalCount, int vehicleUsageIntervalCount, int vuCardAbsentIntervalCount, @@ -28,6 +29,7 @@ public record TachographEsperDriverProcessingResultDto( List drivingIntervals, List drivingInterruptionIntervals, List drivingInterruptionVehicleChangeIntervals, + List dailyWeeklyRestCandidateIntervals, List potentialHomeOvernightStayIntervals, List vehicleUsageIntervals, List vuCardAbsentIntervals, diff --git a/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilder.java b/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilder.java index 35fefdb..f8f857b 100644 --- a/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilder.java +++ b/src/main/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilder.java @@ -55,6 +55,8 @@ public class DriverTimelineBuilder { loadResource("esper/tachograph-driving-interruption-interval-events.epl"); private static final String DRIVING_INTERRUPTION_VEHICLE_CHANGE_INTERVAL_EVENTS_EPL = loadResource("esper/tachograph-driving-interruption-vehicle-change-interval-events.epl"); + private static final String DAILY_WEEKLY_REST_CANDIDATE_INTERVAL_EVENTS_EPL_TEMPLATE = + loadResource("esper/tachograph-daily-weekly-rest-candidate-interval-events.epl"); private static final String POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE = loadResource("esper/tachograph-potential-home-overnight-stay-interval-events.epl"); private static final String VEHICLE_USAGE_INTERVAL_EVENTS_EPL = @@ -209,12 +211,11 @@ public class DriverTimelineBuilder { } public List buildEsperPotentialHomeOvernightStayIntervalEvents( - List drivingInterruptionIntervals, - List vuCardAbsentIntervals, - int minimumRestPeriodMinutes + List drivingInterruptionVehicleChangeIntervals, + List vuCardAbsentIntervals ) { - if (drivingInterruptionIntervals == null - || drivingInterruptionIntervals.isEmpty() + if (drivingInterruptionVehicleChangeIntervals == null + || drivingInterruptionVehicleChangeIntervals.isEmpty() || vuCardAbsentIntervals == null || vuCardAbsentIntervals.isEmpty()) { return List.of(); @@ -223,7 +224,7 @@ public class DriverTimelineBuilder { executeWithRuntime( configuration -> { configuration.getCommon().addEventType( - "TachographDrivingInterruptionIntervalInputEvent", + "TachographDrivingInterruptionVehicleChangeIntervalInputEvent", drivingInterruptionIntervalInputDefinition() ); configuration.getCommon().addEventType( @@ -231,7 +232,7 @@ public class DriverTimelineBuilder { vuCardAbsentIntervalInputDefinition() ); }, - renderPotentialHomeOvernightStayIntervalEventsEpl(minimumRestPeriodMinutes), + POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE, "potentialHomeOvernightStayIntervals", newData -> collectPotentialHomeOvernightStayIntervalEvents(newData, result), runtime -> { @@ -241,6 +242,34 @@ public class DriverTimelineBuilder { "TachographVuCardAbsentIntervalInputEvent" ); } + for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionVehicleChangeIntervals) { + runtime.getEventService().sendEventMap( + toDrivingInterruptionIntervalInputMap(interval), + "TachographDrivingInterruptionVehicleChangeIntervalInputEvent" + ); + } + } + ); + return result; + } + + public List buildEsperDailyWeeklyRestCandidateIntervalEvents( + List drivingInterruptionIntervals, + int minimumRestPeriodMinutes + ) { + if (drivingInterruptionIntervals == null || drivingInterruptionIntervals.isEmpty()) { + return List.of(); + } + List result = new ArrayList<>(); + executeWithRuntime( + configuration -> configuration.getCommon().addEventType( + "TachographDrivingInterruptionIntervalInputEvent", + drivingInterruptionIntervalInputDefinition() + ), + renderDailyWeeklyRestCandidateIntervalEventsEpl(minimumRestPeriodMinutes), + "dailyWeeklyRestCandidateIntervals", + newData -> collectDrivingInterruptionIntervalEventsFromTimestamps(newData, result), + runtime -> { for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionIntervals) { runtime.getEventService().sendEventMap( toDrivingInterruptionIntervalInputMap(interval), @@ -1002,10 +1031,10 @@ public class DriverTimelineBuilder { ); } - private String renderPotentialHomeOvernightStayIntervalEventsEpl(int minimumRestPeriodMinutes) { + private String renderDailyWeeklyRestCandidateIntervalEventsEpl(int minimumRestPeriodMinutes) { long thresholdSeconds = Math.max(1, minimumRestPeriodMinutes) * 60L; - return POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE.replace( - "${POTENTIAL_HOME_OVERNIGHT_STAY_THRESHOLD_SECONDS}", + return DAILY_WEEKLY_REST_CANDIDATE_INTERVAL_EVENTS_EPL_TEMPLATE.replace( + "${MINIMUM_REST_PERIOD_THRESHOLD_SECONDS}", Long.toString(thresholdSeconds) ); } diff --git a/src/main/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingService.java b/src/main/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingService.java index be4c3eb..8dc23d2 100644 --- a/src/main/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingService.java +++ b/src/main/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingService.java @@ -174,11 +174,24 @@ public class TachographFileSessionProcessingService { requestedFrom, requestedTo ); + List rawDailyWeeklyRestCandidateIntervals = + driverTimelineBuilder.buildEsperDailyWeeklyRestCandidateIntervalEvents( + rawDrivingInterruptionIntervals, + minimumRestPeriodMinutes + ); + List dailyWeeklyRestCandidateIntervals = + clipEsperDrivingInterruptionIntervalEvents( + rawDailyWeeklyRestCandidateIntervals, + requestedFrom, + requestedTo + ); + List rawDrivingInterruptionVehicleChangeIntervals = + driverTimelineBuilder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents( + rawDailyWeeklyRestCandidateIntervals + ); List drivingInterruptionVehicleChangeIntervals = clipEsperDrivingInterruptionIntervalEvents( - driverTimelineBuilder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents( - rawDrivingInterruptionIntervals - ), + rawDrivingInterruptionVehicleChangeIntervals, requestedFrom, requestedTo ); @@ -187,9 +200,8 @@ public class TachographFileSessionProcessingService { List potentialHomeOvernightStayIntervals = clipEsperPotentialHomeOvernightStayIntervalEvents( driverTimelineBuilder.buildEsperPotentialHomeOvernightStayIntervalEvents( - rawDrivingInterruptionIntervals, - rawVuCardAbsentIntervals, - minimumRestPeriodMinutes + rawDrivingInterruptionVehicleChangeIntervals, + rawVuCardAbsentIntervals ), rawVuCardAbsentIntervals, requestedFrom, @@ -218,6 +230,7 @@ public class TachographFileSessionProcessingService { drivingIntervals.size(), drivingInterruptionIntervals.size(), drivingInterruptionVehicleChangeIntervals.size(), + dailyWeeklyRestCandidateIntervals.size(), potentialHomeOvernightStayIntervals.size(), vehicleUsageIntervals.size(), vuCardAbsentIntervals.size(), @@ -225,6 +238,7 @@ public class TachographFileSessionProcessingService { drivingIntervals, drivingInterruptionIntervals, drivingInterruptionVehicleChangeIntervals, + dailyWeeklyRestCandidateIntervals, potentialHomeOvernightStayIntervals, vehicleUsageIntervals, vuCardAbsentIntervals, @@ -403,7 +417,12 @@ public class TachographFileSessionProcessingService { return null; } long durationSeconds = Duration.between(start, end).getSeconds(); - long unknownDurationSeconds = overlapSeconds(start, end, rawVuCardAbsentIntervals, interval.driverKey()); + long unknownDurationSeconds = overlapSeconds( + start, + end, + rawVuCardAbsentIntervals, + interval.driverKey() + ); double unknownCoveragePercent = durationSeconds == 0L ? 0.0d : (unknownDurationSeconds * 100.0d) / durationSeconds; @@ -993,8 +1012,9 @@ public class TachographFileSessionProcessingService { "This endpoint returns Esper-backed per-driver interval projections from the in-memory tachograph file-session model.", "Driving intervals are a filtered projection of activity intervals where activityType = DRIVE.", "Driving interruption intervals are gaps between consecutive driving intervals longer than the configured significant-driving threshold.", - "Driving interruption vehicle-change intervals are DTI intervals where previousRegistrationKey differs from nextRegistrationKey.", - "Potential home overnight stay intervals are DTI intervals longer than the configured minimum rest-period threshold where VU card-absent overlap covers at least 95% of the DTI.", + "Driving interruption vehicle-change intervals are daily/weekly rest candidates where previousRegistrationKey differs from nextRegistrationKey.", + "Daily/weekly rest candidate intervals are driving interruption intervals longer than the configured minimum rest-period threshold.", + "Potential home overnight stay intervals are vehicle-change daily/weekly rest candidates where VU card-absent overlap covers at least 95% of the candidate interval.", "VU card-absent intervals are gaps between consecutive normalized vehicle-usage intervals for the same driver.", "occurredFrom and occurredTo clip the returned interval projections to the requested UTC time window.", "Vehicle-usage intervals clear clipped odometer endpoints because boundary odometer values cannot be recomputed safely from the source interval." diff --git a/src/main/resources/esper/tachograph-daily-weekly-rest-candidate-interval-events.epl b/src/main/resources/esper/tachograph-daily-weekly-rest-candidate-interval-events.epl new file mode 100644 index 0000000..2ec2219 --- /dev/null +++ b/src/main/resources/esper/tachograph-daily-weekly-rest-candidate-interval-events.epl @@ -0,0 +1,3 @@ +@name('dailyWeeklyRestCandidateIntervals') +select * +from TachographDrivingInterruptionIntervalInputEvent(durationSeconds > ${MINIMUM_REST_PERIOD_THRESHOLD_SECONDS}); diff --git a/src/main/resources/esper/tachograph-potential-home-overnight-stay-interval-events.epl b/src/main/resources/esper/tachograph-potential-home-overnight-stay-interval-events.epl index 3371baf..85900ea 100644 --- a/src/main/resources/esper/tachograph-potential-home-overnight-stay-interval-events.epl +++ b/src/main/resources/esper/tachograph-potential-home-overnight-stay-interval-events.epl @@ -1,65 +1,65 @@ @name('potentialHomeOvernightStayIntervals') select - d.sessionId as sessionId, - d.driverKey as driverKey, - d.startedAt as startedAt, - d.endedAt as endedAt, - d.durationSeconds as durationSeconds, + c.sessionId as sessionId, + c.driverKey as driverKey, + c.startedAt as startedAt, + c.endedAt as endedAt, + c.durationSeconds as durationSeconds, sum( case - when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond - then d.durationSeconds - when u.startedAtEpochSecond <= d.startedAtEpochSecond - then u.endedAtEpochSecond - d.startedAtEpochSecond - when u.endedAtEpochSecond >= d.endedAtEpochSecond - then d.endedAtEpochSecond - u.startedAtEpochSecond + when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond + then c.durationSeconds + when u.startedAtEpochSecond <= c.startedAtEpochSecond + then u.endedAtEpochSecond - c.startedAtEpochSecond + when u.endedAtEpochSecond >= c.endedAtEpochSecond + then c.endedAtEpochSecond - u.startedAtEpochSecond else u.endedAtEpochSecond - u.startedAtEpochSecond end ) as unknownDurationSeconds, (sum( case - when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond - then d.durationSeconds - when u.startedAtEpochSecond <= d.startedAtEpochSecond - then u.endedAtEpochSecond - d.startedAtEpochSecond - when u.endedAtEpochSecond >= d.endedAtEpochSecond - then d.endedAtEpochSecond - u.startedAtEpochSecond + when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond + then c.durationSeconds + when u.startedAtEpochSecond <= c.startedAtEpochSecond + then u.endedAtEpochSecond - c.startedAtEpochSecond + when u.endedAtEpochSecond >= c.endedAtEpochSecond + then c.endedAtEpochSecond - u.startedAtEpochSecond else u.endedAtEpochSecond - u.startedAtEpochSecond end - ) * 100.0d) / d.durationSeconds as unknownCoveragePercent, - d.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId, - d.nextDrivingSourceIntervalId as nextDrivingSourceIntervalId, - d.previousRegistrationKey as previousRegistrationKey, - d.nextRegistrationKey as nextRegistrationKey, - d.previousVehicleKey as previousVehicleKey, - d.nextVehicleKey as nextVehicleKey -from TachographDrivingInterruptionIntervalInputEvent(durationSeconds > ${POTENTIAL_HOME_OVERNIGHT_STAY_THRESHOLD_SECONDS}) as d unidirectional, + ) * 100.0d) / c.durationSeconds as unknownCoveragePercent, + c.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId, + c.nextDrivingSourceIntervalId as nextDrivingSourceIntervalId, + c.previousRegistrationKey as previousRegistrationKey, + c.nextRegistrationKey as nextRegistrationKey, + c.previousVehicleKey as previousVehicleKey, + c.nextVehicleKey as nextVehicleKey +from TachographDrivingInterruptionVehicleChangeIntervalInputEvent as c unidirectional, TachographVuCardAbsentIntervalInputEvent#keepall as u -where u.driverKey = d.driverKey - and u.startedAtEpochSecond < d.endedAtEpochSecond - and u.endedAtEpochSecond > d.startedAtEpochSecond +where u.driverKey = c.driverKey + and u.startedAtEpochSecond < c.endedAtEpochSecond + and u.endedAtEpochSecond > c.startedAtEpochSecond group by - d.sessionId, - d.driverKey, - d.startedAt, - d.endedAt, - d.startedAtEpochSecond, - d.endedAtEpochSecond, - d.durationSeconds, - d.previousDrivingSourceIntervalId, - d.nextDrivingSourceIntervalId, - d.previousRegistrationKey, - d.nextRegistrationKey, - d.previousVehicleKey, - d.nextVehicleKey + c.sessionId, + c.driverKey, + c.startedAt, + c.endedAt, + c.startedAtEpochSecond, + c.endedAtEpochSecond, + c.durationSeconds, + c.previousDrivingSourceIntervalId, + c.nextDrivingSourceIntervalId, + c.previousRegistrationKey, + c.nextRegistrationKey, + c.previousVehicleKey, + c.nextVehicleKey having sum( case - when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond - then d.durationSeconds - when u.startedAtEpochSecond <= d.startedAtEpochSecond - then u.endedAtEpochSecond - d.startedAtEpochSecond - when u.endedAtEpochSecond >= d.endedAtEpochSecond - then d.endedAtEpochSecond - u.startedAtEpochSecond + when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond + then c.durationSeconds + when u.startedAtEpochSecond <= c.startedAtEpochSecond + then u.endedAtEpochSecond - c.startedAtEpochSecond + when u.endedAtEpochSecond >= c.endedAtEpochSecond + then c.endedAtEpochSecond - u.startedAtEpochSecond else u.endedAtEpochSecond - u.startedAtEpochSecond end -) * 100L >= d.durationSeconds * 95L; +) * 100L >= c.durationSeconds * 95L; diff --git a/src/test/java/at/procon/eventhub/tachographfilesession/api/TachographFileSessionControllerTest.java b/src/test/java/at/procon/eventhub/tachographfilesession/api/TachographFileSessionControllerTest.java index 9faad0c..eff07cc 100644 --- a/src/test/java/at/procon/eventhub/tachographfilesession/api/TachographFileSessionControllerTest.java +++ b/src/test/java/at/procon/eventhub/tachographfilesession/api/TachographFileSessionControllerTest.java @@ -84,6 +84,7 @@ class TachographFileSessionControllerTest { 1, 1, 1, + 1, 2, 1, List.of(new TachographEsperActivityIntervalEvent( @@ -150,6 +151,19 @@ class TachographFileSessionControllerTest { "VIN-1", "VIN-2" )), + List.of(new TachographEsperDrivingInterruptionIntervalEvent( + sessionId, + "12:123", + OffsetDateTime.parse("2026-05-12T10:00:00Z"), + OffsetDateTime.parse("2026-05-12T22:00:00Z"), + 43_200L, + "ACT-2", + "ACT-3", + "12:REG-1", + "12:REG-2", + "VIN-1", + "VIN-2" + )), List.of(new TachographEsperPotentialHomeOvernightStayIntervalEvent( sessionId, "12:123", @@ -258,6 +272,7 @@ class TachographFileSessionControllerTest { .andExpect(jsonPath("$.activityIntervalCount").value(2)) .andExpect(jsonPath("$.drivingInterruptionIntervalCount").value(1)) .andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervalCount").value(1)) + .andExpect(jsonPath("$.dailyWeeklyRestCandidateIntervalCount").value(1)) .andExpect(jsonPath("$.potentialHomeOvernightStayIntervalCount").value(1)) .andExpect(jsonPath("$.vuCardAbsentIntervalCount").value(1)) .andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousRegistrationKey").value("12:REG-1")) diff --git a/src/test/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilderTest.java b/src/test/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilderTest.java index 053d9d4..3c7e8bf 100644 --- a/src/test/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilderTest.java +++ b/src/test/java/at/procon/eventhub/tachographfilesession/service/DriverTimelineBuilderTest.java @@ -378,6 +378,46 @@ class DriverTimelineBuilderTest { assertThat(absentIntervals.get(0).nextVehicleKey()).isEqualTo("VIN-2"); } + @Test + void buildsDailyWeeklyRestCandidateIntervalsFromDrivingInterruptionIntervals() { + UUID sessionId = UUID.randomUUID(); + List drivingInterruptionIntervals = List.of( + new TachographEsperDrivingInterruptionIntervalEvent( + sessionId, + "12:123", + OffsetDateTime.parse("2026-05-01T10:00:00Z"), + OffsetDateTime.parse("2026-05-01T20:00:00Z"), + 36_000L, + "ACT-1", + "ACT-2", + "12:REG-1", + "12:REG-1", + "VIN-1", + "VIN-1" + ), + new TachographEsperDrivingInterruptionIntervalEvent( + sessionId, + "12:123", + OffsetDateTime.parse("2026-05-02T10:00:00Z"), + OffsetDateTime.parse("2026-05-02T18:00:00Z"), + 28_800L, + "ACT-3", + "ACT-4", + "12:REG-1", + "12:REG-1", + "VIN-1", + "VIN-1" + ) + ); + + List candidates = + builder.buildEsperDailyWeeklyRestCandidateIntervalEvents(drivingInterruptionIntervals, 540); + + assertThat(candidates).hasSize(1); + assertThat(candidates.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z")); + assertThat(candidates.get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T20:00:00Z")); + } + @Test void buildsEsperDrivingInterruptionIntervalEventsFromSignificantDrivingGaps() { DriverExtractionSession driver = new DriverExtractionSession( @@ -478,9 +518,9 @@ class DriverTimelineBuilderTest { "ACT-1", "ACT-2", "12:REG-1", - "12:REG-1", + "12:REG-2", "VIN-1", - "VIN-1" + "VIN-2" ) ); List vuCardAbsentIntervals = List.of( @@ -499,13 +539,17 @@ class DriverTimelineBuilderTest { ) ); + List dailyWeeklyRestCandidateIntervals = + builder.buildEsperDailyWeeklyRestCandidateIntervalEvents(interruptions, 720); + List drivingInterruptionVehicleChangeIntervals = + builder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(dailyWeeklyRestCandidateIntervals); List intervals = builder.buildEsperPotentialHomeOvernightStayIntervalEvents( - interruptions, - vuCardAbsentIntervals, - 720 + drivingInterruptionVehicleChangeIntervals, + vuCardAbsentIntervals ); + assertThat(drivingInterruptionVehicleChangeIntervals).hasSize(1); assertThat(intervals).hasSize(1); assertThat(intervals.get(0).sessionId()).isEqualTo(sessionId); assertThat(intervals.get(0).driverKey()).isEqualTo("12:123"); diff --git a/src/test/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingServiceTest.java b/src/test/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingServiceTest.java index 4a5d65d..32b0e9d 100644 --- a/src/test/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingServiceTest.java +++ b/src/test/java/at/procon/eventhub/tachographfilesession/service/TachographFileSessionProcessingServiceTest.java @@ -87,6 +87,7 @@ class TachographFileSessionProcessingServiceTest { assertThat(result.drivingIntervalCount()).isEqualTo(1); assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(0); assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0); + assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(0); assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0); assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2); assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1); @@ -169,7 +170,8 @@ class TachographFileSessionProcessingServiceTest { assertThat(result.activityIntervals().get(0).clippedToRequestedPeriod()).isTrue(); assertThat(result.drivingIntervalCount()).isEqualTo(2); assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(1); - assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(1); + assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0); + assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(0); assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0); assertThat(result.drivingInterruptionIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T09:00:00Z")); assertThat(result.drivingInterruptionIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z")); @@ -177,11 +179,6 @@ class TachographFileSessionProcessingServiceTest { assertThat(result.drivingInterruptionIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2"); assertThat(result.drivingInterruptionIntervals().get(0).previousVehicleKey()).isEqualTo("VIN-1"); assertThat(result.drivingInterruptionIntervals().get(0).nextVehicleKey()).isEqualTo("VIN-2"); - assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T09:00:00Z")); - assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).previousRegistrationKey()).isEqualTo("12:REG-1"); - assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2"); - assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).previousVehicleKey()).isEqualTo("VIN-1"); - assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextVehicleKey()).isEqualTo("VIN-2"); assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2); assertThat(result.vehicleUsageIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:45:00Z")); assertThat(result.vehicleUsageIntervals().get(0).odometerBeginKm()).isNull(); @@ -230,7 +227,7 @@ class TachographFileSessionProcessingServiceTest { ), List.of( new ExtractedCardActivityInterval("ACT-1", OffsetDateTime.parse("2026-05-01T08:00:00Z"), OffsetDateTime.parse("2026-05-01T10:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "a"), - new ExtractedCardActivityInterval("ACT-2", OffsetDateTime.parse("2026-05-02T00:00:00Z"), OffsetDateTime.parse("2026-05-02T00:30:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "b") + new ExtractedCardActivityInterval("ACT-2", OffsetDateTime.parse("2026-05-02T00:00:00Z"), OffsetDateTime.parse("2026-05-02T00:30:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-2", "VIN-2", "b") ), List.of(), List.of() @@ -257,6 +254,13 @@ class TachographFileSessionProcessingServiceTest { ) ); + assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(1); + assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(1); + assertThat(result.dailyWeeklyRestCandidateIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z")); + assertThat(result.dailyWeeklyRestCandidateIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T23:00:00Z")); + assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z")); + assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).previousRegistrationKey()).isEqualTo("12:REG-1"); + assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2"); assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(1); assertThat(result.potentialHomeOvernightStayIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z")); assertThat(result.potentialHomeOvernightStayIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T23:00:00Z"));