Search in sources :

Example 16 with ErrorListHelperModel

use of edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel in project gtfs-realtime-validator by CUTR-at-USF.

the class CrossFeedDescriptorValidator method validate.

@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
    if (combinedFeedMessage == null) {
        // If only one GTFS-rt feed is being monitored for the GTFS dataset, then don't run any of the cross-feed rules
        return new ArrayList<>();
    }
    List<OccurrenceModel> w003List = new ArrayList<>();
    List<OccurrenceModel> e047List = new ArrayList<>();
    /*
          Create inverse maps, so we can efficiently check if a trip_id in TripUpdates is in VehiclePositions, and if
          vehicle_id in VehiclePositions is in TripUpdates.
         */
    // key is trip_id from TripUpdates feed, value is vehicle.id
    HashMap<String, String> tripUpdatesTripIdToVehicleId = new HashMap<>();
    // key is vehicle.id from TripUpdates feed, value is trip_id
    HashMap<String, String> tripUpdatesVehicleIdToTripId = new HashMap<>();
    // A set of trips (key = trip_id) that don't have any vehicle.ids
    Set<String> tripsWithoutVehicles = new HashSet<>();
    int tripUpdateCount = 0;
    // key is vehicle_id from VehiclePositions feed, value is trip_id
    HashMap<String, String> vehiclePositionsVehicleIdToTripId = new HashMap<>();
    // key is trip_id from VehiclePositions feed, value is vehicle_id
    HashMap<String, String> vehiclePositionsTripIdToVehicleId = new HashMap<>();
    // A set of vehicles (key = vehicle.id) that don't have any trip_ids
    Set<String> vehiclesWithoutTrips = new HashSet<>();
    int vehiclePositionCount = 0;
    // Build the maps
    for (GtfsRealtime.FeedEntity entity : combinedFeedMessage.getEntityList()) {
        if (entity.hasTripUpdate() && hasTripId(entity.getTripUpdate())) {
            tripUpdateCount++;
            String tripId = entity.getTripUpdate().getTrip().getTripId();
            String vehicleId = "";
            if (entity.getTripUpdate().hasVehicle() && entity.getTripUpdate().getVehicle().hasId()) {
                vehicleId = entity.getTripUpdate().getVehicle().getId();
            }
            if (StringUtils.isEmpty(vehicleId)) {
                // Trip does not have a vehicle.id - add it to the set
                tripsWithoutVehicles.add(tripId);
            } else {
                // Trip has a vehicle.id - add it to the HashMap
                tripUpdatesTripIdToVehicleId.put(tripId, vehicleId);
                tripUpdatesVehicleIdToTripId.put(vehicleId, tripId);
            // TODO - New rule - check that there is at most one TripUpdate entity per scheduled trip_id - see https://github.com/CUTR-at-USF/gtfs-realtime-validator/issues/33
            }
        }
        if (entity.hasVehicle() && hasVehicleId(entity.getVehicle())) {
            vehiclePositionCount++;
            String vehicleId = entity.getVehicle().getVehicle().getId();
            String tripId = "";
            if (entity.getVehicle().hasTrip() && entity.getVehicle().getTrip().hasTripId()) {
                tripId = entity.getVehicle().getTrip().getTripId();
            }
            if (StringUtils.isEmpty(tripId)) {
                // Vehicle does not have a trip_id - add it to the set
                vehiclesWithoutTrips.add(vehicleId);
            } else {
                // Vehicle has a trip_id - add it to the HashMap
                vehiclePositionsVehicleIdToTripId.put(vehicleId, tripId);
                vehiclePositionsTripIdToVehicleId.put(tripId, vehicleId);
            // TODO - New rule - check that there is at most one vehicle assigned each trip - see https://github.com/CUTR-at-USF/gtfs-realtime-validator/issues/38
            }
        }
    }
    List<ErrorListHelperModel> errors = new ArrayList<>();
    if (tripUpdateCount == 0 || vehiclePositionCount == 0) {
        // We are missing a VehiclePositions or TripUpdates feed, so we can't compare across feeds - return empty list;
        return errors;
    }
    // Check all trips that contained a vehicle
    for (Map.Entry<String, String> trip : tripUpdatesTripIdToVehicleId.entrySet()) {
        if (!vehiclePositionsTripIdToVehicleId.containsKey(trip.getKey())) {
            // W003 - TripUpdates feed has a trip_id that's not in VehiclePositions feed
            RuleUtils.addOccurrence(W003, "trip_id " + trip.getKey() + " is in TripUpdates but not in VehiclePositions feed", w003List, _log);
        }
        if (!vehiclePositionsVehicleIdToTripId.containsKey(trip.getValue()) && !vehiclesWithoutTrips.contains(trip.getValue())) {
            // W003 - TripUpdates feed has a vehicle_id that's not in VehiclePositions feed
            RuleUtils.addOccurrence(W003, "vehicle_id " + trip.getValue() + " is in TripUpdates but not in VehiclePositions feed", w003List, _log);
        }
        checkE047TripUpdates(trip, vehiclePositionsTripIdToVehicleId, e047List);
    }
    // Check all vehicles that contained a trip
    for (Map.Entry<String, String> vehiclePosition : vehiclePositionsVehicleIdToTripId.entrySet()) {
        if (!tripUpdatesVehicleIdToTripId.containsKey(vehiclePosition.getKey())) {
            // W003 - VehiclePositions has a vehicle_id that's not in TripUpdates feed
            RuleUtils.addOccurrence(W003, "vehicle_id " + vehiclePosition.getKey() + " is in VehiclePositions but not in TripUpdates feed", w003List, _log);
        }
        if (!tripUpdatesTripIdToVehicleId.containsKey(vehiclePosition.getValue()) && !tripsWithoutVehicles.contains(vehiclePosition.getValue())) {
            // W003 - VehiclePositions has a trip_id that's not in the TripUpdates feed
            RuleUtils.addOccurrence(W003, "trip_id " + vehiclePosition.getValue() + " is in VehiclePositions but not in TripUpdates feed", w003List, _log);
        }
        checkE047VehiclePositions(vehiclePosition, tripUpdatesVehicleIdToTripId, gtfsMetadata, e047List);
    }
    // Check all trips that did NOT contain a vehicle
    for (String trip_id : tripsWithoutVehicles) {
        if (!vehiclePositionsTripIdToVehicleId.containsKey(trip_id)) {
            // W003 - TripUpdates feed has a trip_id that's not in VehiclePositions feed
            RuleUtils.addOccurrence(W003, "trip_id " + trip_id + " is in TripUpdates but not in VehiclePositions feed", w003List, _log);
        }
    }
    // Check all vehicles that did NOT contain a trip
    for (String vehicle_id : vehiclesWithoutTrips) {
        if (!tripUpdatesVehicleIdToTripId.containsKey(vehicle_id)) {
            // W003 - VehiclePositions has a vehicle_id that's not in TripUpdates feed
            RuleUtils.addOccurrence(W003, "vehicle_id " + vehicle_id + " is in VehiclePositions but not in TripUpdates feed", w003List, _log);
        }
    }
    if (!w003List.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(W003), w003List));
    }
    if (!e047List.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(E047), e047List));
    }
    return errors;
}
Also used : OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime) ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel)

