Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/dev-2.x' into fares-refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardehrenfried committed Jan 16, 2025
2 parents 0a49291 + 1030408 commit 9513ded
Show file tree
Hide file tree
Showing 312 changed files with 8,099 additions and 2,474 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/performance-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
- name: Build graph
if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x'
run: |
cp shaded-jar/target/otp-*-SNAPSHOT-shaded.jar otp.jar
cp otp-shaded/target/otp-shaded-*-SNAPSHOT.jar otp.jar
java -Xmx32G -jar otp.jar --build --save test/performance/${{ matrix.location }}/
- name: Run speed test
Expand Down
4 changes: 4 additions & 0 deletions DEVELOPMENT_DECISION_RECORDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,7 @@ Prefer immutable types over mutable. Use builders where appropriate. See
[Avoid using records if you cannot encapsulate it properly](doc/dev/decisionrecords/RecordsPOJOsBuilders.md#records)


## GraphQL Best Practices - API Design

[Follow best practices for designing GraphQL APIs. Our APIs need to be backwards compatible as they are used
by hundreds of clients (web-pages/apps/services).](doc/dev/decisionrecords/APIGraphQLDesign.md)
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ We run a speed test (included in the code) to measure the performance for every

## Repository layout

The main Java server code is in `application/src/main/`. OTP also includes a Javascript client based on the
MapLibre mapping library in `client/src/`. This client is now used for testing, with most major
deployments building custom clients from reusable components. The Maven build produces a unified ("shaded")
JAR file at `shaded-jar/target/otp-VERSION.jar` containing all necessary code and dependencies to run OpenTripPlanner.
The main Java server code is in `application/src/main/`. OTP also includes a Javascript client
based on the MapLibre mapping library in `client/src/`. This client is now used for testing, with
most major deployments building custom clients from reusable components. The Maven build produces a
unified ("shaded") JAR file at `otp-shaded/target/otp-shaded-VERSION.jar` containing all necessary
code and dependencies to run OpenTripPlanner.

Additional information and instructions are available in
the [main documentation](http://docs.opentripplanner.org/en/dev-2.x/), including a
Expand All @@ -59,7 +60,11 @@ the world.

## Getting in touch

The fastest way to get help is to use our [Gitter chat room](https://gitter.im/opentripplanner/OpenTripPlanner) where most of the core developers are. Bug reports may be filed via the Github [issue tracker](https://github.com/openplans/OpenTripPlanner/issues). The OpenTripPlanner [mailing list](http://groups.google.com/group/opentripplanner-users) is used almost exclusively for project announcements. The mailing list and issue tracker are not intended for support questions or discussions. Please use the chat for this purpose. Other details of [project governance](http://docs.opentripplanner.org/en/dev-2.x/Governance/) can be found in the main documentation.
The fastest way to get help is to use our [Gitter chat room](https://gitter.im/opentripplanner/OpenTripPlanner) where most of the core developers
are. Bug reports may be filed via the Github [issue tracker](https://github.com/openplans/OpenTripPlanner/issues). The OpenTripPlanner [mailing list](http://groups.google.com/group/opentripplanner-users)
is used almost exclusively for project announcements. The mailing list and issue tracker are not
intended for support questions or discussions. Please use the chat for this purpose. Other details
of [project governance](http://docs.opentripplanner.org/en/dev-2.x/Governance/) can be found in the main documentation.

## OTP Ecosystem

Expand Down
8 changes: 4 additions & 4 deletions application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@
<dependency>
<groupId>org.onebusaway</groupId>
<artifactId>onebusaway-gtfs</artifactId>
<version>4.3.0</version>
<version>5.0.0</version>
</dependency>
<!-- Processing is used for the debug GUI (though we could probably use just Java2D) -->
<dependency>
Expand All @@ -312,9 +312,9 @@
</dependency>
<!-- OpenStreetMap protobuf (PBF) definitions and parser -->
<dependency>
<groupId>org.openstreetmap.osmosis</groupId>
<artifactId>osmosis-osm-binary</artifactId>
<version>0.48.3</version>
<groupId>org.openstreetmap.pbf</groupId>
<artifactId>osmpbf</artifactId>
<version>1.6.0</version>
</dependency>
<!-- Command line parameter parsing -->
<dependency>
Expand Down
26 changes: 18 additions & 8 deletions application/src/client/graphiql/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@
copy them directly into your environment, or perhaps include them in your
favored resource bundler.
-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphiql@3.0.4/graphiql.min.css" integrity="sha256-wTzfn13a+pLMB5rMeysPPR1hO7x0SwSeQI+cnw7VdbE=" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphiql@3.8.3/graphiql.min.css" integrity="sha256-sYaCR/jgUCzYaeWB9fPLVbM0hi5/UbHWy6zhEFm5rcI=" crossorigin="anonymous">
<title>OTP GraphQL Explorer</title>
</head>

<body>
<div id="graphiql">Loading...</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/graphiql.min.js" integrity="sha256-t0BNtgZ2L82dpHhlgKJl4yJ1tbQxcp1N5NkEjR82A7E=" crossorigin="anonymous"></script>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/graphiql.min.js" integrity="sha256-IvqrlAZ7aV5feVlhn75obrzIlVACoMl9mGvLukrUvCw=" crossorigin="anonymous"></script>

<script>
const gtfsExampleQuery = `
Expand Down Expand Up @@ -131,6 +132,11 @@
updateURL();
}

function onEditHeaders(headers) {
parameters.headers = headers;
updateURL();
}

function updateURL() {
if(parameters["query"] !== gtfsExampleQuery && parameters["query"] !== transmodelExampleQuery) {

Expand Down Expand Up @@ -168,16 +174,18 @@
window.location.reload();
};

function graphQLFetcher(graphQLParams) {
function graphQLFetcher(query, { headers }) {
const defaultHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
}
const mergedHeaders = Object.assign({}, defaultHeaders, headers);
return fetch(
urls[apiFlavor],
{
method: 'post',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(graphQLParams),
headers: mergedHeaders,
body: JSON.stringify(query),
credentials: 'omit',
},
).then(function (response) {
Expand All @@ -198,10 +206,12 @@
defaultVariableEditorOpen: true,
query: parameters.query || defaultQueries[apiFlavor],
variables: parameters.variables,
headers: parameters.headers,
operationName: parameters.operationName,
onEditQuery: onEditQuery,
onEditVariables: onEditVariables,
onEditOperationName: onEditOperationName,
onEditHeaders: onEditHeaders,
defaultEditorToolsVisibility: true
},
React.createElement(GraphiQL.Logo, {}, [header, select]));
Expand Down
4 changes: 2 additions & 2 deletions application/src/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<link rel="icon" type="image/svg+xml" href="/img/otp-logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OTP Debug</title>
<script type="module" crossorigin src="https://cdn.jsdelivr.net/gh/opentripplanner/debug-client-assets@main/2024/12/2024-12-09T10:11/assets/index-Cy40AOLN.js"></script>
<link rel="stylesheet" crossorigin href="https://cdn.jsdelivr.net/gh/opentripplanner/debug-client-assets@main/2024/12/2024-12-09T10:11/assets/index-DygGy0HD.css">
<script type="module" crossorigin src="https://cdn.jsdelivr.net/gh/opentripplanner/debug-client-assets@main/2025/01/2025-01-11T19:23/assets/index-D--h-dOg.js"></script>
<link rel="stylesheet" crossorigin href="https://cdn.jsdelivr.net/gh/opentripplanner/debug-client-assets@main/2025/01/2025-01-11T19:23/assets/index-BDL0-veX.css">
</head>
<body>
<div id="root"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ public class OrcaFareServiceTest {

private static final Money ONE_DOLLAR = usDollars(1f);
private static final Money TWO_DOLLARS = usDollars(2);
private static final Money FERRY_FARE = usDollars(6.50f);
private static final Money HALF_FERRY_FARE = usDollars(3.25f);
private static final Money HALF_FERRY_FARE = usDollars(1.75f);
private static final Money ORCA_SPECIAL_FARE = usDollars(1.00f);
public static final Money VASHON_WATER_TAXI_CASH_FARE = usDollars(6.75f);
public static final Money WEST_SEATTLE_WATER_TAXI_CASH_FARE = usDollars(5.75f);
Expand Down Expand Up @@ -219,24 +218,24 @@ void calculateFareThatIncludesNoFreeTransfers() {
getLeg(KITSAP_TRANSIT_AGENCY_ID, 121),
getLeg(WASHINGTON_STATE_FERRIES_AGENCY_ID, 150, "Fauntleroy-VashonIsland")
);
calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3).plus(FERRY_FARE));
calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(5));
calculateFare(
rides,
FareType.senior,
ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE).plus(usDollars(0.5f))
ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE.times(2)).plus(usDollars(0.5f))
);
calculateFare(rides, FareType.youth, Money.ZERO_USD);
// We don't get any fares for the skagit transit leg below here because they don't accept ORCA (electronic)
calculateFare(rides, FareType.electronicSpecial, ONE_DOLLAR.plus(ONE_DOLLAR).plus(FERRY_FARE));
calculateFare(rides, FareType.electronicSpecial, ONE_DOLLAR.plus(ONE_DOLLAR).plus(DEFAULT_TEST_RIDE_PRICE.times(2)));
calculateFare(
rides,
FareType.electronicRegular,
DEFAULT_TEST_RIDE_PRICE.times(2).plus(FERRY_FARE)
DEFAULT_TEST_RIDE_PRICE.times(4)
);
calculateFare(
rides,
FareType.electronicSenior,
ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE)
ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE.times(2))
);
calculateFare(rides, FareType.electronicYouth, ZERO_USD);
}
Expand Down Expand Up @@ -326,11 +325,11 @@ void calculateFareForWSFPtToTahlequah() {
List<Leg> rides = List.of(
getLeg(WASHINGTON_STATE_FERRIES_AGENCY_ID, 0, "Point Defiance - Tahlequah")
);
calculateFare(rides, regular, FERRY_FARE);
calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE);
calculateFare(rides, FareType.senior, HALF_FERRY_FARE);
calculateFare(rides, FareType.youth, Money.ZERO_USD);
calculateFare(rides, FareType.electronicSpecial, FERRY_FARE);
calculateFare(rides, FareType.electronicRegular, FERRY_FARE);
calculateFare(rides, FareType.electronicSpecial, DEFAULT_TEST_RIDE_PRICE);
calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE);
calculateFare(rides, FareType.electronicSenior, HALF_FERRY_FARE);
calculateFare(rides, FareType.electronicYouth, Money.ZERO_USD);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,11 @@
import java.util.Map;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
import org.opentripplanner.ext.restapi.model.ApiAbsoluteDirection;
import org.opentripplanner.ext.restapi.model.ApiRelativeDirection;
import org.opentripplanner.ext.restapi.model.ApiVertexType;
import org.opentripplanner.model.plan.AbsoluteDirection;
import org.opentripplanner.model.plan.RelativeDirection;
import org.opentripplanner.model.plan.VertexType;

public class EnumMapperTest {

private static final String MSG =
"Assert that the API enums have the exact same values that " +
"the domain enums of the same type, and that the specialized mapper is mapping all " +
"values. If this assumtion does not hold, create a new test.";

@Test
public void map() {
try {
verifyExactMatch(
AbsoluteDirection.class,
ApiAbsoluteDirection.class,
AbsoluteDirectionMapper::mapAbsoluteDirection
);
verifyExactMatch(
RelativeDirection.class,
ApiRelativeDirection.class,
RelativeDirectionMapper::mapRelativeDirection
);
} catch (RuntimeException ex) {
System.out.println(MSG);
throw ex;
}
}

@Test
public void testVertexTypeMapping() {
verifyExplicitMatch(
Expand Down Expand Up @@ -75,17 +47,4 @@ private <D extends Enum<?>, A extends Enum<?>> void verifyExplicitMatch(
assertTrue(rest.isEmpty());
}

private <D extends Enum<?>, A extends Enum<?>> void verifyExactMatch(
Class<D> domainClass,
Class<A> apiClass,
Function<D, A> mapper
) {
List<A> rest = new ArrayList<>(List.of(apiClass.getEnumConstants()));
for (D it : domainClass.getEnumConstants()) {
A result = mapper.apply(it);
assertEquals(result.name(), it.name());
rest.remove(result);
}
assertTrue(rest.isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import java.time.Duration;
import java.util.Locale;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.opentripplanner.service.vehicleparking.model.VehicleParkingState;
import org.opentripplanner.test.support.ResourceLoader;
Expand All @@ -17,6 +18,7 @@
public class BikelyUpdaterTest {

@Test
@Disabled
void parseBikeBoxes() {
var uri = ResourceLoader.of(this).uri("bikely.json");
var parameters = new BikelyUpdaterParameters(
Expand All @@ -41,8 +43,9 @@ void parseBikeBoxes() {

assertEquals(
"First 12 hour(s) is NOK0.00, afterwards NOK10.00 per 1 hour(s)",
first.getNote().toString(Locale.ENGLISH)
first.getNote().toString(Locale.ROOT)
);
// This test fails in the entur ci pipline
assertEquals(
"Første 12 time(r) er kr 0,00. Deretter kr 10,00 per 1 time(r)",
first.getNote().toString(Locales.NORWEGIAN_BOKMAL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.locationtech.jts.geom.LineString;
import org.opentripplanner.model.fare.FareProductUse;
import org.opentripplanner.model.plan.Leg;
import org.opentripplanner.model.plan.LegTime;
import org.opentripplanner.model.plan.LegCallTime;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.model.plan.StopArrival;
import org.opentripplanner.model.plan.TransitLeg;
Expand Down Expand Up @@ -55,12 +55,12 @@ public Trip getTrip() {
}

@Override
public LegTime start() {
public LegCallTime start() {
return first.start();
}

@Override
public LegTime end() {
public LegCallTime end() {
return second.end();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.opentripplanner.transit.model.basic.Money;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.network.Route;
import org.opentripplanner.transit.model.organization.Agency;

public class OrcaFareService extends DefaultFareService {

Expand All @@ -39,7 +38,7 @@ public class OrcaFareService extends DefaultFareService {
public static final String PIERCE_COUNTY_TRANSIT_AGENCY_ID = "3";
public static final String SKAGIT_TRANSIT_AGENCY_ID = "e0e4541a-2714-487b-b30c-f5c6cb4a310f";
public static final String SEATTLE_STREET_CAR_AGENCY_ID = "23";
public static final String WASHINGTON_STATE_FERRIES_AGENCY_ID = "WSF";
public static final String WASHINGTON_STATE_FERRIES_AGENCY_ID = "95";
public static final String KITSAP_TRANSIT_AGENCY_ID = "kt";
public static final String WHATCOM_AGENCY_ID = "14";
public static final int ROUTE_TYPE_FERRY = 4;
Expand Down Expand Up @@ -398,28 +397,11 @@ private Money getWashingtonStateFerriesFare(
return defaultFare;
}

var longName = routeLongName.toString().replaceAll(" ", "");

Map<FareType, Money> fares = OrcaFaresData.washingtonStateFerriesFares.get(longName);
// WSF doesn't support transfers so we only care about cash fares.
FareType wsfFareType;
if (fareType == FareType.electronicRegular) {
wsfFareType = FareType.regular;
} else if (fareType == FareType.electronicSenior) {
wsfFareType = FareType.senior;
} else if (fareType == FareType.electronicYouth) {
wsfFareType = FareType.youth;
} else if (fareType == FareType.electronicSpecial) {
wsfFareType = FareType.regular;
} else {
wsfFareType = fareType;
}
// WSF is free in one direction on each route
// If a fare is not found in the map, we can assume it's free.
// Route long name is reversed for the reverse direction on a single WSF route
return (fares != null && fares.get(wsfFareType) != null)
? fares.get(wsfFareType)
: Money.ZERO_USD;
return switch (fareType) {
case youth, electronicYouth -> Money.ZERO_USD;
case regular, electronicRegular, electronicSpecial -> defaultFare;
case senior, electronicSenior -> defaultFare.half().roundDownToNearestFiveMinorUnits();
};
}

/**
Expand Down
Loading

0 comments on commit 9513ded

Please sign in to comment.