2020import java .util .HashMap ;
2121import java .util .List ;
2222import java .util .Map ;
23+ import java .util .Objects ;
2324import java .util .SortedSet ;
2425import java .util .concurrent .atomic .AtomicBoolean ;
2526import org .junit .jupiter .api .BeforeAll ;
3132import org .opentripplanner .transit .model .framework .Deduplicator ;
3233import org .opentripplanner .transit .model .framework .FeedScopedId ;
3334import org .opentripplanner .transit .model .framework .Result ;
35+ import org .opentripplanner .transit .model .network .StopPattern ;
3436import org .opentripplanner .transit .model .network .TripPattern ;
37+ import org .opentripplanner .transit .model .site .RegularStop ;
38+ import org .opentripplanner .transit .model .timetable .RealTimeState ;
3539import org .opentripplanner .transit .model .timetable .Trip ;
3640import org .opentripplanner .transit .model .timetable .TripIdAndServiceDate ;
3741import org .opentripplanner .transit .model .timetable .TripOnServiceDate ;
@@ -46,7 +50,7 @@ public class TimetableSnapshotTest {
4650 private static final ZoneId timeZone = ZoneIds .GMT ;
4751 public static final LocalDate SERVICE_DATE = LocalDate .of (2024 , 1 , 1 );
4852 private static Map <FeedScopedId , TripPattern > patternIndex ;
49- static String feedId ;
53+ private static String feedId ;
5054
5155 @ BeforeAll
5256 public static void setUp () throws Exception {
@@ -412,6 +416,130 @@ void testClear() {
412416 assertNotNull (snapshot .getRealtimeAddedRoute (pattern .getRoute ().getId ()));
413417 }
414418
419+ /**
420+ * This test checks that the original timetable is given to TransitLayerUpdater for previously
421+ * added patterns after the buffer is cleared.
422+ * <p>
423+ * Refer to bug #6197 for details.
424+ */
425+ @ Test
426+ void testTransitLayerUpdateAfterClear () {
427+ var resolver = new TimetableSnapshot ();
428+
429+ // make an updated trip
430+ var pattern = patternIndex .get (new FeedScopedId (feedId , "1.1" ));
431+ var trip = pattern .scheduledTripsAsStream ().findFirst ().orElseThrow ();
432+ var scheduledTimetable = pattern .getScheduledTimetable ();
433+ var updatedTripTimes = Objects
434+ .requireNonNull (scheduledTimetable .getTripTimes (trip ))
435+ .copyScheduledTimes ();
436+ for (var i = 0 ; i < updatedTripTimes .getNumStops (); ++i ) {
437+ updatedTripTimes .updateArrivalDelay (i , 30 );
438+ updatedTripTimes .updateDepartureDelay (i , 30 );
439+ }
440+ updatedTripTimes .setRealTimeState (RealTimeState .UPDATED );
441+ var realTimeTripUpdate = new RealTimeTripUpdate (
442+ pattern ,
443+ updatedTripTimes ,
444+ SERVICE_DATE ,
445+ null ,
446+ false ,
447+ false
448+ );
449+
450+ var addedDepartureStopTime = new StopTime ();
451+ var addedArrivalStopTime = new StopTime ();
452+ addedDepartureStopTime .setDepartureTime (0 );
453+ addedDepartureStopTime .setArrivalTime (0 );
454+ addedDepartureStopTime .setStop (RegularStop .of (new FeedScopedId (feedId , "XX" ), () -> 0 ).build ());
455+ addedArrivalStopTime .setDepartureTime (300 );
456+ addedArrivalStopTime .setArrivalTime (300 );
457+ addedArrivalStopTime .setStop (RegularStop .of (new FeedScopedId (feedId , "YY" ), () -> 1 ).build ());
458+ var addedStopTimes = List .of (addedDepartureStopTime , addedArrivalStopTime );
459+ var addedStopPattern = new StopPattern (addedStopTimes );
460+ var route = patternIndex .values ().stream ().findFirst ().orElseThrow ().getRoute ();
461+ var addedTripPattern = TripPattern
462+ .of (new FeedScopedId (feedId , "1.1" ))
463+ .withRoute (route )
464+ .withStopPattern (addedStopPattern )
465+ .withCreatedByRealtimeUpdater (true )
466+ .build ();
467+ var addedTripTimes = TripTimesFactory .tripTimes (
468+ Trip .of (new FeedScopedId (feedId , "addedTrip" )).withRoute (route ).build (),
469+ addedStopTimes ,
470+ new Deduplicator ()
471+ );
472+ var addedTripUpdate = new RealTimeTripUpdate (
473+ addedTripPattern ,
474+ addedTripTimes ,
475+ SERVICE_DATE ,
476+ null ,
477+ true ,
478+ false
479+ );
480+
481+ var transitLayerUpdater = new TransitLayerUpdater (null ) {
482+ int count = 0 ;
483+
484+ /**
485+ * Test that the TransitLayerUpdater receives correct updated timetables upon commit
486+ * <p>
487+ * This method is called 3 times.
488+ * When count = 0, the buffer contains one added and one updated trip, and the timetables
489+ * should reflect this fact.
490+ * When count = 1, the buffer is empty, however, this method should still receive the
491+ * timetables of the previous added and updated patterns in order to restore them to the
492+ * initial scheduled timetable.
493+ * When count = 2, the buffer is still empty, and no changes should be made.
494+ */
495+ @ Override
496+ public void update (
497+ Collection <Timetable > updatedTimetables ,
498+ Map <TripPattern , SortedSet <Timetable >> timetables
499+ ) {
500+ assertThat (updatedTimetables ).hasSize (count == 2 ? 0 : 2 );
501+
502+ updatedTimetables .forEach (timetable -> {
503+ var timetablePattern = timetable .getPattern ();
504+ assertEquals (SERVICE_DATE , timetable .getServiceDate ());
505+ if (timetablePattern == pattern ) {
506+ if (count == 1 ) {
507+ // the timetable for the existing pattern should revert to the original
508+ assertEquals (scheduledTimetable .getTripTimes (), timetable .getTripTimes ());
509+ } else {
510+ // the timetable for the existing pattern should contain the modified times
511+ assertEquals (
512+ RealTimeState .UPDATED ,
513+ Objects .requireNonNull (timetable .getTripTimes (trip )).getRealTimeState ()
514+ );
515+ }
516+ } else if (timetablePattern == addedTripPattern ) {
517+ if (count == 1 ) {
518+ // the timetable for the added pattern should be empty after clearing
519+ assertThat (timetable .getTripTimes ()).isEmpty ();
520+ } else {
521+ // the timetable for the added pattern should contain the times for 1 added trip
522+ assertThat (timetable .getTripTimes ()).hasSize (1 );
523+ }
524+ } else {
525+ throw new RuntimeException ("unknown pattern passed to transit layer updater" );
526+ }
527+ });
528+ ++count ;
529+ }
530+ };
531+
532+ resolver .update (realTimeTripUpdate );
533+ resolver .update (addedTripUpdate );
534+ resolver .commit (transitLayerUpdater , true );
535+
536+ resolver .clear (feedId );
537+ resolver .commit (transitLayerUpdater , true );
538+
539+ resolver .clear (feedId );
540+ resolver .commit (transitLayerUpdater , true );
541+ }
542+
415543 private static TimetableSnapshot createCommittedSnapshot () {
416544 TimetableSnapshot timetableSnapshot = new TimetableSnapshot ();
417545 return timetableSnapshot .commit (null , true );
0 commit comments