Example 17 with ErrorListHelperModel

use of edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel in project gtfs-realtime-validator by CUTR-at-USF.

the class FrequencyTypeZeroValidator method validate.

@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
    List<OccurrenceModel> errorListE006 = new ArrayList<>();
    List<OccurrenceModel> errorListE013 = new ArrayList<>();
    List<OccurrenceModel> errorListW005 = new ArrayList<>();
    for (GtfsRealtime.FeedEntity entity : feedMessage.getEntityList()) {
        if (entity.hasTripUpdate()) {
            GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
            if (gtfsMetadata.getExactTimesZeroTripIds().contains(tripUpdate.getTrip().getTripId())) {
                /**
                 * NOTE - W006 checks for missing trip_ids, because we can't check for that here - we need the trip_id to know if it's exact_times=0
                 */
                if (!tripUpdate.getTrip().hasStartDate()) {
                    // E006 - Missing required trip_update trip field for frequency-based exact_times = 0
                    RuleUtils.addOccurrence(E006, "trip_id " + tripUpdate.getTrip().getTripId() + " is missing start_date", errorListE006, _log);
                }
                if (!tripUpdate.getTrip().hasStartTime()) {
                    // E006 - Missing required trip_update trip field for frequency-based exact_times = 0
                    RuleUtils.addOccurrence(E006, "trip_id " + tripUpdate.getTrip().getTripId() + " is missing start_time", errorListE006, _log);
                }
                if (!(!tripUpdate.getTrip().hasScheduleRelationship() || tripUpdate.getTrip().getScheduleRelationship().equals(GtfsRealtime.TripDescriptor.ScheduleRelationship.UNSCHEDULED))) {
                    // E013 - Validate schedule_relationship is UNSCHEDULED or empty
                    RuleUtils.addOccurrence(E013, "trip_id " + tripUpdate.getTrip().getTripId() + " schedule_relationship " + tripUpdate.getTrip().getScheduleRelationship(), errorListE013, _log);
                }
                if (!tripUpdate.hasVehicle() || !tripUpdate.getVehicle().hasId()) {
                    // W005 - Missing vehicle_id in trip_update for frequency-based exact_times = 0
                    RuleUtils.addOccurrence(W005, "trip_id " + tripUpdate.getTrip().getTripId(), errorListW005, _log);
                }
            }
        }
        if (entity.hasVehicle()) {
            GtfsRealtime.VehiclePosition vehiclePosition = entity.getVehicle();
            if (vehiclePosition.hasTrip() && gtfsMetadata.getExactTimesZeroTripIds().contains(vehiclePosition.getTrip().getTripId())) {
                /**
                 * NOTE - W006 checks for missing trip_ids, because we can't check for that here - we need the trip_id to know if it's exact_times=0
                 */
                if (!vehiclePosition.getTrip().hasStartDate()) {
                    // E006 - Missing required vehicle_position trip field for frequency-based exact_times = 0
                    RuleUtils.addOccurrence(E006, "vehicle_id " + vehiclePosition.getVehicle().getId() + " trip_id " + vehiclePosition.getTrip().getTripId() + " is missing start_date", errorListE006, _log);
                }
                if (!vehiclePosition.getTrip().hasStartTime()) {
                    // E006 - Missing required vehicle_position trip field for frequency-based exact_times = 0
                    RuleUtils.addOccurrence(E006, "vehicle_id " + vehiclePosition.getVehicle().getId() + " trip_id " + vehiclePosition.getTrip().getTripId() + " is missing start_time", errorListE006, _log);
                }
                if (!(!vehiclePosition.getTrip().hasScheduleRelationship() || vehiclePosition.getTrip().getScheduleRelationship().equals(GtfsRealtime.TripDescriptor.ScheduleRelationship.UNSCHEDULED))) {
                    // E013 - Validate schedule_relationship is UNSCHEDULED or empty
                    String prefix = "vehicle_id " + vehiclePosition.getVehicle().getId() + " trip_id " + vehiclePosition.getTrip().getTripId() + " schedule_relationship " + vehiclePosition.getTrip().getScheduleRelationship();
                    RuleUtils.addOccurrence(E013, prefix, errorListE013, _log);
                }
                if (!vehiclePosition.getVehicle().hasId()) {
                    // W005 - Missing vehicle_id for frequency-based exact_times = 0
                    RuleUtils.addOccurrence(W005, "entity ID" + entity.getId() + "with trip_id " + vehiclePosition.getTrip().getTripId(), errorListW005, _log);
                }
            }
        }
    }
    List<ErrorListHelperModel> errors = new ArrayList<>();
    if (!errorListE006.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(E006), errorListE006));
    }
    if (!errorListE013.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(E013), errorListE013));
    }
    if (!errorListW005.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(W005), errorListW005));
    }
    return errors;
}
Also used : ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel) ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime)

