Package org.opentripplanner.routing.core

Source Code of org.opentripplanner.routing.core.TestTransfers

/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. */

package org.opentripplanner.routing.core;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;

import junit.framework.TestCase;

import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.Stop;
import org.onebusaway.gtfs.model.Trip;
import org.onebusaway.gtfs.model.calendar.CalendarServiceData;
import org.onebusaway.gtfs.model.calendar.ServiceDate;
import org.opentripplanner.ConstantsForTests;
import org.opentripplanner.gtfs.GtfsContext;
import org.opentripplanner.gtfs.GtfsLibrary;
import org.opentripplanner.routing.algorithm.GenericAStar;
import org.opentripplanner.routing.edgetype.SimpleTransfer;
import org.opentripplanner.routing.edgetype.TimedTransferEdge;
import org.opentripplanner.routing.edgetype.Timetable;
import org.opentripplanner.routing.edgetype.TimetableResolver;
import org.opentripplanner.routing.edgetype.TransitBoardAlight;
import org.opentripplanner.routing.edgetype.TripPattern;
import org.opentripplanner.routing.edgetype.factory.GTFSPatternHopFactory;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.impl.DefaultStreetVertexIndexFactory;
import org.opentripplanner.routing.spt.GraphPath;
import org.opentripplanner.routing.spt.ShortestPathTree;
import org.opentripplanner.routing.vertextype.TransitStop;
import org.opentripplanner.updater.stoptime.TimetableSnapshotSource;
import org.opentripplanner.util.TestUtils;

import com.google.transit.realtime.GtfsRealtime.TripDescriptor;
import com.google.transit.realtime.GtfsRealtime.TripUpdate;
import com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent;
import com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate;
import com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate.ScheduleRelationship;

/**
* This is a singleton class to hold graph data between test runs, since loading it is slow.
*/
class Context {
    public Graph graph;

    public GenericAStar aStar;

    private static Context instance = null;

    public static Context getInstance() throws IOException {
        if (instance == null) {
            instance = new Context();
        }
        return instance;
    }

    public Context() throws IOException {
        // Create a star search
        aStar = new GenericAStar();

        // Create graph
        GtfsContext context = GtfsLibrary.readGtfs(new File(ConstantsForTests.FAKE_GTFS));
        graph = spy(new Graph());
        GTFSPatternHopFactory factory = new GTFSPatternHopFactory(context);
        factory.run(graph);
        graph.index(new DefaultStreetVertexIndexFactory());
        graph.putService(CalendarServiceData.class,
                GtfsLibrary.createCalendarServiceData(context.getDao()));

        // Add simple transfer to make transfer possible between N-K and F-H
        createSimpleTransfer("agency:K", "agency:F", 100);

        // Add simple transfer to make transfer possible between O-P and U-V
        createSimpleTransfer("agency:P", "agency:U", 100);

        // Add simple transfer to make transfer possible between U-V and I-J
        createSimpleTransfer("agency:V", "agency:I", 100);

        // Create dummy TimetableResolver
        TimetableResolver resolver = new TimetableResolver();

        // Mock TimetableSnapshotSource to return dummy TimetableResolver
        TimetableSnapshotSource timetableSnapshotSource = mock(TimetableSnapshotSource.class);

        when(timetableSnapshotSource.getTimetableSnapshot()).thenReturn(resolver);

        graph.timetableSnapshotSource = (timetableSnapshotSource);
    }

    /**
     * Create simple transfer edge between two vertices given their labels
     * @param from is label of from vertex
     * @param to is label of to vertex
     * @param distance is distance of transfer
     */
    private void createSimpleTransfer(String from, String to, int distance) {
        TransitStop fromv = ((TransitStop) graph.getVertex(from));
        TransitStop tov = ((TransitStop) graph.getVertex(to));
        new SimpleTransfer(fromv, tov, distance, null);
    }
}

/**
* Test transfers, mostly stop-to-stop transfers.
*/
public class TestTransfers extends TestCase {
    private Graph graph;

    private GenericAStar aStar;

