diff --git a/RULES.md b/RULES.md
index aa315515..2bf880b0 100644
--- a/RULES.md
+++ b/RULES.md
@@ -54,6 +54,7 @@ Rules are declared in the [`ValidationRules` class](https://github.com/CUTR-at-U
| [E050](#E050) | `timestamp` is in the future
| [E051](#E051) | GTFS-rt `stop_sequence` not found in GTFS data
| [E052](#E052) | `vehicle.id` is not unique
+| [E053](#E053) | `start_time` for trip has changed
### Table of Warnings
@@ -717,6 +718,16 @@ From [VehiclePosition.VehicleDescriptor](https://github.com/google/transit/blob/
#### References:
* [`vehicle.id`](https://github.com/google/transit/blob/master/gtfs-realtime/spec/en/reference.md#message-vehicledescriptor)
+
+
+### E053 - `start_time` for frequency-based trip has changed
+
+A trip that is defined in frequencies.txt and has exact_times=0 or empty should have the same start_time in the descriptor for it's entire trip instance. A trip instance is defined as one journey of the vehicle from the starting stop_sequence for a trip_id in stop_times.txt to the ending stop_sequence for that same trip_id.
+
+From [TripUpdate.TripDescriptor](https://github.com/google/transit/blob/master/gtfs-realtime/spec/en/reference.md#message-tripdescriptor) for `start_time`:
+
+>If the trip corresponds to exact_times=0, then its start_time may be arbitrary, and is initially expected to be the first departure of the trip. Once established, the start_time of this frequency-based exact_times=0 trip should be considered immutable, even if the first departure time changes
+
# Warnings
diff --git a/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/ValidationRules.java b/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/ValidationRules.java
index 4e7b2a61..a85a5713 100644
--- a/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/ValidationRules.java
+++ b/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/ValidationRules.java
@@ -267,6 +267,10 @@ public class ValidationRules {
public static final ValidationRule E052 = new ValidationRule("E052", "ERROR", "vehicle.id is not unique",
"Each vehicle should have a unique ID",
"which is used by more than one vehicle in the feed");
+
+ public static final ValidationRule E053 = new ValidationRule("E053", "ERROR", "start_time for frequency-based trip changed",
+ "An exact_times = 0 frequencies.txt trip should have the same start_time through it's trip",
+ "exact_times=0 must be immutable");
private static List mAllRules = new ArrayList<>();
diff --git a/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/rules/FrequencyTypeZeroValidator.java b/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/rules/FrequencyTypeZeroValidator.java
index e9053388..a550b262 100644
--- a/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/rules/FrequencyTypeZeroValidator.java
+++ b/gtfs-realtime-validator-lib/src/main/java/edu/usf/cutr/gtfsrtvalidator/lib/validation/rules/FrequencyTypeZeroValidator.java
@@ -17,6 +17,8 @@
package edu.usf.cutr.gtfsrtvalidator.lib.validation.rules;
import com.google.transit.realtime.GtfsRealtime;
+import com.google.transit.realtime.GtfsRealtime.TripUpdate;
+
import edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel;
import edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel;
import edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel;
@@ -26,8 +28,9 @@
import org.onebusaway.gtfs.services.GtfsMutableDao;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.List;
+import java.text.ParseException;
+import java.util.*;
+import java.text.SimpleDateFormat;
import static edu.usf.cutr.gtfsrtvalidator.lib.validation.ValidationRules.*;
@@ -37,6 +40,7 @@
* E006 - Missing required vehicle_position trip field for frequency-based exact_times = 0
* E013 - Frequency type 0 trip schedule_relationship should be UNSCHEDULED or empty
* W005 - Missing vehicle_id in trip_update for frequency-based exact_times = 0
+ * E053 - An exact_times = 0 frequencies.txt trip should have the same start_time through it's trip
*/
public class FrequencyTypeZeroValidator implements FeedEntityValidator {
@@ -47,9 +51,22 @@ public List validate(long currentTimeMillis, GtfsMutableDa
List errorListE006 = new ArrayList<>();
List errorListE013 = new ArrayList<>();
List errorListW005 = new ArrayList<>();
+ List errorListE053 = new ArrayList<>();
+
+ HashMap> previousTripUpdates = new HashMap>();
+
+ if (previousFeedMessage != null) {
+ for (GtfsRealtime.FeedEntity entity : previousFeedMessage.getEntityList()) {
+ if (entity.hasTripUpdate()) {
+ GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
+ addTripUpdate(previousTripUpdates, tripUpdate);
+ }
+ }
+ }
for (GtfsRealtime.FeedEntity entity : feedMessage.getEntityList()) {
if (entity.hasTripUpdate()) {
+
GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
if (gtfsMetadata.getExactTimesZeroTripIds().contains(tripUpdate.getTrip().getTripId())) {
@@ -75,9 +92,11 @@ public List validate(long currentTimeMillis, GtfsMutableDa
// W005 - Missing vehicle_id in trip_update for frequency-based exact_times = 0
RuleUtils.addOccurrence(W005, "trip_id " + tripUpdate.getTrip().getTripId(), errorListW005, _log);
}
+
+ if(previousFeedMessage!=null)
+ checkE053(tripUpdate, previousTripUpdates, errorListE053);
}
}
-
if (entity.hasVehicle()) {
GtfsRealtime.VehiclePosition vehiclePosition = entity.getVehicle();
if (vehiclePosition.hasTrip() &&
@@ -109,6 +128,7 @@ public List validate(long currentTimeMillis, GtfsMutableDa
}
}
}
+
List errors = new ArrayList<>();
if (!errorListE006.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(E006), errorListE006));
@@ -119,6 +139,126 @@ public List validate(long currentTimeMillis, GtfsMutableDa
if (!errorListW005.isEmpty()) {
errors.add(new ErrorListHelperModel(new MessageLogModel(W005), errorListW005));
}
+ if (!errorListE053.isEmpty()) {
+ errors.add(new ErrorListHelperModel(new MessageLogModel(E053), errorListE053));
+ }
return errors;
+
+ }
+
+ private void checkE053(TripUpdate currentTripUpdate, HashMap> previousTripUpdates, List errorListE053) {
+
+ if (!inTripUpdates(currentTripUpdate, previousTripUpdates)) {
+ if (!isNewTrip(previousTripUpdates, currentTripUpdate)) {
+ String errorMessage = "vehicle_id " + currentTripUpdate.getVehicle().getId() + " startTime has changed and is now " + currentTripUpdate.getTrip().getStartTime();
+ RuleUtils.addOccurrence(E053, errorMessage, errorListE053, _log);
+ }
+ }
+
+ }
+
+ private boolean isNewTrip(HashMap> previousTripUpdates, TripUpdate tripUpdate) {
+ TripUpdate latest = null;
+ List tripUpdates = previousTripUpdates.get(new TripUpdateKey(tripUpdate.getVehicle().getId(), tripUpdate.getTrip().getTripId()));
+ if (tripUpdates != null) {
+ for (TripUpdate previousTripUpdate : tripUpdates) {
+ if (latest == null) {
+ latest = previousTripUpdate;
+ }
+ if (new TripUpdateStartTimeComparator().compare(latest, previousTripUpdate) > 0) {
+ latest = previousTripUpdate;
+ }
+ }
+ if (new TripUpdateStartTimeComparator().compare(tripUpdate, latest) > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean inTripUpdates(TripUpdate tripUpdate, HashMap> previousTripUpdates ) {
+
+ List tripUpdates = previousTripUpdates.get(new TripUpdateKey(tripUpdate.getVehicle().getId(), tripUpdate.getTrip().getTripId()));
+ if(tripUpdates !=null )
+ {
+ for (TripUpdate previousTripUpdate : tripUpdates) {
+ if (previousTripUpdate.getTrip().getStartTime().equals(tripUpdate.getTrip().getStartTime())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
+ private void addTripUpdate(HashMap> tripUpdatesMap, GtfsRealtime.TripUpdate tripUpdate) {
+ if (tripUpdate.hasVehicle() && tripUpdate.getVehicle().hasId()) {
+
+ List tripUpdates = null;
+ if (!tripUpdatesMap.containsKey(new TripUpdateKey(tripUpdate.getVehicle().getId(), tripUpdate.getTrip().getTripId()))) {
+ tripUpdates = new ArrayList();
+ } else {
+ tripUpdates = tripUpdatesMap.get(new TripUpdateKey(tripUpdate.getVehicle().getId(), tripUpdate.getTrip().getTripId()));
+ }
+ tripUpdates.add(tripUpdate);
+
+ //Collections.sort(tripUpdates, new TripUpdateStartTimeComparator());
+
+ tripUpdatesMap.put(new TripUpdateKey(tripUpdate.getVehicle().getId(), tripUpdate.getTrip().getTripId()), tripUpdates);
+ }
+ }
+ private class TripUpdateKey
+ {
+ String vehicle_id;
+ String trip_id;
+
+ public TripUpdateKey(String vehicle_id, String trip_id)
+ {
+ this.vehicle_id=vehicle_id;
+ this.trip_id=trip_id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TripUpdateKey that = (TripUpdateKey) o;
+
+ if (vehicle_id != null ? !vehicle_id.equals(that.vehicle_id) : that.vehicle_id != null) return false;
+ return trip_id != null ? trip_id.equals(that.trip_id) : that.trip_id == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = vehicle_id != null ? vehicle_id.hashCode() : 0;
+ result = 31 * result + (trip_id != null ? trip_id.hashCode() : 0);
+ return result;
+ }
+ }
+
+ private class TripUpdateStartTimeComparator implements Comparator {
+ SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ssa");
+
+ @Override
+ public int compare(TripUpdate t1, TripUpdate t2) {
+
+ try {
+ if(t1.hasTrip()&&t1.getTrip().hasStartTime()&&t2.hasTrip()&&t2.getTrip().hasStartTime()) {
+
+ Date t1_date = formatter.parse(t1.getTrip().getStartTime());
+
+ Date t2_date = formatter.parse(t2.getTrip().getStartTime());
+
+ return t1_date.compareTo(t2_date);
+ }
+ } catch (ParseException e) {
+ _log.error(e.getMessage(), e);
+ }
+ return -1;
+ }
+
}
}
diff --git a/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/UtilTest.java b/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/UtilTest.java
index a92c1443..a9233fc4 100644
--- a/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/UtilTest.java
+++ b/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/UtilTest.java
@@ -844,6 +844,6 @@ public void testIsInFuture() {
@Test
public void testGetAllRules() {
List rules = ValidationRules.getRules();
- assertEquals(61, rules.size());
+ assertEquals(62, rules.size());
}
}
diff --git a/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/rules/FrequencyTypeZeroValidatorTest.java b/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/rules/FrequencyTypeZeroValidatorTest.java
index 45236b35..c1906687 100644
--- a/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/rules/FrequencyTypeZeroValidatorTest.java
+++ b/gtfs-realtime-validator-lib/src/test/java/edu/usf/cutr/gtfsrtvalidator/lib/test/rules/FrequencyTypeZeroValidatorTest.java
@@ -1,6 +1,8 @@
package edu.usf.cutr.gtfsrtvalidator.lib.test.rules;
import com.google.transit.realtime.GtfsRealtime;
+import com.google.transit.realtime.GtfsRealtime.FeedMessage;
+
import edu.usf.cutr.gtfsrtvalidator.lib.model.ValidationRule;
import edu.usf.cutr.gtfsrtvalidator.lib.test.FeedMessageTest;
import edu.usf.cutr.gtfsrtvalidator.lib.test.util.TestUtils;
@@ -262,4 +264,250 @@ public void testW005() {
clearAndInitRequiredFeedFields();
}
+
+ /**
+ * E053- inconsistent start time in trip descriptor for frequency-based exact_times = 0
+ */
+ @Test
+ public void testE053() {
+
+ FrequencyTypeZeroValidator frequencyTypeZeroValidator = new FrequencyTypeZeroValidator();
+ Map expected = new HashMap<>();
+ FeedMessage previousMessage=null;
+ FeedMessage currentMessage=null;
+ for (int i = 0; i < 2; i++) {
+ GtfsRealtime.TripDescriptor.Builder tripDescriptorBuilder = GtfsRealtime.TripDescriptor.newBuilder();
+
+ tripDescriptorBuilder.setTripId("1");
+ tripDescriptorBuilder.setStartDate("4-24-2016");
+
+ tripDescriptorBuilder.setStartTime("08:00:00AM");
+
+ GtfsRealtime.VehicleDescriptor.Builder vehicleDescriptorBuilder = GtfsRealtime.VehicleDescriptor.newBuilder();
+
+ vehicleDescriptorBuilder.setId("1");
+
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ vehiclePositionBuilder.setTimestamp(TimestampUtils.MIN_POSIX_TIME);
+ vehiclePositionBuilder.setTrip(tripDescriptorBuilder.build());
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ tripUpdateBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ tripUpdateBuilder.setTrip(tripDescriptorBuilder.build());
+
+ for (int j = 0; j < i + 1; j++) {
+ GtfsRealtime.TripUpdate.StopTimeUpdate.Builder stopTimeUpdateBuilder = GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder();
+
+ stopTimeUpdateBuilder.setStopId("" + j);
+ stopTimeUpdateBuilder.setStopSequence(j);
+
+ GtfsRealtime.TripUpdate.StopTimeEvent.Builder stopTimeEventBuilder = GtfsRealtime.TripUpdate.StopTimeEvent.newBuilder();
+ stopTimeUpdateBuilder.setArrival(stopTimeEventBuilder.build());
+
+ tripUpdateBuilder.addStopTimeUpdate(stopTimeUpdateBuilder.build());
+ }
+
+
+ feedEntityBuilder.setTripUpdate(tripUpdateBuilder.build());
+
+ // Add vehicle_id to vehicle position - 1 warning
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ currentMessage=feedMessageBuilder.build();
+
+ results = frequencyTypeZeroValidator.validate(TimestampUtils.MIN_POSIX_TIME, bullRunnerGtfs, bullRunnerGtfsMetadata, currentMessage, previousMessage, null);
+
+ previousMessage=currentMessage;
+ }
+ expected.clear();
+ TestUtils.assertResults(expected, results);
+ previousMessage=null;
+ for (int i = 0; i < 2; i++) {
+ GtfsRealtime.TripDescriptor.Builder tripDescriptorBuilder = GtfsRealtime.TripDescriptor.newBuilder();
+
+ tripDescriptorBuilder.setTripId("1");
+ tripDescriptorBuilder.setStartDate("4-24-2016");
+ if (i == 0) {
+ tripDescriptorBuilder.setStartTime("08:00:00AM");
+ }
+ if (i == 1) {
+ tripDescriptorBuilder.setStartTime("09:00:00AM");
+ }
+
+
+ GtfsRealtime.VehicleDescriptor.Builder vehicleDescriptorBuilder = GtfsRealtime.VehicleDescriptor.newBuilder();
+
+ vehicleDescriptorBuilder.setId("1");
+
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ vehiclePositionBuilder.setTimestamp(TimestampUtils.MIN_POSIX_TIME);
+ vehiclePositionBuilder.setTrip(tripDescriptorBuilder.build());
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ tripUpdateBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ tripUpdateBuilder.setTrip(tripDescriptorBuilder.build());
+
+ for (int j = 0; j < i + 1; j++) {
+ GtfsRealtime.TripUpdate.StopTimeUpdate.Builder stopTimeUpdateBuilder = GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder();
+
+ stopTimeUpdateBuilder.setStopId("" + j);
+ stopTimeUpdateBuilder.setStopSequence(j);
+
+ GtfsRealtime.TripUpdate.StopTimeEvent.Builder stopTimeEventBuilder = GtfsRealtime.TripUpdate.StopTimeEvent.newBuilder();
+ stopTimeUpdateBuilder.setArrival(stopTimeEventBuilder.build());
+
+ tripUpdateBuilder.addStopTimeUpdate(stopTimeUpdateBuilder.build());
+ }
+
+
+ feedEntityBuilder.setTripUpdate(tripUpdateBuilder.build());
+
+ // Add vehicle_id to vehicle position - 1 warning
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ currentMessage=feedMessageBuilder.build();
+
+ results = frequencyTypeZeroValidator.validate(TimestampUtils.MIN_POSIX_TIME, bullRunnerGtfs, bullRunnerGtfsMetadata, currentMessage, previousMessage, null);
+
+ previousMessage=currentMessage;
+
+ }
+ expected.clear();
+ TestUtils.assertResults(expected, results);
+ previousMessage=null;
+ for (int i = 0; i < 2; i++) {
+ GtfsRealtime.TripDescriptor.Builder tripDescriptorBuilder = GtfsRealtime.TripDescriptor.newBuilder();
+
+ tripDescriptorBuilder.setTripId("1");
+ tripDescriptorBuilder.setStartDate("4-24-2016");
+ if (i == 0) {
+ tripDescriptorBuilder.setStartTime("08:00:00AM");
+ }
+ if (i == 1) {
+ tripDescriptorBuilder.setStartTime("07:00:00AM");
+ }
+
+
+ GtfsRealtime.VehicleDescriptor.Builder vehicleDescriptorBuilder = GtfsRealtime.VehicleDescriptor.newBuilder();
+
+ vehicleDescriptorBuilder.setId("1");
+
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ vehiclePositionBuilder.setTimestamp(TimestampUtils.MIN_POSIX_TIME);
+ vehiclePositionBuilder.setTrip(tripDescriptorBuilder.build());
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ tripUpdateBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ tripUpdateBuilder.setTrip(tripDescriptorBuilder.build());
+
+ for (int j = 0; j < i + 1; j++) {
+ GtfsRealtime.TripUpdate.StopTimeUpdate.Builder stopTimeUpdateBuilder = GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder();
+
+ stopTimeUpdateBuilder.setStopId("" + j);
+ stopTimeUpdateBuilder.setStopSequence(j);
+
+ GtfsRealtime.TripUpdate.StopTimeEvent.Builder stopTimeEventBuilder = GtfsRealtime.TripUpdate.StopTimeEvent.newBuilder();
+ stopTimeUpdateBuilder.setArrival(stopTimeEventBuilder.build());
+
+ tripUpdateBuilder.addStopTimeUpdate(stopTimeUpdateBuilder.build());
+ }
+
+
+ feedEntityBuilder.setTripUpdate(tripUpdateBuilder.build());
+
+ // Add vehicle_id to vehicle position - 1 warning
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ currentMessage=feedMessageBuilder.build();
+
+ results = frequencyTypeZeroValidator.validate(TimestampUtils.MIN_POSIX_TIME, bullRunnerGtfs, bullRunnerGtfsMetadata, currentMessage, previousMessage, null);
+
+ previousMessage=currentMessage;
+
+ }
+ expected.put(ValidationRules.E053, 1);
+ TestUtils.assertResults(expected, results);
+ previousMessage=null;
+ for (int i = 0; i < 2; i++) {
+ GtfsRealtime.TripDescriptor.Builder tripDescriptorBuilder = GtfsRealtime.TripDescriptor.newBuilder();
+
+ tripDescriptorBuilder.setTripId(""+i);
+ tripDescriptorBuilder.setStartDate("4-24-2016");
+ if (i == 0) {
+ tripDescriptorBuilder.setStartTime("08:00:00AM");
+ }
+ if (i == 1) {
+ tripDescriptorBuilder.setStartTime("07:00:00AM");
+ }
+
+
+ GtfsRealtime.VehicleDescriptor.Builder vehicleDescriptorBuilder = GtfsRealtime.VehicleDescriptor.newBuilder();
+
+ vehicleDescriptorBuilder.setId("1");
+
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ vehiclePositionBuilder.setTimestamp(TimestampUtils.MIN_POSIX_TIME);
+ vehiclePositionBuilder.setTrip(tripDescriptorBuilder.build());
+ vehiclePositionBuilder.setVehicle(vehicleDescriptorBuilder.build());
+
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ tripUpdateBuilder.setVehicle(vehicleDescriptorBuilder.build());
+ tripUpdateBuilder.setTrip(tripDescriptorBuilder.build());
+
+ for (int j = 0; j < i + 1; j++) {
+ GtfsRealtime.TripUpdate.StopTimeUpdate.Builder stopTimeUpdateBuilder = GtfsRealtime.TripUpdate.StopTimeUpdate.newBuilder();
+
+ stopTimeUpdateBuilder.setStopId("" + j);
+ stopTimeUpdateBuilder.setStopSequence(j);
+
+ GtfsRealtime.TripUpdate.StopTimeEvent.Builder stopTimeEventBuilder = GtfsRealtime.TripUpdate.StopTimeEvent.newBuilder();
+ stopTimeUpdateBuilder.setArrival(stopTimeEventBuilder.build());
+
+ tripUpdateBuilder.addStopTimeUpdate(stopTimeUpdateBuilder.build());
+ }
+
+
+ feedEntityBuilder.setTripUpdate(tripUpdateBuilder.build());
+
+ // Add vehicle_id to vehicle position - 1 warning
+ feedEntityBuilder.setVehicle(vehiclePositionBuilder.build());
+
+
+ feedMessageBuilder.setEntity(0, feedEntityBuilder.build());
+
+ currentMessage=feedMessageBuilder.build();
+
+ results = frequencyTypeZeroValidator.validate(TimestampUtils.MIN_POSIX_TIME, bullRunnerGtfs, bullRunnerGtfsMetadata, currentMessage, previousMessage, null);
+
+ previousMessage=currentMessage;
+
+ }
+ expected.clear();
+ TestUtils.assertResults(expected, results);
+ clearAndInitRequiredFeedFields();
+ }
}