Example 18 with ErrorListHelperModel

use of edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel in project gtfs-realtime-validator by CUTR-at-USF.

the class FrequencyTypeOneValidator method validate.

@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
    List<OccurrenceModel> errorListE019 = new ArrayList<>();
    for (GtfsRealtime.FeedEntity entity : feedMessage.getEntityList()) {
        if (entity.hasTripUpdate()) {
            GtfsRealtime.TripUpdate tripUpdate = entity.getTripUpdate();
            List<Frequency> frequenceTypeOneList = gtfsMetadata.getExactTimesOneTrips().get(tripUpdate.getTrip().getTripId());
            if (frequenceTypeOneList != null) {
                boolean foundMatch = false;
                String gtfsStartTimeString = null;
                Integer headwaySecs = null;
                // For at least one frequency period for this trip_id, start_time in the GTFS-rt data must be some multiple (including zero) of headway_secs later than the start_time
                for (Frequency f : frequenceTypeOneList) {
                    int startTime = f.getStartTime();
                    // See if the GTFS-rt start_time matches at least one multiple of GTFS start_time for this frequency
                    while (startTime < f.getEndTime()) {
                        // Convert seconds after midnight to 24hr clock time like "06:00:00"
                        gtfsStartTimeString = TimestampUtils.secondsAfterMidnightToClock(startTime);
                        headwaySecs = f.getHeadwaySecs();
                        _log.debug("start time = " + startTime);
                        _log.debug("formatted start time = " + gtfsStartTimeString);
                        if (tripUpdate.getTrip().getStartTime().equals(gtfsStartTimeString)) {
                            // We found a matching multiple - no error for this GTFS-rt start_time
                            foundMatch = true;
                            break;
                        }
                        startTime += f.getHeadwaySecs();
                    }
                    if (foundMatch) {
                        // If we found at least one matching frequency with a matching multiple of headway_secs for the GTFS-rt start_time, then no error
                        break;
                    }
                }
                if (!foundMatch) {
                    // E019 - GTFS-rt frequency exact_times = 1 trip start_time must match GTFS data
                    String prefix = "GTFS-rt trip_id " + tripUpdate.getTrip().getTripId() + " has start_time of " + tripUpdate.getTrip().getStartTime() + " and GTFS frequencies.txt start_time is " + gtfsStartTimeString + " with a headway of " + headwaySecs + " seconds ";
                    RuleUtils.addOccurrence(E019, prefix, errorListE019, _log);
                }
            }
        }
        if (entity.hasVehicle()) {
            GtfsRealtime.VehiclePosition vehiclePosition = entity.getVehicle();
            // E019 - GTFS-rt frequency exact_times = 1 trip start_date and start_time must match GTFS data
            List<Frequency> frequenceTypeOneList = gtfsMetadata.getExactTimesOneTrips().get(vehiclePosition.getTrip().getTripId());
            if (frequenceTypeOneList != null) {
                boolean foundMatch = false;
                String gtfsStartTimeString = null;
                Integer headwaySecs = null;
                // For at least one frequency period for this trip_id, start_time in the GTFS-rt data must be some multiple (including zero) of headway_secs later than the start_time
                for (Frequency f : frequenceTypeOneList) {
                    int startTime = f.getStartTime();
                    // See if the GTFS-rt start_time matches at least one multiple of GTFS start_time for this frequency
                    while (startTime < f.getEndTime()) {
                        // Convert seconds after midnight to 24hr clock time like "06:00:00"
                        gtfsStartTimeString = String.format("%02d:%02d:%02d", startTime / 3600, startTime % 360, startTime % 60);
                        headwaySecs = f.getHeadwaySecs();
                        _log.debug("start time = " + startTime);
                        _log.debug("formatted start time = " + gtfsStartTimeString);
                        if (vehiclePosition.hasTrip() && vehiclePosition.getTrip().getStartTime().equals(gtfsStartTimeString)) {
                            // We found a matching multiple - no error for this GTFS-rt start_time
                            foundMatch = true;
                            break;
                        }
                        startTime += f.getHeadwaySecs();
                    }
                    if (foundMatch) {
                        // If we found at least one matching frequency with a matching multiple of headway_secs for the GTFS-rt start_time, then no error
                        break;
                    }
                }
                if (!foundMatch) {
                    // E019 - GTFS-rt frequency exact_times = 1 trip start_time must match GTFS data
                    String prefix = "GTFS-rt trip_id " + vehiclePosition.getTrip().getTripId() + " has start_time of " + vehiclePosition.getTrip().getStartTime() + " and GTFS frequencies.txt start_time is " + gtfsStartTimeString + " with a headway of " + headwaySecs + " seconds ";
                    RuleUtils.addOccurrence(E019, prefix, errorListE019, _log);
                }
            }
        }
    }
    List<ErrorListHelperModel> errors = new ArrayList<>();
    if (!errorListE019.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(E019), errorListE019));
    }
    return errors;
}
Also used : ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime) ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel) Frequency(org.onebusaway.gtfs.model.Frequency)