    public void setUp() throws Exception {
        // Get graph and a star from singleton class
        graph = Context.getInstance().graph;
        aStar = Context.getInstance().aStar;
    }

    /**
     * Plan journey without optimization and return list of states and edges
     * @param options are options to use for planning the journey
     * @return ordered list of states and edges in the journey
     */
    private GraphPath planJourney(RoutingRequest options) {
        return planJourney(options, false);
    }

    /**
     * Plan journey and return list of states and edges
     * @param options are options to use for planning the journey
     * @param optimize is true when optimization should be used
     * @return ordered list of states and edges in the journey
     */
    private GraphPath planJourney(RoutingRequest options, boolean optimize) {
        // Calculate route and convert to path
        ShortestPathTree spt = aStar.getShortestPathTree(options);
        GraphPath path = spt.getPath(options.rctx.target, optimize);

        // Return list of states and edges in the journey
        return path;
    }

    private List<Trip> extractTrips(GraphPath path) {
        // Get all trips in order
        List<Trip> trips = new ArrayList<Trip>();
        if (path != null) {
            for (State s : path.states) {
                if (s.getBackMode() != null && s.getBackMode().isTransit()) {
                    Trip trip = s.getBackTrip();
                    if (trip != null && !trips.contains(trip)) {
                        trips.add(trip);
                    }
                }
            }
        }

        // Return trips
        return trips;
    }

    /**
     * Apply an update to a table trip pattern and check whether the update was applied correctly
     */
    private void applyUpdateToTripPattern(TripPattern pattern, String tripId, String stopId,
            int stopSeq, int arrive, int depart, ScheduleRelationship scheduleRelationship,
            int timestamp, ServiceDate serviceDate) throws ParseException {
        TimetableResolver snapshot = graph.timetableSnapshotSource.getTimetableSnapshot();
        Timetable timetable = snapshot.resolve(pattern, serviceDate);
        TimeZone timeZone = new SimpleTimeZone(-7, "PST");
        long today = serviceDate.getAsDate(timeZone).getTime() / 1000;
        TripDescriptor.Builder tripDescriptorBuilder = TripDescriptor.newBuilder();

        tripDescriptorBuilder.setTripId(tripId);

        StopTimeEvent.Builder departStopTimeEventBuilder = StopTimeEvent.newBuilder();
        StopTimeEvent.Builder arriveStopTimeEventBuilder = StopTimeEvent.newBuilder();

        departStopTimeEventBuilder.setTime(today + depart);
        arriveStopTimeEventBuilder.setTime(today + arrive);

        StopTimeUpdate.Builder stopTimeUpdateBuilder = StopTimeUpdate.newBuilder();

        stopTimeUpdateBuilder.setStopSequence(stopSeq);
        stopTimeUpdateBuilder.setDeparture(departStopTimeEventBuilder);
        stopTimeUpdateBuilder.setArrival(arriveStopTimeEventBuilder);
        stopTimeUpdateBuilder.setScheduleRelationship(scheduleRelationship);

        TripUpdate.Builder tripUpdateBuilder = TripUpdate.newBuilder();

        tripUpdateBuilder.setTrip(tripDescriptorBuilder);
        tripUpdateBuilder.addStopTimeUpdate(0, stopTimeUpdateBuilder);

        TripUpdate tripUpdate = tripUpdateBuilder.build();

        assertTrue(timetable.update(tripUpdate, timeZone, serviceDate));
    }

    public void testStopToStopTransfer() throws Exception {
        // Replace the transfer table with an empty table
        TransferTable table = new TransferTable();
        when(graph.getTransferTable()).thenReturn(table);

        // Compute a normal path between two stops
        Vertex origin = graph.getVertex("agency:N");
        Vertex destination = graph.getVertex("agency:H");

        // Set options like time and routing context
        RoutingRequest options = new RoutingRequest();
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 11, 11, 11, 0);
        options.setRoutingContext(graph, origin, destination);

