/**
* Copyright (C) 2015 University of South Florida
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.transit_data_federation.impl;
import static org.junit.Assert.assertEquals;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.block;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.blockConfiguration;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.dateAsLong;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.lsids;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.serviceIds;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.stop;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.stopTime;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.time;
import static org.onebusaway.transit_data_federation.testing.UnitTestingSupport.trip;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.realtime.api.TimepointPredictionRecord;
import org.onebusaway.realtime.api.VehicleLocationRecord;
import org.onebusaway.transit_data_federation.impl.blocks.BlockStatusServiceImpl;
import org.onebusaway.transit_data_federation.impl.blocks.ScheduledBlockLocationServiceImpl;
import org.onebusaway.transit_data_federation.impl.realtime.BlockLocationServiceImpl;
import org.onebusaway.transit_data_federation.impl.realtime.VehicleLocationRecordCacheImpl;
import org.onebusaway.transit_data_federation.impl.transit_graph.BlockEntryImpl;
import org.onebusaway.transit_data_federation.impl.transit_graph.StopEntryImpl;
import org.onebusaway.transit_data_federation.impl.transit_graph.TripEntryImpl;
import org.onebusaway.transit_data_federation.model.TargetTime;
import org.onebusaway.transit_data_federation.services.StopTimeService;
import org.onebusaway.transit_data_federation.services.StopTimeService.EFrequencyStopTimeBehavior;
import org.onebusaway.transit_data_federation.services.blocks.BlockInstance;
import org.onebusaway.transit_data_federation.services.blocks.BlockStatusService;
import org.onebusaway.transit_data_federation.services.blocks.ScheduledBlockLocation;
import org.onebusaway.transit_data_federation.services.realtime.ArrivalAndDepartureInstance;
import org.onebusaway.transit_data_federation.services.realtime.BlockLocation;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockStopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.StopTimeEntry;
import org.onebusaway.transit_data_federation.services.tripplanner.StopTimeInstance;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Tests to see if the per stop time point predictions provided by a real-time
* feed are correctly applied to the scheduled time, so the correct predicted
* arrival times are produced. Behavior for propagating times is consistent with
* the GTFS-realtime spec
* (https://developers.google.com/transit/gtfs-realtime/).
*
* @author cetin
* @author barbeau
*/
public class ArrivalAndDepartureServiceImplTest {
private ArrivalAndDepartureServiceImpl _service;
private BlockStatusService _blockStatusService;
private StopTimeService _stopTimeService;
private BlockLocationServiceImpl _blockLocationService;
// Setup current time
private long mCurrentTime = dateAsLong("2015-07-23 13:00");
private long mServiceDate = dateAsLong("2015-07-23 00:00");
// Stops
private StopEntryImpl mStopA = stop("stopA", 47.0, -122.0);
private StopEntryImpl mStopB = stop("stopB", 47.0, -128.0);
private TripEntryImpl mTripA = trip("tripA", "sA", 3000);
@Before
public void setup() {
_service = new ArrivalAndDepartureServiceImpl();
_blockStatusService = new BlockStatusServiceImpl();
_service.setBlockStatusService(_blockStatusService);
_stopTimeService = Mockito.mock(StopTimeServiceImpl.class);
_service.setStopTimeService(_stopTimeService);
_blockLocationService = new BlockLocationServiceImpl();
_blockLocationService.setLocationInterpolation(false);
_service.setBlockLocationService(_blockLocationService);
}
/**
* This method tests time point predictions upstream of a stop for *arrival*
* times.
*
* Test configuration: Time point predictions are upstream of the stop and
* include the given stop_ids, which means that the bus hasn't passed these
* bus stops yet. There are 2 bus stops which have the real time arrival times
* (time point predictions). In this case
* getArrivalsAndDeparturesForStopInTimeRange() should return the absolute
* time point prediction for particular stop that was provided by the feed,
* which replaces the scheduled time from GTFS for these stops.
*
* Current time = 13:00
* Schedule time Real-time from feed
* Stop A 13:30 13:30
* Stop B 13:40 13:50
*
* When requesting arrival estimate for Stop B, result should be 13:50 (same
* as exact prediction from real-time feed).
*/
@Test
public void testGetArrivalsAndDeparturesForStopInTimeRange01() {
// Set time point predictions for stop A
TimepointPredictionRecord tprA = new TimepointPredictionRecord();
tprA.setTimepointId(mStopA.getId());
long tprATime = createPredictedTime(time(13, 30));
tprA.setTimepointPredictedArrivalTime(tprATime);
tprA.setTripId(mTripA.getId());
// Set time point predictions for stop B
TimepointPredictionRecord tprB = new TimepointPredictionRecord();
tprB.setTimepointId(mStopB.getId());
long tprBTime = createPredictedTime(time(13, 50));
tprB.setTimepointPredictedArrivalTime(tprBTime);
tprB.setTripId(mTripA.getId());
// Call ArrivalsAndDeparturesForStopInTimeRange method in
// ArrivalAndDepartureServiceImpl
List<ArrivalAndDepartureInstance> arrivalsAndDepartures = getArrivalsAndDeparturesForStopInTimeRangeByTimepointPredictionRecord(Arrays.asList(
tprA, tprB));
long predictedArrivalTime = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
/**
* Check if the predictedArrivalTime is exactly the same as the
* TimepointPrediction.
*/
assertEquals(tprB.getTimepointPredictedArrivalTime(), predictedArrivalTime);
}
/**
* This method tests upstream time point predictions for scheduled *arrival*
* times.
*
* Test configuration: Time point predictions are upstream of the current
* stop_id, which means that the bus hasn't passed the bus stop yet. A real
* time arrival time (time point prediction) is provided for only one bus stop
* (Stop A). In this case getArrivalsAndDeparturesForStopInTimeRange() should
* calculate a new arrival time for Stop B (based on the upstream prediction
* for Stop A), which is the scheduled arrival time + the upstream deviation.
*
* Current time = 13:00
* Schedule time Real-time from feed
* Stop A 13:30 13:35
* Stop B 13:40 ---
*
* We are requesting arrival time for Stop B, which should be propagated
* downstream from Stop A's prediction, which should be 13:45 (13:40 + 5 min
* deviation from Stop A). Stop A's predicted arrival and departure should
* also be the respective scheduled arrival and departure plus the 5 min
* deviation.
*
*/
@Test
public void testGetArrivalsAndDeparturesForStopInTimeRange02() {
// Set time point predictions for stop A
TimepointPredictionRecord tprA = new TimepointPredictionRecord();
tprA.setTimepointId(mStopA.getId());
long tprATime = createPredictedTime(time(13, 35));
tprA.setTimepointPredictedArrivalTime(tprATime);
tprA.setTripId(mTripA.getId());
// Call ArrivalsAndDeparturesForStopInTimeRange method in
// ArrivalAndDepartureServiceImpl
List<ArrivalAndDepartureInstance> arrivalsAndDepartures = getArrivalsAndDeparturesForStopInTimeRangeByTimepointPredictionRecord(Arrays.asList(tprA));
long predictedArrivalTimeStopA = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
long predictedDepartureTimeStopA = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
long predictedArrivalTimeStopB = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long predictedDepartureTimeStopB = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long scheduledArrivalTimeStopA = getScheduledArrivalTimeByStopId(mTripA,
mStopA.getId());
long scheduledDepartureTimeStopA = getScheduledDepartureTimeByStopId(
mTripA, mStopA.getId());
long scheduledArrivalTimeStopB = getScheduledArrivalTimeByStopId(mTripA,
mStopB.getId());
long scheduledDepartureTimeStopB = getScheduledDepartureTimeByStopId(
mTripA, mStopB.getId());
// The time point prediction for Stop A was 5 min late, so this should be
// applied to Stop B scheduled arrival
long delta = TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopA)
- scheduledArrivalTimeStopA;
assertEquals(TimeUnit.MINUTES.toSeconds(5), delta);
// Check if the predictedArrivalTimes and predictedDepartureTimes is the
// same as the scheduledArrivalTime plus the delta
assertEquals(TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopA),
scheduledArrivalTimeStopA + delta);
assertEquals(TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopA),
scheduledDepartureTimeStopA + delta);
assertEquals(TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopB),
scheduledArrivalTimeStopB + delta);
assertEquals(TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopB),
scheduledDepartureTimeStopB + delta);
}
/**
* This method tests upstream time point predictions with only a predicted
* *departure* time.
*
* Test configuration: There is only one bus stop (Stop A) which has the real
* time departure time (time point prediction). In this case
* getArrivalsAndDeparturesForStopInTimeRange() should return the time point
* prediction for Stop A's departure time, which replaces the scheduled time
* from GTFS for this stop. For Stop B, the upstream departure prediction for
* Stop A should be propagated down to Stop B, and this deviation should be
* used to calculate Stop B's arrival and departure times.
*
* Current time = 13:00
* Schedule Arrival time Schedule Departure time Real-time departure time
* Stop A 13:30 13:35 13:30
* Stop B 13:45 13:50 ----
*
* When requesting arrival estimate for Stop A, result should be 0 (note this
* isn't currently supported - see TODO in method body).
*
* When requesting departure estimate for Stop A, result should be exactly
* same with the real-time feed's departure time for Stop A.
*
* When requesting arrival and departure estimate for Stop B, the result
* should be 5 min less then the scheduled arrival and departure times.
* Because the upstream stop departs 5 min early, OBA should subtract this 5
* min deviation from the downstream scheduled values.
*/
@Test
public void testGetArrivalsAndDeparturesForStopInTimeRange03() {
// Set time point predictions for stop A
TimepointPredictionRecord tprA = new TimepointPredictionRecord();
tprA.setTimepointId(mStopA.getId());
long tprATime = createPredictedTime(time(13, 30));
tprA.setTimepointPredictedDepartureTime(tprATime);
tprA.setTripId(mTripA.getId());
// Call ArrivalsAndDeparturesForStopInTimeRange method in
// ArrivalAndDepartureServiceImpl
List<ArrivalAndDepartureInstance> arrivalsAndDepartures = getArrivalsAndDeparturesForStopInTimeRangeByTimepointPredictionRecord(Arrays.asList(tprA));
long predictedArrivalTimeStopA = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
long predictedDepartureTimeStopA = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
/**
* Check if the predictedDepartureTime is exactly the same with
* TimepointPrediction.
*/
assertEquals(tprA.getTimepointPredictedDepartureTime(),
predictedDepartureTimeStopA);
/**
* TODO - Fully support both real-time arrival and departure times for each
* stop in OBA
*
* We're currently limited by OBA's internal data model which contains only
* one deviation per stop. By GTFS-rt spec, if no real-time arrival
* information is given for a stop, then the scheduled arrival should be
* used. In our case here, we're getting a real-time departure for Stop A
* (and no real-time arrival time for Stop A), but then we're showing the
* real-time departure info for Stop A as the real-time arrival time for
* Stop A. So, we're effectively propagating the real-time value backwards
* within the same stop. The correct value for predictedArrivalTimeStopA is
* actually 0, because we don't have any real-time arrival information for
* Stop A (or upstream of Stop A).
*
* So, the below assertion is currently commented out, as it fails. Future
* work should overhaul OBA's data model to support more than one real-time
* deviation per stop. When this is correctly implemented, the below
* assertion should be uncommented and it should pass.
*/
// assertEquals(0, predictedArrivalTimeStopA);
/**
* Test for Stop B
*/
long predictedArrivalTimeStopB = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long predictedDepartureTimeStopB = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long scheduledDepartureTimeForStopA = getScheduledDepartureTimeByStopId(
mTripA, mStopA.getId());
long scheduledArrivalTimeForStopB = getScheduledArrivalTimeByStopId(mTripA,
mStopB.getId());
long scheduledDepartureTimeForStopB = getScheduledDepartureTimeByStopId(
mTripA, mStopB.getId());
// Calculate the departure time difference from the upstream stop
long deltaB = (scheduledDepartureTimeForStopA - TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopA));
/**
* Check if the predictedArrivalTime is 5 min less then the scheduled
* arrival time for stop B.
*/
assertEquals(TimeUnit.MINUTES.toSeconds(5), deltaB);
assertEquals(scheduledArrivalTimeForStopB - deltaB,
TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopB));
/**
* Check if the predictedDepartureTime is 5 min less then the scheduled
* departure time for stop B.
*/
assertEquals(scheduledDepartureTimeForStopB - deltaB,
TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopB));
}
/**
* This method tests upstream time point predictions with both predicted
* arrival and departure times.
*
* Test configuration: Time point predictions are upstream and include the
* current stop_id, which means that the bus hasn't passed the bus stop yet.
* There is only one bus stop (Stop A) which has the real time arrival and
* departure times (time point prediction). In this case
* getArrivalsAndDeparturesForStopInTimeRange() should return absolute time
* point prediction for Stop A's departure time, which replaces the scheduled
* time from GTFS for this stop. Stop B's predictions should be derived from
* the upstream predictions provided for Stop A.
*
* Current time = 13:00
* Schedule Arrival time Schedule Departure time Real-time arrival time Real-time departure time
* Stop A 13:30 13:35 13:20 13:30
* Stop B 13:45 13:50 ----- -----
*
* When requesting arrival estimate for Stop A, result should be 13:20
* (predicted real-time arrival time). Note that this currently isn't support
* - see TODO statement in method body.
*
* When requesting departure estimate for Stop A, result should be 13:30
* (predicted real-time departure time).
*
* When requesting arrival and departure estimates for Stop B, results should
* be 5 min less then the scheduled arrival and departure times. Because the
* upstream Stop A departs 5 min early, OBA should subtract this 5 min from
* the downstream estimates.
*/
@Test
public void testGetArrivalsAndDeparturesForStopInTimeRange04() {
// Set time point predictions for stop A
TimepointPredictionRecord tprA = new TimepointPredictionRecord();
tprA.setTimepointId(mStopA.getId());
long tprADepartureTime = createPredictedTime(time(13, 30));
tprA.setTimepointPredictedDepartureTime(tprADepartureTime);
long tprAArrivalTime = createPredictedTime(time(13, 20));
tprA.setTimepointPredictedArrivalTime(tprAArrivalTime);
tprA.setTripId(mTripA.getId());
// Call ArrivalsAndDeparturesForStopInTimeRange method in
// ArrivalAndDepartureServiceImpl
List<ArrivalAndDepartureInstance> arrivalsAndDepartures = getArrivalsAndDeparturesForStopInTimeRangeByTimepointPredictionRecord(Arrays.asList(tprA));
long predictedDepartureTimeStopA = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
/**
* Check if the predictedDepartureTime is exactly the same with
* TimepointPrediction.
*/
assertEquals(tprA.getTimepointPredictedDepartureTime(),
predictedDepartureTimeStopA);
/**
* TODO - Fully support both real-time arrival and departure times for each
* stop in OBA
*
* We're currently limited by OBA's internal data model which contains only
* one deviation per stop. By GTFS-rt spec, if real-time arrival information
* is given for a stop, then it should be used. In our case we expect to get
* 13:20 as predictedArrivalTime, as this is the predicted arrival time
* supplied in the real-time feed. However, we are getting 13:25 as
* predictedArrivalTime, which is actually the predictedDepartureTime for
* this stop. This is because OBA must prefer predicted departure times to
* arrival times when only one deviation per stop is supported, as the
* departure times are what should be propagated downstream.
*
* So, the below assertion is currently commented out, as it fails. Future
* work should overhaul OBA's data model to support more than one real-time
* deviation per stop. When this is correctly implemented, the below
* assertion should be uncommented and it should pass.
*/
// long predictedArrivalTimeStopA = getPredictedArrivalTimeByStopId(
// arrivalsAndDepartures, stopA.getId());
//
// assertEquals(TimeUnit.MILLISECONDS.toSeconds(tprA.getTimepointPredictedArrivalTime()),
// TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopA));
/**
* Test for Stop B
*/
long scheduledDepartureTimeForStopA = getScheduledDepartureTimeByStopId(
mTripA, mStopA.getId());
long predictedArrivalTimeStopB = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long predictedDepartureTimeStopB = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long scheduledArrivalTimeForStopB = getScheduledArrivalTimeByStopId(mTripA,
mStopB.getId());
long scheduledDepartureTimeForStopB = getScheduledDepartureTimeByStopId(
mTripA, mStopB.getId());
// Calculate the departure time difference from the upstream stop
long deltaB = scheduledDepartureTimeForStopA
- TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopA);
/**
* Check if the predictedDepartureTime is 5 min less then the scheduled
* departure time for stop B.
*/
assertEquals(TimeUnit.MINUTES.toSeconds(5), deltaB);
assertEquals(scheduledDepartureTimeForStopB - deltaB,
TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopB));
/**
* Check if the predictedArrivalTime is 5 min less then the scheduled
* arrival time for stop B.
*/
assertEquals(scheduledArrivalTimeForStopB - deltaB,
TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopB));
}
/**
* This method tests a request for an arrival time for a stop, when the
* current time is greater than the arrival time prediction for that stop
* (Stop B). In other words, the bus is predicted to have already passed the
* stop (Stop B).
*
* Test configuration: There are 2 bus stops which have the real time arrival
* times (time point predictions) - Stop A and B. In this case
* getArrivalsAndDeparturesForStopInTimeRange() should return last received
* time point prediction for particular stop we're requesting information for.
*
* Current time = 14:00
* Schedule time Real-time from feed
* Stop A 13:30 13:30
* Stop B 13:40 13:50
*
*/
@Test
public void testGetArrivalsAndDeparturesForStopInTimeRange05() {
// Override the current time with a later time than the time point
// predictions
mCurrentTime = dateAsLong("2015-07-23 14:00");
// Set time point predictions for stop A
TimepointPredictionRecord tprA = new TimepointPredictionRecord();
tprA.setTimepointId(mStopA.getId());
long tprATime = createPredictedTime(time(13, 30));
tprA.setTimepointPredictedArrivalTime(tprATime);
tprA.setTripId(mTripA.getId());
// Set time point predictions for stop B
TimepointPredictionRecord tprB = new TimepointPredictionRecord();
tprB.setTimepointId(mStopB.getId());
long tprBTime = createPredictedTime(time(13, 50));
tprB.setTimepointPredictedArrivalTime(tprBTime);
tprB.setTripId(mTripA.getId());
// Call ArrivalsAndDeparturesForStopInTimeRange method in
// ArrivalAndDepartureServiceImpl
List<ArrivalAndDepartureInstance> arrivalsAndDepartures = getArrivalsAndDeparturesForStopInTimeRangeByTimepointPredictionRecord(Arrays.asList(
tprA, tprB));
long predictedArrivalTimeStopA = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
long predictedArrivalTimeStopB = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
/**
* Check if the predictedArrivalTime is exactly the same as
* TimepointPrediction for both stops
*/
assertEquals(tprA.getTimepointPredictedArrivalTime(),
predictedArrivalTimeStopA);
assertEquals(tprB.getTimepointPredictedArrivalTime(),
predictedArrivalTimeStopB);
/**
* Check if the predictedDepartureTimes and scheduledDepartureTimes have the
* same delta as arrival predictions and scheduled arrival times for both
* stops
*/
long predictedDepartureTimeStopA = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
long predictedDepartureTimeStopB = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long scheduledArrivalTimeForStopA = getScheduledArrivalTimeByStopId(mTripA,
mStopA.getId());
long scheduledArrivalTimeForStopB = getScheduledArrivalTimeByStopId(mTripA,
mStopB.getId());
long scheduledDepartureTimeForStopA = getScheduledDepartureTimeByStopId(
mTripA, mStopA.getId());
long scheduledDepartureTimeForStopB = getScheduledDepartureTimeByStopId(
mTripA, mStopB.getId());
long deltaA = TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopA)
- scheduledArrivalTimeForStopA;
assertEquals(scheduledDepartureTimeForStopA + deltaA,
TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopA));
long deltaB = TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopB)
- scheduledArrivalTimeForStopB;
assertEquals(scheduledDepartureTimeForStopB + deltaB,
TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopB));
}
/**
* This method tests to make sure upstream propagation isn't happening.
*
* Test configuration: Time point predictions are downstream of Stop A, which
* means that the bus is predicted to have already passed the bus stop. There
* only one bus stop (Stop B) which has a real time arrival time (time point
* prediction). In this case getArrivalsAndDeparturesForStopInTimeRange() for
* Stop A should return a predicted arrival time = 0, indicating that no
* real-time information is available for Stop A.
*
* Current time = 14:00
* Schedule time Real-time from feed
* Stop A 13:30 -----
* Stop B 13:45 13:40
*
* Since the bus already passed the bus stop A, and no real-time information
* is available for Stop A, OBA should NOT propagate arrival estimate for Stop
* B upstream to Stop A.
*/
@Test
public void testGetArrivalsAndDeparturesForStopInTimeRange06() {
// Override the current time with a later time than the time point
// predictions
mCurrentTime = dateAsLong("2015-07-23 14:00");
// Set time point predictions for stop B
TimepointPredictionRecord tprB = new TimepointPredictionRecord();
tprB.setTimepointId(mStopB.getId());
long tprBTime = createPredictedTime(time(13, 40));
tprB.setTimepointPredictedArrivalTime(tprBTime);
tprB.setTripId(mTripA.getId());
// Call ArrivalsAndDeparturesForStopInTimeRange method in
// ArrivalAndDepartureServiceImpl
List<ArrivalAndDepartureInstance> arrivalsAndDepartures = getArrivalsAndDeparturesForStopInTimeRangeByTimepointPredictionRecord(Arrays.asList(tprB));
long predictedArrivalTimeStopB = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
/**
* Check if the predictedArrivalTime for stop B is exactly the same as
* TimepointPredictionRecord.
*/
assertEquals(tprB.getTimepointPredictedArrivalTime(),
predictedArrivalTimeStopB);
/**
* Check predicted departure for Stop B too, to make sure its propagated
* from provided predicted arrival time
*/
long scheduledArrivalTimeForStopB = getScheduledArrivalTimeByStopId(mTripA,
mStopB.getId());
long scheduledDepartureTimeForStopB = getScheduledDepartureTimeByStopId(
mTripA, mStopB.getId());
long predictedDepartureTimeStopB = getPredictedDepartureTimeByStopId(
arrivalsAndDepartures, mStopB.getId());
long deltaB = TimeUnit.MILLISECONDS.toSeconds(predictedArrivalTimeStopB)
- scheduledArrivalTimeForStopB;
assertEquals(scheduledDepartureTimeForStopB + deltaB,
TimeUnit.MILLISECONDS.toSeconds(predictedDepartureTimeStopB));
/**
* Make sure the predictedArrivalTime for stop A is equals to 0 - in other
* words, we should show no real-time information for this stop and use the
* scheduled time instead.
*/
long predictedArrivalTimeA = getPredictedArrivalTimeByStopId(
arrivalsAndDepartures, mStopA.getId());
assertEquals(0, predictedArrivalTimeA);
}
/**
* Set up the BlockLocationServiceImpl for the test, using the given
* timepointPredictions
*
* @param timepointPredictions real-time predictions to apply to the
* BlockLocationServiceImpl
* @return a list of ArrivalAndDepartureInstances which is used to access
* predicted arrival/departure times for a stop, for comparison
* against the expected values
*/
private List<ArrivalAndDepartureInstance> getArrivalsAndDeparturesForStopInTimeRangeByTimepointPredictionRecord(
List<TimepointPredictionRecord> timepointPredictions) {
TargetTime target = new TargetTime(mCurrentTime, mCurrentTime);
// Setup block
BlockEntryImpl block = block("blockA");
stopTime(0, mStopA, mTripA, time(13, 30), time(13, 35), 1000);
stopTime(1, mStopB, mTripA, time(13, 45), time(13, 50), 2000);
BlockConfigurationEntry blockConfig = blockConfiguration(block,
serviceIds(lsids("sA"), lsids()), mTripA);
BlockStopTimeEntry bstAA = blockConfig.getStopTimes().get(0);
BlockStopTimeEntry bstAB = blockConfig.getStopTimes().get(1);
BlockStopTimeEntry bstBA = blockConfig.getStopTimes().get(0);
// Setup block location instance for trip B
BlockInstance blockInstance = new BlockInstance(blockConfig, mServiceDate);
BlockLocation blockLocationB = new BlockLocation();
blockLocationB.setActiveTrip(bstBA.getTrip());
blockLocationB.setBlockInstance(blockInstance);
blockLocationB.setClosestStop(bstBA);
blockLocationB.setDistanceAlongBlock(400);
blockLocationB.setInService(true);
blockLocationB.setNextStop(bstAA);
blockLocationB.setPredicted(false);
blockLocationB.setScheduledDistanceAlongBlock(400);
blockLocationB.setTimepointPredictions(timepointPredictions);
// Mock StopTimeInstance with time frame
long stopTimeFrom = dateAsLong("2015-07-23 00:00");
long stopTimeTo = dateAsLong("2015-07-24 00:00");
StopTimeInstance sti1 = new StopTimeInstance(bstAB,
blockInstance.getState());
ArrivalAndDepartureInstance in1 = new ArrivalAndDepartureInstance(sti1);
in1.setBlockLocation(blockLocationB);
in1.setPredictedArrivalTime((long) (in1.getScheduledArrivalTime()));
in1.setPredictedDepartureTime((long) (in1.getScheduledDepartureTime()));
StopTimeInstance sti2 = new StopTimeInstance(bstBA,
blockInstance.getState());
ArrivalAndDepartureInstance in2 = new ArrivalAndDepartureInstance(sti2);
in2.setBlockLocation(blockLocationB);
Date fromTimeBuffered = new Date(stopTimeFrom
- _blockStatusService.getRunningLateWindow() * 1000);
Date toTimeBuffered = new Date(stopTimeTo
+ _blockStatusService.getRunningEarlyWindow() * 1000);
Mockito.when(
_stopTimeService.getStopTimeInstancesInTimeRange(mStopB,
fromTimeBuffered, toTimeBuffered,
EFrequencyStopTimeBehavior.INCLUDE_UNSPECIFIED)).thenReturn(
Arrays.asList(sti1, sti2));
// Create and add vehicle location record cache
VehicleLocationRecordCacheImpl _cache = new VehicleLocationRecordCacheImpl();
VehicleLocationRecord vlr = new VehicleLocationRecord();
vlr.setBlockId(blockLocationB.getBlockInstance().getBlock().getBlock().getId());
vlr.setTripId(mTripA.getId());
vlr.setTimepointPredictions(blockLocationB.getTimepointPredictions());
vlr.setTimeOfRecord(mCurrentTime);
vlr.setVehicleId(new AgencyAndId("1", "123"));
// Create ScheduledBlockLocation for cache
ScheduledBlockLocation sbl = new ScheduledBlockLocation();
sbl.setActiveTrip(blockLocationB.getActiveTrip());
// Add data to cache
_cache.addRecord(blockInstance, vlr, sbl, null);
_blockLocationService.setVehicleLocationRecordCache(_cache);
ScheduledBlockLocationServiceImpl scheduledBlockLocationServiceImpl = new ScheduledBlockLocationServiceImpl();
_blockLocationService.setScheduledBlockLocationService(scheduledBlockLocationServiceImpl);
// Call ArrivalAndDepartureService
return _service.getArrivalsAndDeparturesForStopInTimeRange(mStopB, target,
stopTimeFrom, stopTimeTo);
}
//
// Helper methods
//
private long getPredictedArrivalTimeByStopId(
List<ArrivalAndDepartureInstance> arrivalsAndDepartures,
AgencyAndId stopId) {
for (ArrivalAndDepartureInstance adi : arrivalsAndDepartures) {
if (adi.getStop().getId().equals(stopId)) {
return adi.getPredictedArrivalTime();
}
}
return 0;
}
private long getPredictedDepartureTimeByStopId(
List<ArrivalAndDepartureInstance> arrivalsAndDepartures,
AgencyAndId stopId) {
for (ArrivalAndDepartureInstance adi : arrivalsAndDepartures) {
if (adi.getStop().getId().equals(stopId)) {
return adi.getPredictedDepartureTime();
}
}
return 0;
}
private long getScheduledArrivalTimeByStopId(TripEntryImpl trip,
AgencyAndId id) {
for (StopTimeEntry ste : trip.getStopTimes()) {
if (ste.getStop().getId().equals(id)) {
return ste.getArrivalTime() + mServiceDate / 1000;
}
}
return 0;
}
private long getScheduledDepartureTimeByStopId(TripEntryImpl trip,
AgencyAndId id) {
for (StopTimeEntry ste : trip.getStopTimes()) {
if (ste.getStop().getId().equals(id)) {
return ste.getDepartureTime() + mServiceDate / 1000;
}
}
return 0;
}
private long createPredictedTime(int time) {
return (mServiceDate / 1000 + time) * 1000;
}
}