Example 19 with ErrorListHelperModel

use of edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel in project gtfs-realtime-validator by CUTR-at-USF.

the class HeaderValidator method validate.

@Override
public List<ErrorListHelperModel> validate(long currentTimeMillis, GtfsDaoImpl gtfsData, GtfsMetadata gtfsMetadata, GtfsRealtime.FeedMessage feedMessage, GtfsRealtime.FeedMessage previousFeedMessage, GtfsRealtime.FeedMessage combinedFeedMessage) {
    List<OccurrenceModel> errorListE038 = new ArrayList<>();
    List<OccurrenceModel> errorListE039 = new ArrayList<>();
    List<OccurrenceModel> errorListE049 = new ArrayList<>();
    if (!GtfsUtils.isValidVersion(feedMessage.getHeader())) {
        // E038 - Invalid header.gtfs_realtime_version
        RuleUtils.addOccurrence(E038, "header.gtfs_realtime_version of " + feedMessage.getHeader().getGtfsRealtimeVersion(), errorListE038, _log);
    }
    try {
        if (GtfsUtils.isV2orHigher(feedMessage.getHeader()) && !feedMessage.getHeader().hasIncrementality()) {
            // E049 - header incrementality not populated
            RuleUtils.addOccurrence(E049, "", errorListE049, _log);
        }
    } catch (Exception e) {
        _log.error("Error checking header version for E049: " + e);
    }
    if (feedMessage.getHeader().getIncrementality().equals(GtfsRealtime.FeedHeader.Incrementality.FULL_DATASET)) {
        for (GtfsRealtime.FeedEntity entity : feedMessage.getEntityList()) {
            if (entity.hasIsDeleted()) {
                // E039 - FULL_DATASET feeds should not include entity.is_deleted
                RuleUtils.addOccurrence(E039, "entity ID " + entity.getId() + " has is_deleted=" + entity.getIsDeleted(), errorListE039, _log);
            }
        }
    }
    List<ErrorListHelperModel> errors = new ArrayList<>();
    if (!errorListE038.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(E038), errorListE038));
    }
    if (!errorListE039.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(E039), errorListE039));
    }
    if (!errorListE049.isEmpty()) {
        errors.add(new ErrorListHelperModel(new MessageLogModel(E049), errorListE049));
    }
    return errors;
}
Also used : ErrorListHelperModel(edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel) MessageLogModel(edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel) ArrayList(java.util.ArrayList) OccurrenceModel(edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel) GtfsRealtime(com.google.transit.realtime.GtfsRealtime)

