Skip to content

Commit

Permalink
Merge pull request opentripplanner#5877 from Skanetrafiken/siri-timet…
Browse files Browse the repository at this point in the history
…able-test-nicer-assertions

Add nicer assertions to SiriTimetableSnapshotSourceTest
  • Loading branch information
habrahamsson-skanetrafiken authored Jun 3, 2024
2 parents 0695d7d + 397818f commit f535524
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.junit.jupiter.api.Test;
import org.opentripplanner.DateTimeHelper;
import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore;
import org.opentripplanner.model.PickDrop;
import org.opentripplanner.model.StopTime;
import org.opentripplanner.model.calendar.CalendarServiceData;
import org.opentripplanner.transit.model._data.TransitModelForTest;
Expand All @@ -29,6 +28,7 @@
import org.opentripplanner.transit.model.timetable.TripOnServiceDate;
import org.opentripplanner.transit.model.timetable.TripTimes;
import org.opentripplanner.transit.model.timetable.TripTimesFactory;
import org.opentripplanner.transit.model.timetable.TripTimesStringBuilder;
import org.opentripplanner.transit.service.DefaultTransitService;
import org.opentripplanner.transit.service.StopModel;
import org.opentripplanner.transit.service.TransitModel;
Expand Down Expand Up @@ -73,10 +73,11 @@ void testAddJourney() {
var result = env.applyEstimatedTimetable(updates);

assertEquals(1, result.successful());
var tripTimes = env.getTripTimesForTrip("newJourney");
assertEquals(RealTimeState.ADDED, tripTimes.getRealTimeState());
assertEquals(2 * 60, tripTimes.getDepartureTime(0));
assertEquals(4 * 60, tripTimes.getDepartureTime(1));
assertEquals("ADDED | C1 [R] 0:02 0:02 | D1 0:04 0:04", env.getRealtimeTimetable("newJourney"));
assertEquals(
"SCHEDULED | C1 0:01 0:01 | D1 0:03 0:03",
env.getScheduledTimetable("newJourney")
);
}

@Test
Expand All @@ -98,14 +99,13 @@ void testReplaceJourney() {

assertEquals(1, result.successful());

var tripTimes = env.getTripTimesForTrip("newJourney");
var pattern = env.getPatternForTrip(env.id("newJourney"));
assertEquals(RealTimeState.ADDED, tripTimes.getRealTimeState());
assertEquals(2 * 60, tripTimes.getDepartureTime(0));
assertEquals(4 * 60, tripTimes.getDepartureTime(1));
assertEquals(env.stopA1.getId(), pattern.getStop(0).getId());
assertEquals(env.stopC1.getId(), pattern.getStop(1).getId());
assertEquals("ADDED | A1 [R] 0:02 0:02 | C1 0:04 0:04", env.getRealtimeTimetable("newJourney"));
assertEquals(
"SCHEDULED | A1 0:01 0:01 | C1 0:03 0:03",
env.getScheduledTimetable("newJourney")
);

// Original trip should not get canceled
var originalTripTimes = env.getTripTimesForTrip(env.trip1);
assertEquals(RealTimeState.SCHEDULED, originalTripTimes.getRealTimeState());
}
Expand All @@ -123,6 +123,10 @@ void testUpdateJourneyWithDatedVehicleJourneyRef() {
var result = env.applyEstimatedTimetable(updates);
assertEquals(1, result.successful());
assertTripUpdated(env);
assertEquals(
"UPDATED | A1 0:00:15 0:00:15 | B1 0:00:25 0:00:25",
env.getRealtimeTimetable(env.trip1)
);
}

