7 Commits

Author SHA1 Message Date
9b62867b3f introduce asynchronous data retrieval
All checks were successful
continuous-integration/drone/push Build is passing
The client now offers getTripsAsync(), getStopsAsync() and
getMessagesAsync() that return a Future of the requested objects. The
synchronous methods are still present, but only wrap the new ones
internally.
2022-08-30 13:36:39 +02:00
c494c0c81b deps: bump jackson-databind from 2.13.2.1 to 2.13.3
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-30 13:21:50 +02:00
bb0d11d10c test: use JRE8+ version of WireMock for offline testing
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-04-13 17:48:09 +02:00
bcc47d5f05 deps: bump jackson-databind from 2.13.0 to 2.13.2.1
Plus some minor dev-dependency updates.
2022-04-13 17:48:08 +02:00
276c12abc4 readme++
All checks were successful
continuous-integration/drone/push Build is passing
2021-10-02 15:29:03 +02:00
6fd21e2a03 update dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2021-10-02 15:20:23 +02:00
afef896f12 migrate to GH actions for CI 2021-10-02 15:14:20 +02:00
12 changed files with 419 additions and 151 deletions

View File

@ -6,15 +6,15 @@ steps:
- name: test - name: test
image: maven:3-openjdk-11 image: maven:3-openjdk-11
commands: commands:
- mvn clean test - mvn -B clean test
--- ---
kind: pipeline kind: pipeline
type: docker type: docker
name: java15 name: java17
steps: steps:
- name: test - name: test
image: maven:3-openjdk-15 image: maven:3-openjdk-17
commands: commands:
- mvn clean test - mvn -B clean test

33
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: CI
on: [ push, pull_request ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ 11, 17 ]
include:
- jdk: 11
analysis: true
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
- name: Test
run: mvn -B -P coverage clean verify
- name: Analysis
if: matrix.analysis && github.event_name == 'push'
run: >
mvn -B sonar:sonar
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.organization=stklcode-github
-Dsonar.login=$SONAR_TOKEN
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View File

@ -1,16 +0,0 @@
language: java
jdk:
- openjdk11
- openjdk15
install: true
addons:
sonarcloud:
organization: "stklcode-github"
token:
secure: "FkEe/+MKpF4pSX3ZYOgu7oeIKf0460Q3XVLUhIX9bk2dyY8hoab74oCo4FtD7jim0+ZC13JVHGDX7iOQMUtS5EZ+x+pA0qpppzCK5zV8afN/l46HJ07kJldvr+EH0klbDVMFZQ5dT7r/w6CoDzjtENHzKQAJLcheUVDNpkcuBdaplTqIAVf3lQpKtOuVjQJ5qZDwwS5wsHNqPcYbcEGrPmcKDVnp3mD3bfI6dT1bbRt845QcD73rPYkQKxen8eIwJxFf5MZStgvbj7yphPxPGwoLAsoLP6LpThTDYcrg+vgUnSs+l9GckL3IbhPAmecixLbKVnphBZzRTvpdMTt5KeOoAJ2nM6RLs5cRCqiEgLEioWkVaSH5WxoBj38Z1h4fTsDV3dTcCuQWX8GFxdeeTelu+XbatdRWMnUgiF7oax+uNvR62fasTbAc7dWPJbARiD7ZbkWH4nHEY07xKKx87xzUz36ZeEHGoBXgqnLmv/FCwqMrEpOoIT41fc0WYtdIA4wjRoAyG0u+wNBMbVlf4PK72seM4b/bmU+TtmaaVla/SvNOiz+A3DHxtJEUScPcL3QGjviddglMf+wyD6VXVViq9VuYRKZFyjpuoNpb5lwEbwmRnmLabBx8jBgyPinjpmqHYlIntcPAwuyLRaqTHFcmCrbeeZEf7KaPRYKx+Cs="
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.sonar/cache'
script:
- if [ "$TRAVIS_JDK_VERSION" == "openjdk11" ]; then mvn -P coverage clean package sonar:sonar; else mvn clean test; fi

View File

