Skip to content

Commit

Permalink
add test for opentripplanner#6242
Browse files Browse the repository at this point in the history
  • Loading branch information
miklcct committed Nov 8, 2024
1 parent 39c0aac commit 9673c2e
Show file tree
Hide file tree
Showing 6 changed files with 405 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ public class TimetableSnapshotSource implements TimetableSnapshotProvider {
private final ZoneId timeZone;

/**
* Long-lived transit editor service that has access to the timetable snapshot buffer.
* This differs from the usual use case where the transit service refers to the latest published
* Long-lived transit editor service that has access to the timetable snapshot buffer. This
* differs from the usual use case where the transit service refers to the latest published
* timetable snapshot.
*/
private final TransitEditorService transitEditorService;
Expand All @@ -114,10 +114,9 @@ public TimetableSnapshotSource(
}

/**
* Constructor is package local to allow unit-tests to provide their own clock, not using system
* time.
* Constructor to allow tests to provide their own clock, not using system time.
*/
TimetableSnapshotSource(
public TimetableSnapshotSource(
TimetableSnapshotSourceParameters parameters,
TimetableRepository timetableRepository,
Supplier<LocalDate> localDateNow
Expand Down Expand Up @@ -148,8 +147,9 @@ public TimetableSnapshotSource(
*
* @param backwardsDelayPropagationType Defines when delays are propagated to previous stops and
* if these stops are given the NO_DATA flag.
* @param updateIncrementality Determines the incrementality of the updates. FULL updates clear the buffer
* of all previous updates for the given feed id.
* @param updateIncrementality Determines the incrementality of the updates. FULL updates
* clear the buffer of all previous updates for the given
* feed id.
* @param updates GTFS-RT TripUpdate's that should be applied atomically
*/
public UpdateResult applyTripUpdates(
Expand Down Expand Up @@ -304,10 +304,10 @@ private void purgePatternModifications(
);
if (
!isPreviouslyAddedTrip(tripId, pattern, serviceDate) ||
(
tripScheduleRelationship != ScheduleRelationship.CANCELED &&
tripScheduleRelationship != ScheduleRelationship.DELETED
)
(
tripScheduleRelationship != ScheduleRelationship.CANCELED &&
tripScheduleRelationship != ScheduleRelationship.DELETED
)
) {
// Remove previous realtime updates for this trip. This is necessary to avoid previous
// stop pattern modifications from persisting. If a trip was previously added with the ScheduleRelationship
Expand Down Expand Up @@ -342,8 +342,8 @@ public TimetableSnapshot getTimetableSnapshot() {

/**
* @return the current timetable snapshot buffer that contains pending changes (not yet published
* in a snapshot). This should be used in the context of an updater to build a TransitEditorService
* that sees all the changes applied so far by real-time updates.
* in a snapshot). This should be used in the context of an updater to build a
* TransitEditorService that sees all the changes applied so far by real-time updates.
*/
public TimetableSnapshot getTimetableSnapshotBuffer() {
return snapshotManager.getTimetableSnapshotBuffer();
Expand Down Expand Up @@ -697,7 +697,7 @@ private Route createRoute(TripDescriptor tripDescriptor, FeedScopedId tripId) {
// the route in this update doesn't already exist, but the update contains the information so it will be created
if (
tripDescriptor.hasExtension(MfdzRealtimeExtensions.tripDescriptor) &&
!routeExists(tripId.getFeedId(), tripDescriptor)
!routeExists(tripId.getFeedId(), tripDescriptor)
) {
FeedScopedId routeId = new FeedScopedId(tripId.getFeedId(), tripDescriptor.getRouteId());

Expand Down Expand Up @@ -805,7 +805,7 @@ private Result<UpdateSuccess, UpdateError> addTripToGraphAndBuffer(
debug(
trip.getId(),
"ADDED trip has invalid arrival time (compared to start date in " +
"TripDescriptor), skipping."
"TripDescriptor), skipping."
);
return UpdateError.result(trip.getId(), INVALID_ARRIVAL_TIME);
}
Expand All @@ -819,7 +819,7 @@ private Result<UpdateSuccess, UpdateError> addTripToGraphAndBuffer(
debug(
trip.getId(),
"ADDED trip has invalid departure time (compared to start date in " +
"TripDescriptor), skipping."
"TripDescriptor), skipping."
);
return UpdateError.result(trip.getId(), INVALID_DEPARTURE_TIME);
}
Expand Down Expand Up @@ -1090,7 +1090,7 @@ private Result<UpdateSuccess, UpdateError> handleCanceledTrip(
) {
var canceledPreviouslyAddedTrip =
incrementality != FULL_DATASET &&
cancelPreviouslyAddedTrip(tripId, serviceDate, cancelationType);
cancelPreviouslyAddedTrip(tripId, serviceDate, cancelationType);

// if previously an added trip was removed, there can't be a scheduled trip to remove
if (canceledPreviouslyAddedTrip) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@
import static org.opentripplanner.transit.model.basic.TransitMode.FERRY;
import static org.opentripplanner.transit.model.timetable.OccupancyStatus.FEW_SEATS_AVAILABLE;

import com.google.transit.realtime.GtfsRealtime;
import jakarta.ws.rs.core.Response;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.Instant;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Comparator;
Expand All @@ -42,7 +45,9 @@
import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.framework.model.Grams;
import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore;
import org.opentripplanner.model.FeedInfo;
import org.opentripplanner.model.calendar.CalendarServiceData;
import org.opentripplanner.model.fare.FareMedium;
import org.opentripplanner.model.fare.FareProduct;
import org.opentripplanner.model.fare.ItineraryFares;
Expand All @@ -60,6 +65,10 @@
import org.opentripplanner.routing.alertpatch.EntitySelector;
import org.opentripplanner.routing.alertpatch.TimePeriod;
import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitLayer;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerMapper;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerUpdater;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graphfinder.GraphFinder;
Expand Down Expand Up @@ -91,11 +100,18 @@
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.model.timetable.RealTimeTripTimes;
import org.opentripplanner.transit.model.timetable.Trip;
import org.opentripplanner.transit.model.timetable.TripTimesFactory;
import org.opentripplanner.transit.service.DefaultTransitService;
import org.opentripplanner.transit.service.TimetableRepository;
import org.opentripplanner.transit.service.TransitEditorService;
import org.opentripplanner.transit.service.TransitService;
import org.opentripplanner.updater.GtfsRealtimeFuzzyTripMatcher;
import org.opentripplanner.updater.TimetableSnapshotSourceParameters;
import org.opentripplanner.updater.trip.BackwardsDelayPropagationType;
import org.opentripplanner.updater.trip.TimetableSnapshotSource;
import org.opentripplanner.updater.trip.TripUpdateBuilder;
import org.opentripplanner.updater.trip.UpdateIncrementality;
import org.opentripplanner.utils.collection.ListUtils;

class GraphQLIntegrationTest {
Expand All @@ -116,6 +132,10 @@ class GraphQLIntegrationTest {
.map(p -> (RegularStop) p.stop)
.toList();
private static final Route ROUTE = TimetableRepositoryForTest.route("a-route").build();
private static final String ADDED_TRIP_ID = "ADDED_TRIP";
private static final String REPLACEMENT_TRIP_ID = "REPLACEMENT_TRIP";
public static final ZoneId TIME_ZONE = ZoneIds.BERLIN;
public static final String FEED_ID = TimetableRepositoryForTest.FEED_ID;

private static VehicleRentalStation VEHICLE_RENTAL_STATION = new TestVehicleRentalStationBuilder()
.withVehicles(10)
Expand All @@ -137,6 +157,8 @@ class GraphQLIntegrationTest {
static final Instant ALERT_END_TIME = ALERT_START_TIME.plus(1, ChronoUnit.DAYS);
private static final int TEN_MINUTES = 10 * 60;

private static final LocalDate SERVICE_DATE = LocalDate.of(2024, 1, 1);

private static GraphQLRequestContext context;

private static final Deduplicator DEDUPLICATOR = new Deduplicator();
Expand All @@ -157,38 +179,59 @@ static void setup() {
List.of()
);

var siteRepository = TEST_MODEL.siteRepositoryBuilder();
STOP_LOCATIONS.forEach(siteRepository::withRegularStop);
var model = siteRepository.build();
var timetableRepository = new TimetableRepository(model, DEDUPLICATOR);
var siteRepositoryBuilder = TEST_MODEL.siteRepositoryBuilder();
STOP_LOCATIONS.forEach(siteRepositoryBuilder::withRegularStop);
var siteRepository = siteRepositoryBuilder.build();
var timetableRepository = new TimetableRepository(siteRepository, DEDUPLICATOR);

var trip = TimetableRepositoryForTest
.trip("123")
.withHeadsign(I18NString.of("Trip Headsign"))
.build();
var stopTimes = TEST_MODEL.stopTimesEvery5Minutes(3, trip, T11_00);
var tripTimes = TripTimesFactory.tripTimes(trip, stopTimes, DEDUPLICATOR);

var calendar = new CalendarServiceData();
FeedScopedId serviceId = calendar.getOrCreateServiceIdForDate(SERVICE_DATE);

var tripToBeReplaced = TimetableRepositoryForTest
.trip(REPLACEMENT_TRIP_ID)
.withServiceId(serviceId)
.build();
final TripPattern pattern = TEST_MODEL
.pattern(BUS)
.withScheduledTimeTableBuilder(builder -> builder.addTripTimes(tripTimes))
.withScheduledTimeTableBuilder(builder ->
builder
.addTripTimes(tripTimes)
.addTripTimes(
TripTimesFactory.tripTimes(
tripToBeReplaced,
TEST_MODEL.stopTimesEvery5Minutes(3, tripToBeReplaced, T11_30),
DEDUPLICATOR
)
)
)
.build();

timetableRepository.addTripPattern(id("pattern-1"), pattern);

var feedId = "testfeed";
var feedInfo = FeedInfo.dummyForTest(feedId);
var feedInfo = FeedInfo.dummyForTest(FEED_ID);
timetableRepository.addFeedInfo(feedInfo);

var agency = Agency
.of(new FeedScopedId(feedId, "agency-xx"))
.of(new FeedScopedId(FEED_ID, "agency-xx"))
.withName("speedtransit")
.withUrl("www.otp-foo.bar")
.withTimezone("Europe/Berlin")
.build();
timetableRepository.addAgency(agency);

timetableRepository.initTimeZone(ZoneIds.BERLIN);
timetableRepository.initTimeZone(TIME_ZONE);
var serviceCodes = timetableRepository.getServiceCodes();
serviceCodes.put(serviceId, serviceCodes.size());
timetableRepository.updateCalendarServiceData(true, calendar, DataImportIssueStore.NOOP);
timetableRepository.index();

var routes = Arrays
.stream(TransitMode.values())
.sorted(Comparator.comparing(Enum::name))
Expand Down Expand Up @@ -226,6 +269,29 @@ public Set<Route> getRoutesForStop(StopLocation stop) {
};
routes.forEach(transitService::addRoutes);

timetableRepository.setTransitLayer(
TransitLayerMapper.map(TransitTuningParameters.FOR_TEST, timetableRepository)
);
timetableRepository.setRealtimeTransitLayer(
new TransitLayer(timetableRepository.getTransitLayer())
);
var transitLayerUpdater = new TransitLayerUpdater(transitService);
timetableRepository.setTransitLayerUpdater(transitLayerUpdater);

var timetableSnapshotProvider = new TimetableSnapshotSource(
TimetableSnapshotSourceParameters.DEFAULT,
timetableRepository,
() -> SERVICE_DATE
);
timetableSnapshotProvider.applyTripUpdates(
new GtfsRealtimeFuzzyTripMatcher(transitService),
BackwardsDelayPropagationType.REQUIRED_NO_DATA,
UpdateIncrementality.FULL_DATASET,
List.of(getAddedTrip(busRoute), getReplacementTrip(tripToBeReplaced)),
FEED_ID
);
timetableSnapshotProvider.flushBuffer();

var step1 = walkStep("street")
.withRelativeDirection(RelativeDirection.DEPART)
.withAbsoluteDirection(20)
Expand Down Expand Up @@ -323,6 +389,35 @@ public Set<Route> getRoutesForStop(StopLocation stop) {
);
}

private static GtfsRealtime.TripUpdate getAddedTrip(Route route) {
var tripUpdateBuilder = new TripUpdateBuilder(
route.getId().getId(),
ADDED_TRIP_ID,
SERVICE_DATE,
GtfsRealtime.TripDescriptor.ScheduleRelationship.ADDED,
TIME_ZONE
);
tripUpdateBuilder.addStopTime(A.stop.getId().getId(), 0);
tripUpdateBuilder.addStopTime(B.stop.getId().getId(), 300);
tripUpdateBuilder.addStopTime(C.stop.getId().getId(), 600);
tripUpdateBuilder.addStopTime(D.stop.getId().getId(), 900);
return tripUpdateBuilder.build();
}

private static GtfsRealtime.TripUpdate getReplacementTrip(Trip trip) {
var tripUpdateBuilder = new TripUpdateBuilder(
trip.getId().getId(),
SERVICE_DATE,
GtfsRealtime.TripDescriptor.ScheduleRelationship.REPLACEMENT,
TIME_ZONE
);
tripUpdateBuilder.addStopTime(A.stop.getId().getId(), 0);
tripUpdateBuilder.addStopTime(B.stop.getId().getId(), 300);
tripUpdateBuilder.addStopTime(C.stop.getId().getId(), 600);
tripUpdateBuilder.addStopTime(D.stop.getId().getId(), 900);
return tripUpdateBuilder.build();
}

private static BikeAccess bikesAllowed(TransitMode m) {
return switch (m.ordinal() % 3) {
case 0 -> BikeAccess.ALLOWED;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,21 @@ public TripUpdateBuilder(
this.midnight = ServiceDateUtils.asStartOfService(serviceDate, zoneId);
}

public TripUpdateBuilder addStopTime(String stopId, int minutes) {
public TripUpdateBuilder(
String routeId,
String tripId,
LocalDate serviceDate,
GtfsRealtime.TripDescriptor.ScheduleRelationship scheduleRelationship,
ZoneId zoneId
) {
this(tripId, serviceDate, scheduleRelationship, zoneId);
tripDescriptorBuilder.setRouteId(routeId);
}

public TripUpdateBuilder addStopTime(String stopId, int secondsFromMidnight) {
return addStopTime(
stopId,
minutes,
secondsFromMidnight,
NO_VALUE,
NO_DELAY,
NO_DELAY,
Expand All @@ -49,10 +60,14 @@ public TripUpdateBuilder addStopTime(String stopId, int minutes) {
);
}

public TripUpdateBuilder addStopTime(String stopId, int minutes, DropOffPickupType pickDrop) {
public TripUpdateBuilder addStopTime(
String stopId,
int secondsFromMidnight,
DropOffPickupType pickDrop
) {
return addStopTime(
stopId,
minutes,
secondsFromMidnight,
NO_VALUE,
NO_DELAY,
NO_DELAY,
Expand Down Expand Up @@ -122,7 +137,7 @@ public TripUpdateBuilder addRawStopTime(StopTimeUpdate stopTime) {

private TripUpdateBuilder addStopTime(
String stopId,
int minutes,
int secondsFromMidnight,
int stopSequence,
int arrivalDelay,
int departureDelay,
Expand Down Expand Up @@ -153,8 +168,8 @@ private TripUpdateBuilder addStopTime(
final GtfsRealtime.TripUpdate.StopTimeEvent.Builder arrivalBuilder = stopTimeUpdateBuilder.getArrivalBuilder();
final GtfsRealtime.TripUpdate.StopTimeEvent.Builder departureBuilder = stopTimeUpdateBuilder.getDepartureBuilder();

if (minutes > NO_VALUE) {
var epochSeconds = midnight.plusHours(8).plusMinutes(minutes).toEpochSecond();
if (secondsFromMidnight > NO_VALUE) {
var epochSeconds = midnight.plusSeconds(secondsFromMidnight).toEpochSecond();
arrivalBuilder.setTime(epochSeconds);
departureBuilder.setTime(epochSeconds);
}
Expand Down
Loading

0 comments on commit 9673c2e

Please sign in to comment.