/**
Expand Down Expand Up @@ -152,7 +156,7 @@ void testUpdateJourneyWithoutJourneyRef() {
var updates = updatedJourneyBuilder(env).buildEstimatedTimetableDeliveries();
var result = env.applyEstimatedTimetable(updates);
assertEquals(0, result.successful());
assertFailure(result, UpdateError.UpdateErrorType.TRIP_NOT_FOUND);
assertFailure(UpdateError.UpdateErrorType.TRIP_NOT_FOUND, result);
}

/**
Expand Down Expand Up @@ -191,7 +195,7 @@ void testUpdateJourneyWithFuzzyMatchingAndMissingAimedDepartureTime() {

var result = env.applyEstimatedTimetableWithFuzzyMatcher(updates);
assertEquals(0, result.successful(), "Should fail gracefully");
assertFailure(result, UpdateError.UpdateErrorType.NO_FUZZY_TRIP_MATCH);
assertFailure(UpdateError.UpdateErrorType.NO_FUZZY_TRIP_MATCH, result);
}

/**
Expand All @@ -214,15 +218,10 @@ void testChangeQuay() {
var result = env.applyEstimatedTimetable(updates);

assertEquals(1, result.successful());

var pattern = env.getPatternForTrip(env.trip1.getId());
var tripTimes = env.getTripTimesForTrip(env.trip1);
assertEquals(RealTimeState.MODIFIED, tripTimes.getRealTimeState());
assertEquals(11, tripTimes.getScheduledDepartureTime(0));
assertEquals(15, tripTimes.getDepartureTime(0));
assertEquals(20, tripTimes.getScheduledArrivalTime(1));
assertEquals(33, tripTimes.getArrivalTime(1));
assertEquals(env.stopB2, pattern.getStop(1));
assertEquals(
"MODIFIED | A1 [R] 0:00:15 0:00:15 | B2 0:00:33 0:00:33",
env.getRealtimeTimetable(env.trip1)
);
}

@Test
Expand All @@ -245,12 +244,10 @@ void testCancelStop() {
var result = env.applyEstimatedTimetable(updates);

assertEquals(1, result.successful());

var pattern = env.getPatternForTrip(env.trip2.getId());

assertEquals(PickDrop.SCHEDULED, pattern.getAlightType(0));
assertEquals(PickDrop.CANCELLED, pattern.getAlightType(1));
assertEquals(PickDrop.SCHEDULED, pattern.getAlightType(2));
assertEquals(
"MODIFIED | A1 0:01:01 0:01:01 | B1 [C] 0:01:10 0:01:11 | C1 0:01:30 0:01:30",
env.getRealtimeTimetable(env.trip2)
);
}

// TODO: support this
Expand Down Expand Up @@ -278,23 +275,10 @@ void testAddStop() {
var result = env.applyEstimatedTimetable(updates);

assertEquals(1, result.successful());

var pattern = env.getPatternForTrip(env.trip1.getId());
var tripTimes = env.getTripTimesForTrip(env.trip1);
assertEquals(RealTimeState.MODIFIED, tripTimes.getRealTimeState());
assertEquals(11, tripTimes.getScheduledDepartureTime(0));
assertEquals(15, tripTimes.getDepartureTime(0));

// Should it work to get the scheduled times from an extra call?
assertEquals(19, tripTimes.getScheduledArrivalTime(1));
assertEquals(24, tripTimes.getScheduledDepartureTime(1));

assertEquals(20, tripTimes.getDepartureTime(1));
assertEquals(25, tripTimes.getDepartureTime(1));

assertEquals(20, tripTimes.getScheduledArrivalTime(2));
assertEquals(33, tripTimes.getArrivalTime(2));
assertEquals(List.of(env.stopA1, env.stopD1, env.stopB1), pattern.getStops());
assertEquals(
"MODIFIED | A1 0:00:15 0:00:15 | D1 [C] 0:00:20 0:00:25 | B1 0:00:33 0:00:33",
env.getRealtimeTimetable(env.trip1)
);
}

/////////////////
Expand All @@ -311,7 +295,7 @@ void testNotMonitored() {

var result = env.applyEstimatedTimetable(updates);

assertFailure(result, UpdateError.UpdateErrorType.NOT_MONITORED);
assertFailure(UpdateError.UpdateErrorType.NOT_MONITORED, result);
}

@Test
Expand All @@ -336,7 +320,7 @@ void testReplaceJourneyWithoutEstimatedVehicleJourneyCode() {
var result = env.applyEstimatedTimetable(updates);

// TODO: this should have a more specific error type
assertFailure(result, UpdateError.UpdateErrorType.UNKNOWN);
assertFailure(UpdateError.UpdateErrorType.UNKNOWN, result);
}

@Test
Expand All @@ -356,7 +340,7 @@ void testNegativeHopTime() {

var result = env.applyEstimatedTimetable(updates);

assertFailure(result, UpdateError.UpdateErrorType.NEGATIVE_HOP_TIME);
assertFailure(UpdateError.UpdateErrorType.NEGATIVE_HOP_TIME, result);
}

@Test
Expand All @@ -379,7 +363,7 @@ void testNegativeDwellTime() {

var result = env.applyEstimatedTimetable(updates);

assertFailure(result, UpdateError.UpdateErrorType.NEGATIVE_DWELL_TIME);
assertFailure(UpdateError.UpdateErrorType.NEGATIVE_DWELL_TIME, result);
}

// TODO: support this
Expand All @@ -405,30 +389,29 @@ void testExtraUnknownStop() {

var result = env.applyEstimatedTimetable(updates);

assertFailure(result, UpdateError.UpdateErrorType.INVALID_STOP_SEQUENCE);
assertFailure(UpdateError.UpdateErrorType.INVALID_STOP_SEQUENCE, result);
}

private void assertFailure(UpdateResult result, UpdateError.UpdateErrorType errorType) {
assertEquals(result.failures().keySet(), Set.of(errorType));
private void assertFailure(UpdateError.UpdateErrorType expectedError, UpdateResult result) {
assertEquals(Set.of(expectedError), result.failures().keySet());
}

private static SiriEtBuilder updatedJourneyBuilder(RealtimeTestEnvironment env) {
return new SiriEtBuilder(env.getDateTimeHelper())
.withRecordedCalls(builder ->
builder.call(env.stopA1).departAimedActual("00:00:11", "00:00:15")
)
.withEstimatedCalls(builder ->
builder.call(env.stopB1).arriveAimedExpected("00:00:20", "00:00:25")
builder
.call(env.stopA1)
.departAimedExpected("00:00:11", "00:00:15")
.call(env.stopB1)
.arriveAimedExpected("00:00:20", "00:00:25")
);
}

private static void assertTripUpdated(RealtimeTestEnvironment env) {
var tripTimes = env.getTripTimesForTrip(env.trip1);
assertEquals(RealTimeState.UPDATED, tripTimes.getRealTimeState());
assertEquals(11, tripTimes.getScheduledDepartureTime(0));
assertEquals(15, tripTimes.getDepartureTime(0));
assertEquals(20, tripTimes.getScheduledArrivalTime(1));
assertEquals(25, tripTimes.getArrivalTime(1));
assertEquals(
"UPDATED | A1 0:00:15 0:00:15 | B1 0:00:25 0:00:25",
env.getRealtimeTimetable(env.trip1)
);
}

private static class RealtimeTestEnvironment {
Expand Down Expand Up @@ -565,6 +548,32 @@ public TripTimes getTripTimesForTrip(Trip trip) {
return getTripTimesForTrip(trip.getId(), serviceDate);
}

public String getRealtimeTimetable(String tripId) {
return getRealtimeTimetable(id(tripId), serviceDate);
}

public String getRealtimeTimetable(Trip trip) {
return getRealtimeTimetable(trip.getId(), serviceDate);
}

public String getRealtimeTimetable(FeedScopedId tripId, LocalDate serviceDate) {
var tt = getTripTimesForTrip(tripId, serviceDate);
var pattern = getPatternForTrip(tripId);

return TripTimesStringBuilder.encodeTripTimes(tt, pattern);
}

public String getScheduledTimetable(String tripId) {
return getScheduledTimetable(id(tripId));
}

public String getScheduledTimetable(FeedScopedId tripId) {
var pattern = getPatternForTrip(tripId);
var tt = pattern.getScheduledTimetable().getTripTimes(tripId);

return TripTimesStringBuilder.encodeTripTimes(tt, pattern);
}

/**
* Find the current TripTimes for a trip id on the default serviceDate
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.opentripplanner.transit.model.timetable;

import java.util.ArrayList;
import org.opentripplanner.framework.time.TimeUtils;
import org.opentripplanner.transit.model.network.TripPattern;

public class TripTimesStringBuilder {

/**
* This encodes the trip times and information about stops in a readable way in order to simplify
* testing/debugging. The format of the outputput string is:
*
* <pre>
* REALTIME_STATE | stop1 [FLAGS] arrivalTime departureTime | stop2 ...
*
* Where flags are:
* C: Canceled
* R: Recorded
* PI: Prediction Inaccurate
* ND: No Data
* </pre>
*
* @throws IllegalStateException if TripTimes does not match the TripPattern
*/
public static String encodeTripTimes(TripTimes tripTimes, TripPattern pattern) {
var stops = pattern.getStops();

if (tripTimes.getNumStops() != stops.size()) {
throw new IllegalArgumentException(
"TripTimes and TripPattern have different number of stops"
);
}

StringBuilder s = new StringBuilder(tripTimes.getRealTimeState().toString());
for (int i = 0; i < tripTimes.getNumStops(); i++) {
var depart = tripTimes.getDepartureTime(i);
var arrive = tripTimes.getArrivalTime(i);
var flags = new ArrayList<String>();
if (tripTimes.isCancelledStop(i)) {
flags.add("C");
}
if (tripTimes.isRecordedStop(i)) {
flags.add("R");
}
if (tripTimes.isPredictionInaccurate(i)) {
flags.add("PI");
}
if (tripTimes.isNoDataStop(i)) {
flags.add("ND");
}

s.append(" | ").append(stops.get(i).getName());
if (!flags.isEmpty()) {
s.append(" [").append(String.join(",", flags)).append("]");
}
s
.append(" ")
.append(TimeUtils.timeToStrCompact(arrive))
.append(" ")
.append(TimeUtils.timeToStrCompact(depart));
}
return s.toString();
}
}

0 comments on commit f535524

Please sign in to comment.