@ -1,6 +1,29 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## unreleased
### Features
* New methods for asynchronous trip, stop and message retrieval (#15)
## 2.0.3 - 2022-08-30
### Security
* Updated dependencies
## 2.0.2 - 2022-04-13
### Security
* Updated dependencies
## 2.0.1 - 2021-10-02
### Security
* Updated dependencies
### Improvement
* Built and tested with JDK 17
## 2.0.0 - 2021-01-30 ## 2.0.0 - 2021-01-30
### Breaking ### Breaking
* Java 11 or later required * Java 11 or later required
@ -19,6 +42,12 @@ All notable changes to this project will be documented in this file.
---- ----
## 1.3.2 - 2022-08-30
### Improvements
* Dependency updates
## 1.3.1 - 2020-12-12 ## 1.3.1 - 2020-12-12
### Fixed ### Fixed
* Allow reopening an `AsyncUraTripReader` without raising an exception (#13) * Allow reopening an `AsyncUraTripReader` without raising an exception (#13)

View File

@ -107,7 +107,7 @@ Files ending with `Test.java` will be automatically included into the test suite
## Continuous Integration ## Continuous Integration
Automated tests are run using [Travis CI](https://travis-ci.com/stklcode/juraclient) for every commit including pull requests. Automated tests are run using [GitHub Actions](https://github.com/stklcode/juraclient/actions/) for every commit including pull requests.
There is also a code quality analysis pushing results to [SonarCloud](https://sonarcloud.io/dashboard?id=de.stklcode.pubtrans%3Ajuraclient). There is also a code quality analysis pushing results to [SonarCloud](https://sonarcloud.io/dashboard?id=de.stklcode.pubtrans%3Ajuraclient).
Keep in mind that the ruleset is not yet perfect, so not every minor issue has to be fixed immediately. Keep in mind that the ruleset is not yet perfect, so not every minor issue has to be fixed immediately.

View File

@ -1,5 +1,5 @@
# jURAclient # jURAclient
[![Build Status](https://travis-ci.com/stklcode/juraclient.svg?branch=master)](https://travis-ci.com/stklcode/juraclient) [![Build Status](https://github.com/stklcode/juraclient/actions/workflows/ci.yml/badge.svg)](https://github.com/stklcode/juraclient/actions/workflows/ci.yml)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=de.stklcode.pubtrans%3Ajuraclient&metric=alert_status)](https://sonarcloud.io/dashboard?id=de.stklcode.pubtrans%3Ajuraclient) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=de.stklcode.pubtrans%3Ajuraclient&metric=alert_status)](https://sonarcloud.io/dashboard?id=de.stklcode.pubtrans%3Ajuraclient)
[![Javadocs](https://www.javadoc.io/badge/de.stklcode.pubtrans/juraclient.svg)](https://www.javadoc.io/doc/de.stklcode.pubtrans/juraclient) [![Javadocs](https://www.javadoc.io/badge/de.stklcode.pubtrans/juraclient.svg)](https://www.javadoc.io/doc/de.stklcode.pubtrans/juraclient)
[![Maven Central](https://img.shields.io/maven-central/v/de.stklcode.pubtrans/juraclient.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.stklcode.pubtrans%22%20AND%20a%3A%22juraclient%22) [![Maven Central](https://img.shields.io/maven-central/v/de.stklcode.pubtrans/juraclient.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.stklcode.pubtrans%22%20AND%20a%3A%22juraclient%22)
@ -22,17 +22,17 @@ However, new features might not be backported.
### Initialization ### Initialization
```java ```java
// Instantiate the client (e.g. using the TFL API) // Instantiate the client.
UraClient ura = new UraClient("http://countdown.api.tfl.gov.uk"); UraClient ura = new UraClient("https://ura.example.com");
// Initialize the API with non-standard endpoints (e.g. ASEAG with API V2) // Initialize the API with non-standard endpoints.
UraClient ura = new UraClient("http://ivu.aseag.de", UraClient ura = new UraClient("https://ura.example.com",
"interfaces/ura/instant_V2", "interfaces/ura/instant_V2",
"interfaces/ura/stream_V2"); "interfaces/ura/stream_V2");
// Initialization with configuration builder (Client v2.x) // Initialization with configuration builder (Client v2.x)
UraClient ura = new UraClient( UraClient ura = new UraClient(
UraClientConfiguration.forBaseURL("http://ura.example.com") UraClientConfiguration.forBaseURL("https://ura.example.com")
.withInstantPath("interfaces/ura/instant_V2") .withInstantPath("interfaces/ura/instant_V2")
.withStreamPath("interfaces/ura/stream_V2") .withStreamPath("interfaces/ura/stream_V2")
.withConnectTimeout(Duration.ofSeconds(2)) .withConnectTimeout(Duration.ofSeconds(2))
@ -81,10 +81,10 @@ List<Message> msgs = ura.forStop("100000")
<dependency> <dependency>
<groupId>de.stklcode.pubtrans</groupId> <groupId>de.stklcode.pubtrans</groupId>
<artifactId>juraclient</artifactId> <artifactId>juraclient</artifactId>
<version>2.0.0</version> <version>2.0.2</version>
</dependency> </dependency>
``` ```
## License ## License
The project is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). The project is licensed under [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).

26
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>de.stklcode.pubtrans</groupId> <groupId>de.stklcode.pubtrans</groupId>
<artifactId>juraclient</artifactId> <artifactId>juraclient</artifactId>
<version>2.0.0</version> <version>2.1.0-SNAPSHOT</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -22,7 +22,7 @@
<licenses> <licenses>
<license> <license>
<name>Apache License 2.0</name> <name>Apache License 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.html</url> <url>https://www.apache.org/licenses/LICENSE-2.0.html</url>
<distribution>repo</distribution> <distribution>repo</distribution>
</license> </license>
</licenses> </licenses>
@ -50,13 +50,13 @@
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>2.12.1</version> <version>2.13.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<version>5.7.0</version> <version>5.9.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -67,8 +67,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.tomakehurst</groupId> <groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId> <artifactId>wiremock-jre8</artifactId>
<version>2.27.2</version> <version>2.33.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -78,7 +78,7 @@
<dependency> <dependency>
<groupId>org.sonarsource.scanner.maven</groupId> <groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId> <artifactId>sonar-maven-plugin</artifactId>
<version>3.8.0.2131</version> <version>3.9.1.2184</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
@ -88,15 +88,17 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.10.1</version>
<configuration> <configuration>
<release>11</release> <release>11</release>
<source>11</source>
<target>11</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version> <version>3.2.2</version>
<configuration> <configuration>
<archive> <archive>
<manifestEntries> <manifestEntries>
@ -121,7 +123,7 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version> <version>0.8.8</version>
<executions> <executions>
<execution> <execution>
<id>prepare-agent</id> <id>prepare-agent</id>
@ -176,7 +178,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version> <version>3.4.1</version>
<configuration> <configuration>
<overview>${basedir}/src/main/javadoc/overview.html</overview> <overview>${basedir}/src/main/javadoc/overview.html</overview>
<source>11</source> <source>11</source>
@ -201,7 +203,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId> <artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version> <version>3.0.1</version>
<executions> <executions>
<execution> <execution>
<id>sign-artifacts</id> <id>sign-artifacts</id>

View File

@ -17,6 +17,7 @@
package de.stklcode.pubtrans.ura; package de.stklcode.pubtrans.ura;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.pubtrans.ura.exception.AsyncUraClientException;
import de.stklcode.pubtrans.ura.exception.UraClientConfigurationException; import de.stklcode.pubtrans.ura.exception.UraClientConfigurationException;
import de.stklcode.pubtrans.ura.exception.UraClientException; import de.stklcode.pubtrans.ura.exception.UraClientException;
import de.stklcode.pubtrans.ura.model.Message; import de.stklcode.pubtrans.ura.model.Message;
@ -33,6 +34,8 @@ import java.net.http.HttpResponse;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Consumer; import java.util.function.Consumer;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
@ -244,7 +247,6 @@ public class UraClient implements Serializable {
* @param query The query. * @param query The query.
* @return List of trips. * @return List of trips.
* @throws UraClientException Error with API communication. * @throws UraClientException Error with API communication.
* @throws UraClientException Error with API communication.
* @since 1.0 * @since 1.0
* @since 2.0 Throws {@link UraClientException}. * @since 2.0 Throws {@link UraClientException}.
*/ */
@ -263,27 +265,84 @@ public class UraClient implements Serializable {
* @since 2.0 Throws {@link UraClientException}. * @since 2.0 Throws {@link UraClientException}.
*/ */
public List<Trip> getTrips(final Query query, final Integer limit) throws UraClientException { public List<Trip> getTrips(final Query query, final Integer limit) throws UraClientException {
List<Trip> trips = new ArrayList<>(); try {
try (InputStream is = requestInstant(REQUEST_TRIP, query); return getTripsAsync(query, limit).join();
BufferedReader br = new BufferedReader(new InputStreamReader(is))) { } catch (CompletionException e) {
String version = null; if (e.getCause() instanceof AsyncUraClientException) {
String line = br.readLine(); throw new UraClientException((AsyncUraClientException) e.getCause());
while (line != null && (limit == null || trips.size() < limit)) { } else {
List<Serializable> l = mapper.readValue(line, mapper.getTypeFactory().constructCollectionType(List.class, Serializable.class)); throw new UraClientException("Asynchronous trip request failed to complete", e.getCause());
/* Check if result exists and has correct response type */
if (l != null && !l.isEmpty()) {
if (l.get(0).equals(RES_TYPE_URA_VERSION)) {
version = l.get(1).toString();
} else if (l.get(0).equals(RES_TYPE_PREDICTION)) {
trips.add(new Trip(l, version));
}
}
line = br.readLine();
} }
} catch (IOException e) {
throw new UraClientException("Failed to read trips from API", e);
} }
return trips; }
/**
* Get list of trips asynchronously.
* If forStops() and/or forLines() has been called, those will be used as filter.
*
* @return List of trips.
* @since 2.1
*/
public CompletableFuture<List<Trip>> getTripsAsync() {
return getTripsAsync(new Query(), null);
}
/**
* Get list of trips with limit asynchronously.
* If forStops() and/or forLines() has been called, those will be used as filter.
*
* @param limit Maximum number of results.
* @return List of trips.
* @since 2.1
*/
public CompletableFuture<List<Trip>> getTripsAsync(final Integer limit) {
return getTripsAsync(new Query(), limit);
}
/**
* Get list of trips asynchronously.
* If forStops() and/or forLines() has been called, those will be used as filter.
*
* @param query The query.
* @return List of trips.
* @since 2.1
*/
public CompletableFuture<List<Trip>> getTripsAsync(final Query query) {
return getTripsAsync(query, null);
}
/**
* Get list of trips for given stopIDs and lineIDs with result limit asynchronously.
*
* @param query The query.
* @param limit Maximum number of results.
* @return List of trips.
* @since 2.1
*/
public CompletableFuture<List<Trip>> getTripsAsync(final Query query, final Integer limit) {
return requestInstantAsync(REQUEST_TRIP, query).thenApply(is -> {
List<Trip> trips = new ArrayList<>();
try (is; BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String version = null;
String line = br.readLine();
while (line != null && (limit == null || trips.size() < limit)) {
List<Serializable> l = mapper.readValue(line, mapper.getTypeFactory().constructCollectionType(List.class, Serializable.class));
/* Check if result exists and has correct response type */
if (l != null && !l.isEmpty()) {
if (l.get(0).equals(RES_TYPE_URA_VERSION)) {
version = l.get(1).toString();
} else if (l.get(0).equals(RES_TYPE_PREDICTION)) {
trips.add(new Trip(l, version));
}
}
line = br.readLine();
}
} catch (IOException e) {
throw new AsyncUraClientException("Failed to read trips from API", e);
}
return trips;
});
} }
/** /**
@ -351,21 +410,52 @@ public class UraClient implements Serializable {
* @since 2.0 Throws {@link UraClientException}. * @since 2.0 Throws {@link UraClientException}.
*/ */
public List<Stop> getStops(final Query query) throws UraClientException { public List<Stop> getStops(final Query query) throws UraClientException {
List<Stop> stops = new ArrayList<>(); try {
try (InputStream is = requestInstant(REQUEST_STOP, query); return getStopsAsync(query).join();
BufferedReader br = new BufferedReader(new InputStreamReader(is))) { } catch (CompletionException e) {
String line; if (e.getCause() instanceof AsyncUraClientException) {
while ((line = br.readLine()) != null) { throw new UraClientException((AsyncUraClientException) e.getCause());
List<Serializable> l = mapper.readValue(line, mapper.getTypeFactory().constructCollectionType(List.class, Serializable.class)); } else {
/* Check if result exists and has correct response type */ throw new UraClientException("Asynchronous stop request failed to complete", e.getCause());
if (l != null && !l.isEmpty() && l.get(0).equals(RES_TYPE_STOP)) {
stops.add(new Stop(l));
}
} }
} catch (IOException e) {
throw new UraClientException("Failed to read stops from API", e);
} }
return stops; }
/**
* Get list of stops without filters asynchronously.
*
* @return The list of stops.
* @since 2.1
*/
public CompletableFuture<List<Stop>> getStopsAsync() {
return getStopsAsync(new Query());
}
/**
* List available stopIDs asynchronously.
* If forStops() and/or forLines() has been called, those will be used as filter.
*
* @param query The query.
* @return The list.
* @since 2.0
*/
public CompletableFuture<List<Stop>> getStopsAsync(final Query query) {
return requestInstantAsync(REQUEST_TRIP, query).thenApply(is -> {
List<Stop> stops = new ArrayList<>();
try (is; BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = br.readLine()) != null) {
List<Serializable> l = mapper.readValue(line, mapper.getTypeFactory().constructCollectionType(List.class, Serializable.class));
/* Check if result exists and has correct response type */
if (l != null && !l.isEmpty() && l.get(0).equals(RES_TYPE_STOP)) {
stops.add(new Stop(l));
}
}
} catch (IOException e) {
throw new AsyncUraClientException("Failed to read stops from API", e);
}
return stops;
});
} }
/** /**
@ -406,39 +496,83 @@ public class UraClient implements Serializable {
* @since 2.0 Throw {@link UraClientException}. * @since 2.0 Throw {@link UraClientException}.
*/ */
public List<Message> getMessages(final Query query, final Integer limit) throws UraClientException { public List<Message> getMessages(final Query query, final Integer limit) throws UraClientException {
List<Message> messages = new ArrayList<>(); try {
try (InputStream is = requestInstant(REQUEST_MESSAGE, query); return getMessagesAsync(query, limit).join();
BufferedReader br = new BufferedReader(new InputStreamReader(is))) { } catch (CompletionException e) {
String version = null; if (e.getCause() instanceof AsyncUraClientException) {
String line = br.readLine(); throw new UraClientException((AsyncUraClientException) e.getCause());
while (line != null && (limit == null || messages.size() < limit)) { } else {
List<Serializable> l = mapper.readValue(line, mapper.getTypeFactory().constructCollectionType(List.class, Serializable.class)); throw new UraClientException("Asynchronous message request failed to complete", e.getCause());
/* Check if result exists and has correct response type */
if (l != null && !l.isEmpty()) {
if (l.get(0).equals(RES_TYPE_URA_VERSION)) {
version = l.get(1).toString();
} else if (l.get(0).equals(RES_TYPE_FLEX_MESSAGE)) {
messages.add(new Message(l, version));
}
}
line = br.readLine();
} }
} catch (IOException e) {
throw new UraClientException("Failed to read messages from API", e);
} }
return messages;
} }
/** /**
* Issue request to instant endpoint and return input stream. * Get list of messages.
*
* @return List of messages.
* @since 2.1
*/
public CompletableFuture<List<Message>> getMessagesAsync() {
return getMessagesAsync(new Query(), null);
}
/**
* Get list of messages asynchronously.
* If forStops() has been called, those will be used as filter.
*
* @param query The query.
* @return List of messages.
* @since 2.1
*/
public CompletableFuture<List<Message>> getMessagesAsync(final Query query) {
return getMessagesAsync(query, null);
}
/**
* Get list of messages for given stopIDs with result limit asynchronously.
*
* @param query The query.
* @param limit Maximum number of results.
* @return List of messages.
* @since 2.1
*/
public CompletableFuture<List<Message>> getMessagesAsync(final Query query, final Integer limit) {
return requestInstantAsync(REQUEST_MESSAGE, query).thenApply(is -> {
List<Message> messages = new ArrayList<>();
try (is; BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String version = null;
String line = br.readLine();
while (line != null && (limit == null || messages.size() < limit)) {
List<Serializable> l = mapper.readValue(line, mapper.getTypeFactory().constructCollectionType(List.class, Serializable.class));
/* Check if result exists and has correct response type */
if (l != null && !l.isEmpty()) {
if (l.get(0).equals(RES_TYPE_URA_VERSION)) {
version = l.get(1).toString();
} else if (l.get(0).equals(RES_TYPE_FLEX_MESSAGE)) {
messages.add(new Message(l, version));
}
}
line = br.readLine();
}
} catch (IOException e) {
throw new AsyncUraClientException("Failed to read messages from API", e);
}
return messages;
});
}
/**
* Issue asynchronous request to instant endpoint and return input stream.
* *
* @param returnList Fields to fetch. * @param returnList Fields to fetch.
* @param query The query. * @param query The query.
* @return Response {@link InputStream}. * @return Response {@link InputStream}.
* @throws IOException on errors * @since 2.1
*/ */
private InputStream requestInstant(final String[] returnList, final Query query) throws IOException { private CompletableFuture<InputStream> requestInstantAsync(final String[] returnList, final Query query) {
return request(requestURL(config.getBaseURL() + config.getInstantPath(), returnList, query)); return requestAsync(requestURL(config.getBaseURL() + config.getInstantPath(), returnList, query));
} }
/** /**
@ -498,6 +632,28 @@ public class UraClient implements Serializable {
} }
} }
/**
* Open given URL as InputStream.
*
* @param url The URL.
* @return Response {@link InputStream}.
* @since 2.1
*/
private CompletableFuture<InputStream> requestAsync(String url) {
var clientBuilder = HttpClient.newBuilder();
if (config.getConnectTimeout() != null) {
clientBuilder.connectTimeout(config.getConnectTimeout());
}
var reqBuilder = HttpRequest.newBuilder(URI.create(url)).GET();
if (config.getTimeout() != null) {
reqBuilder.timeout(config.getTimeout());
}
return clientBuilder.build().sendAsync(reqBuilder.build(), HttpResponse.BodyHandlers.ofInputStream())
.thenApply(HttpResponse::body);
}
/** /**
* Add a URL parameter with list of values, if filled. * Add a URL parameter with list of values, if filled.
* *
@ -630,6 +786,16 @@ public class UraClient implements Serializable {
return UraClient.this.getStops(this); return UraClient.this.getStops(this);
} }
/**
* Get stops for set filters asynchronously.
*
* @return List of matching trips.
* @since 2.1
*/
public CompletableFuture<List<Stop>> getStopsAsync() {
return UraClient.this.getStopsAsync(this);
}
/** /**
* Get trips for set filters. * Get trips for set filters.
* *
@ -642,6 +808,16 @@ public class UraClient implements Serializable {
return UraClient.this.getTrips(this); return UraClient.this.getTrips(this);
} }
/**
* Get trips for set filters asynchronously.
*
* @return List of matching trips.
* @since 2.1
*/
public CompletableFuture<List<Trip>> getTripsAsync() {
return UraClient.this.getTripsAsync(this);
}
/** /**
* Get trips for set filters. * Get trips for set filters.
* *
@ -678,5 +854,15 @@ public class UraClient implements Serializable {
public List<Message> getMessages() throws UraClientException { public List<Message> getMessages() throws UraClientException {
return UraClient.this.getMessages(this); return UraClient.this.getMessages(this);
} }
/**
* Get trips for set filters asynchronously.
*
* @return List of matching messages.
* @since 2.1
*/
public CompletableFuture<List<Message>> getMessagesAsync() {
return UraClient.this.getMessagesAsync(this);
}
} }
} }

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
import java.time.Duration; import java.time.Duration;
/** /**
* Configurstion Object for the {@link UraClient}. * Configuration Object for the {@link UraClient}.
* *
* @author Stefan Kalscheuer * @author Stefan Kalscheuer
* @since 2.0 * @since 2.0

View File

@ -0,0 +1,37 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
*
* 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 de.stklcode.pubtrans.ura.exception;
/**
* Custom exception class indicating an error with the URA API communication.
*
* @author Stefan Kalscheuer
* @since 2.1
*/
public class AsyncUraClientException extends RuntimeException {
private static final long serialVersionUID = -7530123149703928296L;
/**
* Default constructor.
*
* @param message The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
* @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
*/
public AsyncUraClientException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -36,4 +36,13 @@ public class UraClientException extends IOException {
public UraClientException(String message, Throwable cause) { public UraClientException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
/**
* Constructor from asynchronous exception.
*
* @param e Asynchronous exception to wrap.
*/
public UraClientException(AsyncUraClientException e) {
super(e.getMessage(), e.getCause());
}
} }

View File

@ -16,17 +16,14 @@
package de.stklcode.pubtrans.ura; package de.stklcode.pubtrans.ura;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.http.Fault; import com.github.tomakehurst.wiremock.http.Fault;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import de.stklcode.pubtrans.ura.exception.UraClientException; import de.stklcode.pubtrans.ura.exception.UraClientException;
import de.stklcode.pubtrans.ura.model.Message; import de.stklcode.pubtrans.ura.model.Message;
import de.stklcode.pubtrans.ura.model.Stop; import de.stklcode.pubtrans.ura.model.Stop;
import de.stklcode.pubtrans.ura.model.Trip; import de.stklcode.pubtrans.ura.model.Trip;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import java.io.IOException; import java.io.IOException;
import java.net.http.HttpConnectTimeoutException; import java.net.http.HttpConnectTimeoutException;
@ -36,6 +33,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
@ -46,27 +44,17 @@ import static org.junit.jupiter.api.Assertions.*;
/** /**
* Unit test for the URA Client. * Unit test for the URA Client.
* Tests run against mocked data collected from ASEAG API (http://ivu.aseag.de) and * Tests run against mocked data collected from ASEAG API (no longer available) and
* TFL API (http://http://countdown.api.tfl.gov.uk) * TFL API (http://countdown.api.tfl.gov.uk)
* *
* @author Stefan Kalscheuer * @author Stefan Kalscheuer
*/ */
public class UraClientTest { public class UraClientTest {
private static WireMockServer httpMock;
@BeforeAll @RegisterExtension
public static void setUp() { public static WireMockExtension wireMock = WireMockExtension.newInstance()
// Initialize HTTP mock. .options(wireMockConfig().dynamicPort())
httpMock = new WireMockServer(WireMockConfiguration.options().dynamicPort()); .build();
httpMock.start();
WireMock.configureFor("localhost", httpMock.port());
}
@AfterAll
public static void tearDown() {
httpMock.stop();
httpMock = null;
}
@Test @Test
public void getStopsTest() throws UraClientException { public void getStopsTest() throws UraClientException {
@ -74,7 +62,7 @@ public class UraClientTest {
mockHttpToFile(2, "instant_V2_stops.txt"); mockHttpToFile(2, "instant_V2_stops.txt");
// List stops and verify some values. // List stops and verify some values.
List<Stop> stops = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream").getStops(); List<Stop> stops = new UraClient(wireMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream").getStops();
assertThat(stops, hasSize(10)); assertThat(stops, hasSize(10));
assertThat(stops.get(0).getId(), is("100210")); assertThat(stops.get(0).getId(), is("100210"));
assertThat(stops.get(1).getName(), is("Brockenberg")); assertThat(stops.get(1).getName(), is("Brockenberg"));
@ -86,7 +74,7 @@ public class UraClientTest {
mockHttpToError(500); mockHttpToError(500);
try { try {
new UraClient(httpMock.baseUrl()).getStops(); new UraClient(wireMock.baseUrl()).getStops();
} catch (RuntimeException e) { } catch (RuntimeException e) {
assertThat(e, is(instanceOf(IllegalStateException.class))); assertThat(e, is(instanceOf(IllegalStateException.class)));
assertThat(e.getCause(), is(instanceOf(IOException.class))); assertThat(e.getCause(), is(instanceOf(IOException.class)));
@ -100,7 +88,7 @@ public class UraClientTest {
mockHttpToFile(2, "instant_V2_stops_line.txt"); mockHttpToFile(2, "instant_V2_stops_line.txt");
// List stops and verify some values. // List stops and verify some values.
List<Stop> stops = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream") List<Stop> stops = new UraClient(wireMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream")
.forLines("33") .forLines("33")
.getStops(); .getStops();
assertThat(stops, hasSize(47)); assertThat(stops, hasSize(47));
@ -118,7 +106,7 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_stops_circle.txt"); mockHttpToFile(1, "instant_V1_stops_circle.txt");
// List stops and verify some values. // List stops and verify some values.
List<Stop> stops = new UraClient(httpMock.baseUrl()) List<Stop> stops = new UraClient(wireMock.baseUrl())
.forPosition(51.51009, -0.1345734, 200) .forPosition(51.51009, -0.1345734, 200)
.getStops(); .getStops();
assertThat(stops, hasSize(13)); assertThat(stops, hasSize(13));
@ -130,7 +118,7 @@ public class UraClientTest {
assertThat(stops.get(5).getIndicator(), is(nullValue())); assertThat(stops.get(5).getIndicator(), is(nullValue()));
mockHttpToFile(1, "instant_V1_stops_circle_name.txt"); mockHttpToFile(1, "instant_V1_stops_circle_name.txt");
stops = new UraClient(httpMock.baseUrl()) stops = new UraClient(wireMock.baseUrl())
.forStopsByName("Piccadilly Circus") .forStopsByName("Piccadilly Circus")
.forPosition(51.51009, -0.1345734, 200) .forPosition(51.51009, -0.1345734, 200)
.getStops(); .getStops();
@ -144,13 +132,13 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_trips_destination.txt"); mockHttpToFile(1, "instant_V1_trips_destination.txt");
// List stops and verify some values. // List stops and verify some values.
List<Trip> trips = new UraClient(httpMock.baseUrl()).forDestinationNames("Piccadilly Circus").getTrips(); List<Trip> trips = new UraClient(wireMock.baseUrl()).forDestinationNames("Piccadilly Circus").getTrips();
assertThat(trips, hasSize(9)); assertThat(trips, hasSize(9));
assertThat(trips.stream().filter(t -> !t.getDestinationName().equals("Piccadilly Cir")).findAny(), assertThat(trips.stream().filter(t -> !t.getDestinationName().equals("Piccadilly Cir")).findAny(),
is(Optional.empty())); is(Optional.empty()));
mockHttpToFile(1, "instant_V1_trips_stop_destination.txt"); mockHttpToFile(1, "instant_V1_trips_stop_destination.txt");
trips = new UraClient(httpMock.baseUrl()) trips = new UraClient(wireMock.baseUrl())
.forStops("156") .forStops("156")
.forDestinationNames("Marble Arch") .forDestinationNames("Marble Arch")
.getTrips(); .getTrips();
@ -167,11 +155,11 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_trips_towards.txt"); mockHttpToFile(1, "instant_V1_trips_towards.txt");
/* List stops and verify some values */ /* List stops and verify some values */
List<Trip> trips = new UraClient(httpMock.baseUrl()).towards("Marble Arch").getTrips(); List<Trip> trips = new UraClient(wireMock.baseUrl()).towards("Marble Arch").getTrips();
assertThat(trips, hasSize(10)); assertThat(trips, hasSize(10));
mockHttpToFile(1, "instant_V1_trips_stop_towards.txt"); mockHttpToFile(1, "instant_V1_trips_stop_towards.txt");
trips = new UraClient(httpMock.baseUrl()).forStops("156").towards("Marble Arch").getTrips(); trips = new UraClient(wireMock.baseUrl()).forStops("156").towards("Marble Arch").getTrips();
assertThat(trips, hasSize(17)); assertThat(trips, hasSize(17));
assertThat(trips.stream().filter(t -> !t.getStop().getId().equals("156")).findAny(), is(Optional.empty())); assertThat(trips.stream().filter(t -> !t.getStop().getId().equals("156")).findAny(), is(Optional.empty()));
} }
@ -182,7 +170,7 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_trips_all.txt"); mockHttpToFile(1, "instant_V1_trips_all.txt");
// Get trips without filters and verify some values. // Get trips without filters and verify some values.
List<Trip> trips = new UraClient(httpMock.baseUrl()).getTrips(); List<Trip> trips = new UraClient(wireMock.baseUrl()).getTrips();
assertThat(trips, hasSize(10)); assertThat(trips, hasSize(10));
assertThat(trips.get(0).getId(), is("27000165015001")); assertThat(trips.get(0).getId(), is("27000165015001"));
assertThat(trips.get(1).getLineID(), is("55")); assertThat(trips.get(1).getLineID(), is("55"));
@ -199,7 +187,7 @@ public class UraClientTest {
mockHttpToFile(2, "instant_V2_trips_all.txt"); mockHttpToFile(2, "instant_V2_trips_all.txt");
// Get trips without filters and verify some values. // Get trips without filters and verify some values.
trips = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream") trips = new UraClient(wireMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream")
.getTrips(); .getTrips();
assertThat(trips, hasSize(10)); assertThat(trips, hasSize(10));
assertThat(trips.get(0).getId(), is("27000165015001")); assertThat(trips.get(0).getId(), is("27000165015001"));
@ -215,13 +203,13 @@ public class UraClientTest {
// Get limited number of trips. // Get limited number of trips.
mockHttpToFile(1, "instant_V1_trips_all.txt"); mockHttpToFile(1, "instant_V1_trips_all.txt");
trips = new UraClient(httpMock.baseUrl()).getTrips(5); trips = new UraClient(wireMock.baseUrl()).getTrips(5);
assertThat(trips, hasSize(5)); assertThat(trips, hasSize(5));
// Test mockException handling. // Test mockException handling.
mockHttpToError(502); mockHttpToError(502);
try { try {
new UraClient(httpMock.baseUrl()).getTrips(); new UraClient(wireMock.baseUrl()).getTrips();
} catch (RuntimeException e) { } catch (RuntimeException e) {
assertThat(e, is(instanceOf(IllegalStateException.class))); assertThat(e, is(instanceOf(IllegalStateException.class)));
assertThat(e.getCause(), is(instanceOf(IOException.class))); assertThat(e.getCause(), is(instanceOf(IOException.class)));
@ -231,7 +219,7 @@ public class UraClientTest {
mockHttpToException(); mockHttpToException();
UraClientException exception = assertThrows( UraClientException exception = assertThrows(
UraClientException.class, UraClientException.class,
() -> new UraClient(httpMock.baseUrl()).getTrips(), () -> new UraClient(wireMock.baseUrl()).getTrips(),
"Expected reader to raise an exception" "Expected reader to raise an exception"
); );
assertEquals("Failed to read trips from API", exception.getMessage(), "Unexpected error message"); assertEquals("Failed to read trips from API", exception.getMessage(), "Unexpected error message");
@ -244,7 +232,7 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_trips_stop.txt"); mockHttpToFile(1, "instant_V1_trips_stop.txt");
// Get trips for stop ID 100000 (Aachen Bushof) and verify some values. // Get trips for stop ID 100000 (Aachen Bushof) and verify some values.
List<Trip> trips = new UraClient(httpMock.baseUrl()) List<Trip> trips = new UraClient(wireMock.baseUrl())
.forStops("100000") .forStops("100000")
.getTrips(); .getTrips();
assertThat(trips, hasSize(10)); assertThat(trips, hasSize(10));
@ -256,7 +244,7 @@ public class UraClientTest {
// Get trips for stop name "Uniklinik" and verify some values. // Get trips for stop name "Uniklinik" and verify some values.
mockHttpToFile(1, "instant_V1_trips_stop_name.txt"); mockHttpToFile(1, "instant_V1_trips_stop_name.txt");
trips = new UraClient(httpMock.baseUrl()) trips = new UraClient(wireMock.baseUrl())
.forStopsByName("Uniklinik") .forStopsByName("Uniklinik")
.getTrips(); .getTrips();
assertThat(trips, hasSize(10)); assertThat(trips, hasSize(10));
@ -270,7 +258,7 @@ public class UraClientTest {
mockHttpToException(); mockHttpToException();
UraClientException exception = assertThrows( UraClientException exception = assertThrows(
UraClientException.class, UraClientException.class,
() -> new UraClient(httpMock.baseUrl()).getStops(), () -> new UraClient(wireMock.baseUrl()).getStops(),
"Expected reader to raise an exception" "Expected reader to raise an exception"
); );
assertEquals("Failed to read stops from API", exception.getMessage(), "Unexpected error message"); assertEquals("Failed to read stops from API", exception.getMessage(), "Unexpected error message");
@ -283,7 +271,7 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_trips_line.txt"); mockHttpToFile(1, "instant_V1_trips_line.txt");
// Get trips for line ID 3 and verify some values. // Get trips for line ID 3 and verify some values.
List<Trip> trips = new UraClient(httpMock.baseUrl()) List<Trip> trips = new UraClient(wireMock.baseUrl())
.forLines("3") .forLines("3")
.getTrips(); .getTrips();
assertThat(trips, hasSize(10)); assertThat(trips, hasSize(10));
@ -295,7 +283,7 @@ public class UraClientTest {
// Get trips for line name "3.A" and verify some values. // Get trips for line name "3.A" and verify some values.
mockHttpToFile(1, "instant_V1_trips_line_name.txt"); mockHttpToFile(1, "instant_V1_trips_line_name.txt");
trips = new UraClient(httpMock.baseUrl()) trips = new UraClient(wireMock.baseUrl())
.forLinesByName("3.A") .forLinesByName("3.A")
.getTrips(); .getTrips();
assertThat(trips, hasSize(10)); assertThat(trips, hasSize(10));
@ -307,7 +295,7 @@ public class UraClientTest {
// Get trips for line 3 with direction 1 and verify some values. // Get trips for line 3 with direction 1 and verify some values.
mockHttpToFile(1, "instant_V1_trips_line_direction.txt"); mockHttpToFile(1, "instant_V1_trips_line_direction.txt");
trips = new UraClient(httpMock.baseUrl()) trips = new UraClient(wireMock.baseUrl())
.forLines("412") .forLines("412")
.forDirection(2) .forDirection(2)
.getTrips(); .getTrips();
@ -317,7 +305,7 @@ public class UraClientTest {
// Test lineID and direction in different order. // Test lineID and direction in different order.
mockHttpToFile(1, "instant_V1_trips_line_direction.txt"); mockHttpToFile(1, "instant_V1_trips_line_direction.txt");
trips = new UraClient(httpMock.baseUrl()) trips = new UraClient(wireMock.baseUrl())
.forDirection(2) .forDirection(2)
.forLines("412") .forLines("412")
.getTrips(); .getTrips();
@ -332,7 +320,7 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_trips_stop_line.txt"); mockHttpToFile(1, "instant_V1_trips_stop_line.txt");
// Get trips for line ID 25 and 25 at stop 100000 and verify some values. // Get trips for line ID 25 and 25 at stop 100000 and verify some values.
List<Trip> trips = new UraClient(httpMock.baseUrl()) List<Trip> trips = new UraClient(wireMock.baseUrl())
.forLines("25", "35") .forLines("25", "35")
.forStops("100000") .forStops("100000")
.getTrips(); .getTrips();
@ -353,7 +341,7 @@ public class UraClientTest {
mockHttpToFile(1, "instant_V1_messages.txt"); mockHttpToFile(1, "instant_V1_messages.txt");
// Get messages without filter and verify some values. // Get messages without filter and verify some values.
List<Message> messages = new UraClient(httpMock.baseUrl()) List<Message> messages = new UraClient(wireMock.baseUrl())
.getMessages(); .getMessages();
assertThat(messages, hasSize(2)); assertThat(messages, hasSize(2));
assertThat(messages.get(0).getStop().getId(), is("100707")); assertThat(messages.get(0).getStop().getId(), is("100707"));
@ -368,7 +356,7 @@ public class UraClientTest {
mockHttpToException(); mockHttpToException();
UraClientException exception = assertThrows( UraClientException exception = assertThrows(
UraClientException.class, UraClientException.class,
() -> new UraClient(httpMock.baseUrl()).getMessages(), () -> new UraClient(wireMock.baseUrl()).getMessages(),
"Expected reader to raise an exception" "Expected reader to raise an exception"
); );
assertEquals("Failed to read messages from API", exception.getMessage(), "Unexpected error message"); assertEquals("Failed to read messages from API", exception.getMessage(), "Unexpected error message");
@ -381,7 +369,7 @@ public class UraClientTest {
mockHttpToFile(2, "instant_V2_messages_stop.txt"); mockHttpToFile(2, "instant_V2_messages_stop.txt");
// Get trips for stop ID 100707 (Berensberger Str.) and verify some values. // Get trips for stop ID 100707 (Berensberger Str.) and verify some values.
List<Message> messages = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream") List<Message> messages = new UraClient(wireMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream")
.forStops("100707") .forStops("100707")
.getMessages(); .getMessages();
assertThat(messages, hasSize(1)); assertThat(messages, hasSize(1));
@ -407,14 +395,14 @@ public class UraClientTest {
assertTrue(exception.getCause() instanceof HttpConnectTimeoutException, "Exception cause is not HttpConnectionTimeoutException"); assertTrue(exception.getCause() instanceof HttpConnectTimeoutException, "Exception cause is not HttpConnectionTimeoutException");
// Mock the HTTP call with delay of 200ms, but immediate connection. // Mock the HTTP call with delay of 200ms, but immediate connection.
WireMock.stubFor( wireMock.stubFor(
get(urlPathEqualTo("/interfaces/ura/instant_V1")).willReturn( get(urlPathEqualTo("/interfaces/ura/instant_V1")).willReturn(
aResponse().withFixedDelay(200).withBodyFile("instant_V1_trips_destination.txt") aResponse().withFixedDelay(200).withBodyFile("instant_V1_trips_destination.txt")
) )
); );
assertDoesNotThrow( assertDoesNotThrow(
() -> new UraClient( () -> new UraClient(
UraClientConfiguration.forBaseURL(httpMock.baseUrl()) UraClientConfiguration.forBaseURL(wireMock.baseUrl())
.withConnectTimeout(Duration.ofMillis(100)) .withConnectTimeout(Duration.ofMillis(100))
.build() .build()
).forDestinationNames("Piccadilly Circus").getTrips(), ).forDestinationNames("Piccadilly Circus").getTrips(),
@ -425,7 +413,7 @@ public class UraClientTest {
exception = assertThrows( exception = assertThrows(
UraClientException.class, UraClientException.class,
() -> new UraClient( () -> new UraClient(
UraClientConfiguration.forBaseURL(httpMock.baseUrl()) UraClientConfiguration.forBaseURL(wireMock.baseUrl())
.withTimeout(Duration.ofMillis(100)) .withTimeout(Duration.ofMillis(100))
.build() .build()
).forDestinationNames("Piccadilly Circus").getTrips(), ).forDestinationNames("Piccadilly Circus").getTrips(),
@ -435,7 +423,7 @@ public class UraClientTest {
assertDoesNotThrow( assertDoesNotThrow(
() -> new UraClient( () -> new UraClient(
UraClientConfiguration.forBaseURL(httpMock.baseUrl()) UraClientConfiguration.forBaseURL(wireMock.baseUrl())
.withTimeout(Duration.ofMillis(300)) .withTimeout(Duration.ofMillis(300))
.build() .build()
).forDestinationNames("Piccadilly Circus").getTrips(), ).forDestinationNames("Piccadilly Circus").getTrips(),
@ -444,7 +432,7 @@ public class UraClientTest {
} }
private static void mockHttpToFile(int version, String resourceFile) { private static void mockHttpToFile(int version, String resourceFile) {
WireMock.stubFor( wireMock.stubFor(
get(urlPathEqualTo("/interfaces/ura/instant_V" + version)).willReturn( get(urlPathEqualTo("/interfaces/ura/instant_V" + version)).willReturn(
aResponse().withBodyFile(resourceFile) aResponse().withBodyFile(resourceFile)
) )
@ -452,7 +440,7 @@ public class UraClientTest {
} }
private static void mockHttpToError(int code) { private static void mockHttpToError(int code) {
WireMock.stubFor( wireMock.stubFor(
get(anyUrl()).willReturn( get(anyUrl()).willReturn(
aResponse().withStatus(code) aResponse().withStatus(code)
) )
@ -460,7 +448,7 @@ public class UraClientTest {
} }
private static void mockHttpToException() { private static void mockHttpToException() {
WireMock.stubFor( wireMock.stubFor(
get(anyUrl()).willReturn( get(anyUrl()).willReturn(
aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK) aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK)
) )