Aggregations

ErrorListHelperModel (edu.usf.cutr.gtfsrtvalidator.lib.model.helper.ErrorListHelperModel)19 MessageLogModel (edu.usf.cutr.gtfsrtvalidator.lib.model.MessageLogModel)14 OccurrenceModel (edu.usf.cutr.gtfsrtvalidator.lib.model.OccurrenceModel)14 GtfsRealtime (com.google.transit.realtime.GtfsRealtime)10 ArrayList (java.util.ArrayList)9 ValidationRule (edu.usf.cutr.gtfsrtvalidator.lib.model.ValidationRule)6 Test (org.junit.Test)6 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 HashMap (java.util.HashMap)2 List (java.util.List)2 SerializationFeature (com.fasterxml.jackson.databind.SerializationFeature)1 InvalidProtocolBufferException (com.google.protobuf.InvalidProtocolBufferException)1 TextFormat (com.google.protobuf.TextFormat)1 BatchProcessor (edu.usf.cutr.gtfsrtvalidator.lib.batch.BatchProcessor)1 FeedMessageTest (edu.usf.cutr.gtfsrtvalidator.lib.test.FeedMessageTest)1 GtfsUtils (edu.usf.cutr.gtfsrtvalidator.lib.util.GtfsUtils)1 SortUtils (edu.usf.cutr.gtfsrtvalidator.lib.util.SortUtils)1 TimestampUtils (edu.usf.cutr.gtfsrtvalidator.lib.util.TimestampUtils)1 TimestampUtils.getElapsedTime (edu.usf.cutr.gtfsrtvalidator.lib.util.TimestampUtils.getElapsedTime)1 TimestampUtils.getElapsedTimeString (edu.usf.cutr.gtfsrtvalidator.lib.util.TimestampUtils.getElapsedTimeString)1