        // Plan journey
        GraphPath path;
        List<Trip> trips;
        path = planJourney(options);
        trips = extractTrips(path);
        // Validate result
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.2", trips.get(1).getId().getId());

        // Add transfer to table, transfer time was 27600 seconds
        Stop stopK = new Stop();
        stopK.setId(new AgencyAndId("agency", "K"));
        Stop stopF = new Stop();
        stopF.setId(new AgencyAndId("agency", "F"));
        table.addTransferTime(stopK, stopF, null, null, null, null, 27601);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check whether a later second trip was taken
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.3", trips.get(1).getId().getId());

        // Revert the graph, thus using the original transfer table again
        reset(graph);
    }

    public void testStopToStopTransferInReverse() throws Exception {
        // Replace the transfer table with an empty table
        TransferTable table = new TransferTable();
        when(graph.getTransferTable()).thenReturn(table);

        // Compute a normal path between two stops
        Vertex origin = graph.getVertex("agency:N");
        Vertex destination = graph.getVertex("agency:H");

        // Set options like time and routing context
        RoutingRequest options = new RoutingRequest();
        options.setArriveBy(true);
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 12, 1, 0, 0);
        options.setRoutingContext(graph, origin, destination);

        // Plan journey
        GraphPath path;
        List<Trip> trips;
        path = planJourney(options, true);
        trips = extractTrips(path);
        // Validate result
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.2", trips.get(1).getId().getId());

        // Add transfer to table, transfer time was 27600 seconds
        Stop stopK = new Stop();
        stopK.setId(new AgencyAndId("agency", "K"));
        Stop stopF = new Stop();
        stopF.setId(new AgencyAndId("agency", "F"));
        table.addTransferTime(stopK, stopF, null, null, null, null, 27601);

        // Plan journey
        path = planJourney(options, true);
        trips = extractTrips(path);
        // Check whether a later second trip was taken
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.3", trips.get(1).getId().getId());

        // Revert the graph, thus using the original transfer table again
        reset(graph);
    }

    public void testStopToStopTransferWithFrequency() throws Exception {
        // Replace the transfer table with an empty table
        TransferTable table = new TransferTable();
        when(graph.getTransferTable()).thenReturn(table);

        // Compute a normal path between two stops
        Vertex origin = graph.getVertex("agency:O");
        Vertex destination = graph.getVertex("agency:V");

        // Set options like time and routing context
        RoutingRequest options = new RoutingRequest();
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 11, 13, 11, 0);
        options.setRoutingContext(graph, origin, destination);

        // Plan journey
        GraphPath path;
        List<Trip> trips;
        path = planJourney(options);
        trips = extractTrips(path);
        // Validate result
        assertEquals("10.5", trips.get(0).getId().getId());
        assertEquals("15.1", trips.get(1).getId().getId());
        // Find state with FrequencyBoard back edge and save time of that state
        long time = -1;
        for (State s : path.states) {
            if (s.getBackEdge() instanceof TransitBoardAlight && ((TransitBoardAlight)s.getBackEdge()).boarding)  {
                time = s.getTimeSeconds(); // find the final board edge, don't break
            }
        }
        assertTrue(time >= 0);

        // Add transfer to table such that the next trip will be chosen
        // (there are 3600 seconds between trips), transfer time was 75 seconds
        Stop stopP = new Stop();
        stopP.setId(new AgencyAndId("agency", "P"));
        Stop stopU = new Stop();
        stopU.setId(new AgencyAndId("agency", "U"));
        table.addTransferTime(stopP, stopU, null, null, null, null, 3675);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check whether a later second trip was taken
        assertEquals("10.5", trips.get(0).getId().getId());
        assertEquals("15.1", trips.get(1).getId().getId());
        // Find state with FrequencyBoard back edge and save time of that state
        long newTime = -1;
        for (State s : path.states) {
            if (s.getBackEdge() instanceof TransitBoardAlight && ((TransitBoardAlight)s.getBackEdge()).boarding)  {
                newTime = s.getTimeSeconds(); // find the final board edge, don't break
            }
        }
        assertTrue(newTime >= 0);
        assertTrue(newTime > time);
        assertEquals(3600, newTime - time);

        // Revert the graph, thus using the original transfer table again
        reset(graph);
    }

    public void testStopToStopTransferWithFrequencyInReverse() throws Exception {
        // Replace the transfer table with an empty table
        TransferTable table = new TransferTable();
        when(graph.getTransferTable()).thenReturn(table);

        // Compute a normal path between two stops
        @SuppressWarnings("deprecation")
        Vertex origin = graph.getVertex("agency:U");
        @SuppressWarnings("deprecation")
        Vertex destination = graph.getVertex("agency:J");

        // Set options like time and routing context
        RoutingRequest options = new RoutingRequest();
        options.setArriveBy(true);
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 11, 11, 11, 0);
        options.setRoutingContext(graph, origin, destination);

        // Plan journey
        GraphPath path;
        List<Trip> trips;
        path = planJourney(options);
        trips = extractTrips(path);
        // Validate result
        assertEquals("15.1", trips.get(0).getId().getId());
        assertEquals("5.1", trips.get(1).getId().getId());
        // Find state with FrequencyBoard back edge and save time of that state
        long time = -1;
        for (State s : path.states) {
            if (s.getBackEdge() instanceof TransitBoardAlight
                    && s.getBackState() != null) {
                time = s.getBackState().getTimeSeconds();
                break;
            }
        }
        assertTrue(time >= 0);

        // Add transfer to table such that the next trip will be chosen
        // (there are 3600 seconds between trips), transfer time was 75 seconds
        Stop stopV = new Stop();
        stopV.setId(new AgencyAndId("agency", "V"));
        Stop stopI = new Stop();
        stopI.setId(new AgencyAndId("agency", "I"));
        table.addTransferTime(stopV, stopI, null, null, null, null, 3675);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check whether a later second trip was taken
        assertEquals("15.1", trips.get(0).getId().getId());
        assertEquals("5.1", trips.get(1).getId().getId());
        // Find state with FrequencyBoard back edge and save time of that state
        long newTime = -1;
        for (State s : path.states) {
            if (s.getBackEdge() instanceof TransitBoardAlight
                    && s.getBackState() != null) {
                newTime = s.getBackState().getTimeSeconds();
                break;
            }
        }
        assertTrue(newTime >= 0);
        assertTrue(newTime < time);
        assertEquals(3600, time - newTime);

        // Revert the graph, thus using the original transfer table again
        reset(graph);
    }

    public void testForbiddenStopToStopTransfer() throws Exception {
        // Replace the transfer table with an empty table
        TransferTable table = new TransferTable();
        when(graph.getTransferTable()).thenReturn(table);

        // Compute a normal path between two stops
        Vertex origin = graph.getVertex("agency:N");
        Vertex destination = graph.getVertex("agency:H");

        // Set options like time and routing context
        RoutingRequest options = new RoutingRequest();
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 11, 11, 11, 0);
        options.setRoutingContext(graph, origin, destination);

        // Plan journey
        GraphPath path;
        List<Trip> trips;
        path = planJourney(options);
        trips = extractTrips(path);
        // Validate result
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.2", trips.get(1).getId().getId());

        // Add forbidden transfer to table
        Stop stopK = new Stop();
        stopK.setId(new AgencyAndId("agency", "K"));
        Stop stopF = new Stop();
        stopF.setId(new AgencyAndId("agency", "F"));
        table.addTransferTime(stopK, stopF, null, null, null, null,
                StopTransfer.FORBIDDEN_TRANSFER);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check that no trip was returned
        assertEquals(0, trips.size());

        // Revert the graph, thus using the original transfer table again
        reset(graph);
    }

    public void testForbiddenStopToStopTransferWithFrequencyInReverse() throws Exception {
        // Replace the transfer table with an empty table
        TransferTable table = new TransferTable();
        when(graph.getTransferTable()).thenReturn(table);

        // Compute a normal path between two stops
        Vertex origin = graph.getVertex("agency:U");
        Vertex destination = graph.getVertex("agency:J");

        // Set options like time and routing context
        RoutingRequest options = new RoutingRequest();
        options.setArriveBy(true);
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 11, 11, 11, 0);
        options.setRoutingContext(graph, origin, destination);

        // Plan journey
        GraphPath path;
        List<Trip> trips;
        path = planJourney(options);
        trips = extractTrips(path);
        // Validate result
        assertEquals("15.1", trips.get(0).getId().getId());
        assertEquals("5.1", trips.get(1).getId().getId());

        // Add forbidden transfer to table
        Stop stopV = new Stop();
        stopV.setId(new AgencyAndId("agency", "V"));
        Stop stopI = new Stop();
        stopI.setId(new AgencyAndId("agency", "I"));
        table.addTransferTime(stopV, stopI, null, null, null, null,
                StopTransfer.FORBIDDEN_TRANSFER);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check that no trip was returned
        assertEquals(0, trips.size());

        // Revert the graph, thus using the original transfer table again
        reset(graph);
    }

    public void testTimedStopToStopTransfer() throws Exception {
        ServiceDate serviceDate = new ServiceDate(2009, 07, 11);

        // Replace the transfer table with an empty table
        TransferTable table = new TransferTable();
        when(graph.getTransferTable()).thenReturn(table);

        // Compute a normal path between two stops
        Vertex origin = graph.getVertex("agency:N");
        Vertex destination = graph.getVertex("agency:H");

        // Set options like time and routing context
        RoutingRequest options = new RoutingRequest();
        options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 7, 11, 11, 11, 0);
        options.setRoutingContext(graph, origin, destination);

        // Plan journey
        GraphPath path;
        List<Trip> trips;
        path = planJourney(options);
        trips = extractTrips(path);
        // Validate result
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.2", trips.get(1).getId().getId());

        // Add timed transfer to table
        Stop stopK = new Stop();
        stopK.setId(new AgencyAndId("agency", "K"));
        Stop stopF = new Stop();
        stopF.setId(new AgencyAndId("agency", "F"));
        table.addTransferTime(stopK, stopF, null, null, null, null, StopTransfer.TIMED_TRANSFER);
        // Don't forget to also add a TimedTransferEdge
        Vertex fromVertex = graph.getVertex("agency:K_arrive");
        Vertex toVertex = graph.getVertex("agency:F_depart");
        TimedTransferEdge timedTransferEdge = new TimedTransferEdge(fromVertex, toVertex);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check whether the trips are still the same
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.2", trips.get(1).getId().getId());

        // Now apply a real-time update: let the to-trip be early by 27600 seconds,
        // resulting in a transfer time of 0 seconds
        Trip trip = graph.index.tripForId.get(new AgencyAndId("agency", "4.2"));
        TripPattern pattern = graph.index.patternForTrip.get(trip);
        applyUpdateToTripPattern(pattern, "4.2", "F", 1, 55200, 55200,
                ScheduleRelationship.SCHEDULED, 0, serviceDate);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check whether the trips are still the same
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.2", trips.get(1).getId().getId());

        // Now apply a real-time update: let the to-trip be early by 27601 seconds,
        // resulting in a transfer time of -1 seconds
        applyUpdateToTripPattern(pattern, "4.2", "F", 1, 55199, 55199,
                ScheduleRelationship.SCHEDULED, 0, serviceDate);

        // Plan journey
        path = planJourney(options);
        trips = extractTrips(path);
        // Check whether a later second trip was taken
        assertEquals("8.1", trips.get(0).getId().getId());
        assertEquals("4.3", trips.get(1).getId().getId());

        // "Revert" the real-time update
        applyUpdateToTripPattern(pattern, "4.2", "F", 1, 82800, 82800,
                ScheduleRelationship.SCHEDULED, 0, serviceDate);
        // Remove the timed transfer from the graph
        timedTransferEdge.detach(graph);
        // Revert the graph, thus using the original transfer table again
        reset(graph);
    }
}
TOP

Related Classes of org.opentripplanner.routing.core.TestTransfers

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.