Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(WIP) Add AbstractOpenTripPlannerProvider #211

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions enabler/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies {
compile 'org.json:json:20090211' // provided by Android
compile 'net.sf.kxml:kxml2:2.3.0' // provided by Android
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.+'
testRuntime 'org.slf4j:slf4j-jdk14:1.7.25'
}

Expand Down
803 changes: 803 additions & 0 deletions enabler/src/de/schildbach/pte/AbstractOpenTripPlannerProvider.java

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions enabler/src/de/schildbach/pte/MitfahrenBWProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package de.schildbach.pte;

import com.google.common.collect.Multimap;

import java.util.Locale;

import de.schildbach.pte.dto.Product;
import okhttp3.HttpUrl;

/**
* @author Holger Bruch
* @author Kavitha Ravi
*/
public class MitfahrenBWProvider extends AbstractOpenTripPlannerProvider {

public MitfahrenBWProvider() {
super(NetworkId.MFBW, HttpUrl.parse("http://api.mfdz.de/").newBuilder().addPathSegment("otp")
.build());
setLocale(Locale.GERMAN);
setNumTripsRequested(3);
}

protected Multimap<Product, String> defaultProductToOTPModeMapping() {
Multimap<Product, String> productsToModeMap = super.defaultProductToOTPModeMapping();
// TODO ON_DEMAND is no official OTP Mode yet. Mitfahren-BW supports RIDESHARING
// (in the sense of CARPOOLING, not Ride-Hailing). Probably it's better to subsume this
// under mode ON_DEMAND since characteristics as seen from rider are mostly equivalent
productsToModeMap.put(Product.ON_DEMAND, "RIDESHARING");
return productsToModeMap;
}
}
2 changes: 1 addition & 1 deletion enabler/src/de/schildbach/pte/NetworkId.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public enum NetworkId {
RT,

// Germany
DB, BVG, VBB, NVV, BAYERN, MVV, INVG, AVV, VGN, VVM, VMV, SH, GVH, BSVAG, VBN, NASA, VMT, VVO, VMS, VGS, VRR, VRS, MVG, VRN, VVS, DING, KVV, VAGFR, NVBW, VVV,
DB, BVG, VBB, NVV, BAYERN, MVV, INVG, AVV, VGN, VVM, VMV, SH, GVH, BSVAG, VBN, NASA, VMT, VVO, VMS, VGS, VRR, VRS, MVG, VRN, VVS, DING, KVV, VAGFR, NVBW, VVV, MFBW,

// Austria
OEBB, VAO, VOR, WIEN, OOEVV, LINZ, SVV, VVT, STV, VMOBIL,
Expand Down
8 changes: 8 additions & 0 deletions enabler/src/de/schildbach/pte/dto/Style.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ public enum Shape {
RECT, ROUNDED, CIRCLE
}

public Style(final int backgroundColor) {
this.shape = Shape.ROUNDED;
this.backgroundColor = backgroundColor;
this.backgroundColor2 = 0;
this.foregroundColor = deriveForegroundColor(backgroundColor);
this.borderColor = 0;
}

public Style(final int backgroundColor, final int foregroundColor) {
this.shape = Shape.ROUNDED;
this.backgroundColor = backgroundColor;
Expand Down
4 changes: 2 additions & 2 deletions enabler/src/de/schildbach/pte/util/HttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public void log(final String message) {
OKHTTP_CLIENT = builder.build();
}

private static final String SCRAPE_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
private static final String DEFAULT_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you rename this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment below, it‘s now a default that can be overridden

private static final int SCRAPE_PEEK_SIZE = 8192;

private static final Logger log = LoggerFactory.getLogger(HttpClient.class);
Expand Down Expand Up @@ -173,10 +173,10 @@ public void getInputStream(final Callback callback, final HttpUrl url, final Str
while (true) {
final Request.Builder request = new Request.Builder();
request.url(url);
request.header("Accept", DEFAULT_ACCEPT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why moving this here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OTP‘s responds with xml or json, depending on The accept header. To have it return json, I need to set it to json, which was always overridden by the SCRAPE_ACCEPT header. Hope just using this as default but not mandatory will not break anything for other providers. Or was there an explicit reason why it was necessary to override it?

request.headers(Headers.of(headers));
if (postRequest != null)
request.post(RequestBody.create(MediaType.parse(requestContentType), postRequest));
request.header("Accept", SCRAPE_ACCEPT);
if (userAgent != null)
request.header("User-Agent", userAgent);
if (referer != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package de.schildbach.pte;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;

import org.hamcrest.CoreMatchers;
import org.json.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Collections;

import de.schildbach.pte.dto.Location;
import de.schildbach.pte.dto.LocationType;
import de.schildbach.pte.dto.Product;
import de.schildbach.pte.dto.SuggestLocationsResult;
import de.schildbach.pte.dto.Trip;
import de.schildbach.pte.dto.Trip.Leg;
import de.schildbach.pte.dto.Trip.Public;
import okhttp3.HttpUrl;

@RunWith(MockitoJUnitRunner.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure that you really need Mockito. Any reason you can not use assertEquals() or assertNotNull()?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I introduced mockito to stub out the AOTPP.request() method to do some unit testing. Current provider tests seemed to be all live provider tests, which mostly print the results and do only a few plausibility checks. I‘m still not happy having large json snippets in the test class. Still thinking about this... I‘ll rewrite the asserts to match the current pte style, but still think mockito would be useful

public class AbstractOpenTripPlannerProviderTest {

@Spy
private AbstractOpenTripPlannerProvider otpProvider = new AbstractOpenTripPlannerProvider(NetworkId.MFBW, HttpUrl.parse("http://none/"));

@Test
public void parseLocation_coord() throws Exception {
String coordJson = "{\"lat\":49,\"lon\":9})";
Location location = otpProvider.parseLocationFromTo(new JSONObject(coordJson));

assertThat(location, CoreMatchers.notNullValue());
assertThat(location.type, CoreMatchers.equalTo(LocationType.COORD));
assertThat(location.lat, CoreMatchers.equalTo((int)(49*1E6)));
assertThat(location.lon, CoreMatchers.equalTo((int)(9*1E6)));
}

@Test
public void parseLegs_withoutIntermediateStops() throws Exception {
Trip.Public legWithoutIntermediateStops = (Public) otpProvider.parseLeg(new JSONObject("{" +
" \"startTime\": 1532173920000," +
" \"endTime\": 1532174340000," +
" \"departureDelay\": 0," +
" \"arrivalDelay\": 0," +
" \"realTime\": false," +
" \"distance\": 4850.009558278676," +
" \"pathway\": false," +
" \"mode\": \"RAIL\"," +
" \"route\": \"Karlsruhe - Bretten - Gülshausen - Bauerbach - Flehingen - Eppingen - Schwaigern - Heilbronn - Öhringen\"," +
" \"agencyName\": \"kvv\"," +
" \"agencyUrl\": \"http://unkwnown/\"," +
" \"agencyTimeZoneOffset\": 7200000," +
" \"routeColor\": \"83b23b\"," +
" \"routeType\": 109," +
" \"routeId\": \"nvbv:kvv:22014:E:R:j18\"," +
" \"routeTextColor\": \"FFFFFF\"," +
" \"interlineWithPreviousLeg\": false," +
" \"headsign\": \"Öhringen\"," +
" \"agencyId\": \"13\"," +
" \"tripId\": \"nvbv:kvv:22014:E:R:j18-6-20615-13:36\"," +
" \"serviceDate\": \"20180721\"," +
" \"from\": {" +
" \"name\": \"Weinsberg Bahnhof\"," +
" \"stopId\": \"nvbv:de:08125:4344:1:1\"," +
" \"platformCode\": \"1\"," +
" \"lon\": 9.286208029239999," +
" \"lat\": 49.14834012859," +
" \"arrival\": 1532173919000," +
" \"departure\": 1532173920000," +
" \"stopIndex\": 9," +
" \"stopSequence\": 10," +
" \"vertexType\": \"TRANSIT\"" +
" }," +
" \"to\": {" +
" \"name\": \"Sülzbach Schule (S-Bahn)\"," +
" \"stopId\": \"nvbv:de:08125:2005:1:1\"," +
" \"platformCode\": \"1\"," +
" \"lon\": 9.35141767054," +
" \"lat\": 49.145066559929994," +
" \"arrival\": 1532174340000," +
" \"departure\": 1532174341000," +
" \"stopIndex\": 13," +
" \"stopSequence\": 14," +
" \"vertexType\": \"TRANSIT\"" +
" }," +
" \"legGeometry\": {" +
" \"points\": \"ch~jHwutw@kC{dCwDau@zFkqCvUghA\"," +
" \"length\": 5" +
" }," +
" \"routeLongName\": \"Karlsruhe - Bretten - Gülshausen - Bauerbach - Flehingen - Eppingen - Schwaigern - Heilbronn - Öhringen\"," +
" \"rentedBike\": false," +
" \"transitLeg\": true," +
" \"duration\": 420," +
" \"intermediateStops\": []," +
" \"steps\": []" +
" }"));

assertThat(legWithoutIntermediateStops, CoreMatchers.notNullValue());
assertThat(legWithoutIntermediateStops.intermediateStops, notNullValue());
assertThat(legWithoutIntermediateStops.intermediateStops.isEmpty(), equalTo(true));
}

@Test
public void parseLeg_withIntermediateStops() throws Exception {
Leg legWithIntermediateStops = otpProvider.parseLeg(new JSONObject("{" +
" \"startTime\": 1532173920000," +
" \"endTime\": 1532174340000," +
" \"departureDelay\": 0," +
" \"arrivalDelay\": 0," +
" \"realTime\": false," +
" \"distance\": 4850.009558278676," +
" \"pathway\": false," +
" \"mode\": \"RAIL\"," +
" \"route\": \"Karlsruhe - Bretten - Gülshausen - Bauerbach - Flehingen - Eppingen - Schwaigern - Heilbronn - Öhringen\"," +
" \"agencyName\": \"kvv\"," +
" \"agencyUrl\": \"http://unkwnown/\"," +
" \"agencyTimeZoneOffset\": 7200000," +
" \"routeColor\": \"83b23b\"," +
" \"routeType\": 109," +
" \"routeId\": \"nvbv:kvv:22014:E:R:j18\"," +
" \"routeTextColor\": \"FFFFFF\"," +
" \"interlineWithPreviousLeg\": false," +
" \"headsign\": \"Öhringen\"," +
" \"agencyId\": \"13\"," +
" \"tripId\": \"nvbv:kvv:22014:E:R:j18-6-20615-13:36\"," +
" \"serviceDate\": \"20180721\"," +
" \"from\": {" +
" \"name\": \"Weinsberg Bahnhof\"," +
" \"stopId\": \"nvbv:de:08125:4344:1:1\"," +
" \"platformCode\": \"1\"," +
" \"lon\": 9.286208029239999," +
" \"lat\": 49.14834012859," +
" \"arrival\": 1532173919000," +
" \"departure\": 1532173920000," +
" \"stopIndex\": 9," +
" \"stopSequence\": 10," +
" \"vertexType\": \"TRANSIT\"" +
" }," +
" \"to\": {" +
" \"name\": \"Sülzbach Schule (S-Bahn)\"," +
" \"stopId\": \"nvbv:de:08125:2005:1:1\"," +
" \"platformCode\": \"1\"," +
" \"lon\": 9.35141767054," +
" \"lat\": 49.145066559929994," +
" \"arrival\": 1532174340000," +
" \"departure\": 1532174341000," +
" \"stopIndex\": 13," +
" \"stopSequence\": 14," +
" \"vertexType\": \"TRANSIT\"" +
" }," +
" \"legGeometry\": {" +
" \"points\": \"ch~jHwutw@kC{dCwDau@zFkqCvUghA\"," +
" \"length\": 5" +
" }," +
" \"routeLongName\": \"Karlsruhe - Bretten - Gülshausen - Bauerbach - Flehingen - Eppingen - Schwaigern - Heilbronn - Öhringen\"," +
" \"rentedBike\": false," +
" \"transitLeg\": true," +
" \"duration\": 420," +
" \"intermediateStops\": [" +
" {" +
" \"name\": \"Weinsberg/Ellhofen Gewerbegebi\"," +
" \"stopId\": \"nvbv:de:08125:1598:1:1\"," +
" \"platformCode\": \"1\"," +
" \"lon\": 9.30762309997," +
" \"lat\": 49.14904026286," +
" \"arrival\": 1532174040000," +
" \"departure\": 1532174040000," +
" \"stopIndex\": 10," +
" \"stopSequence\": 11," +
" \"vertexType\": \"TRANSIT\"" +
" }," +
" {" +
" \"name\": \"Ellhofen Bahnhof\"," +
" \"stopId\": \"nvbv:de:08125:2003:3:1\"," +
" \"platformCode\": \"1\"," +
" \"lon\": 9.31627837142," +
" \"lat\": 49.149960974660004," +
" \"arrival\": 1532174100000," +
" \"departure\": 1532174100000," +
" \"stopIndex\": 11," +
" \"stopSequence\": 12," +
" \"vertexType\": \"TRANSIT\"" +
" }," +
" {" +
" \"name\": \"Sülzbach Bahnhof\"," +
" \"stopId\": \"nvbv:de:08125:2004:1:1\"," +
" \"platformCode\": \"1\"," +
" \"lon\": 9.33969625383," +
" \"lat\": 49.14870741667," +
" \"arrival\": 1532174220000," +
" \"departure\": 1532174220000," +
" \"stopIndex\": 12," +
" \"stopSequence\": 13," +
" \"vertexType\": \"TRANSIT\"" +
" }" +
" ]," +
" \"steps\": []" +
" }"));

assertThat(legWithIntermediateStops, notNullValue());
}

@Test
public void suggestLocations_noResults() throws Exception {
String suggestLocationsResponse = "[]";
Mockito.doReturn(suggestLocationsResponse ).when(otpProvider).request(Mockito.any(HttpUrl.class));
SuggestLocationsResult suggestLocations = otpProvider.suggestLocations("Weinsberg");
assertThat(suggestLocations.suggestedLocations.isEmpty(), equalTo(true));
}

@Test
public void convertProductsToOTPModes(){
String expectedModes = "WALK,RAIL,BUS";
assertThat(otpProvider.convertProductsToOTPModes(Product.fromCodes(new char[]{'R','B'})), equalTo(expectedModes));
}
}
Loading