diff --git a/pom.xml b/pom.xml index af688c2..9e73ef6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,6 @@ - + 4.0.0 de.stklcode.pubtrans @@ -65,15 +64,9 @@ test - net.bytebuddy - byte-buddy - 1.10.10 - test - - - net.bytebuddy - byte-buddy-agent - 1.10.10 + com.github.tomakehurst + wiremock + 2.26.3 test diff --git a/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java b/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java index 401df08..054e2ea 100644 --- a/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java +++ b/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java @@ -16,23 +16,23 @@ 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 de.stklcode.pubtrans.ura.model.Message; import de.stklcode.pubtrans.ura.model.Stop; import de.stklcode.pubtrans.ura.model.Trip; -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.agent.ByteBuddyAgent; -import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.IOException; -import java.io.InputStream; import java.util.List; import java.util.Optional; -import static net.bytebuddy.implementation.MethodDelegation.to; -import static net.bytebuddy.matcher.ElementMatchers.named; +import static com.github.tomakehurst.wiremock.client.WireMock.*; import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; @@ -46,29 +46,29 @@ import static org.hamcrest.core.Is.is; * @author Stefan Kalscheuer */ public class UraClientTest { - // Mocked resource URL and exception message. - private static String mockResource = null; - private static String mockException = null; + private static WireMockServer httpMock; @BeforeAll - public static void initByteBuddy() { - // Install ByteBuddy Agent. - ByteBuddyAgent.install(); + public static void setUp() { + // Initialize HTTP mock. + httpMock = new WireMockServer(WireMockConfiguration.options().dynamicPort()); + httpMock.start(); + WireMock.configureFor("localhost", httpMock.port()); + } - new ByteBuddy().redefine(UraClient.class) - .method(named("request")) - .intercept(to(UraClientTest.class)) - .make() - .load(UraClient.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + @AfterAll + public static void tearDown() { + httpMock.stop(); + httpMock = null; } @Test public void getStopsTest() { // Mock the HTTP call. - mockHttpToFile("instant_V2_stops.txt"); + mockHttpToFile(2, "instant_V2_stops.txt"); // List stops and verify some values. - List stops = new UraClient("mocked").getStops(); + List stops = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream").getStops(); assertThat(stops, hasSize(10)); assertThat(stops.get(0).getId(), is("100210")); assertThat(stops.get(1).getName(), is("Brockenberg")); @@ -77,36 +77,26 @@ public class UraClientTest { assertThat(stops.get(4).getLongitude(), is(6.0708663)); // Test Exception handling. - mockHttpToException("Provoked Exception 1"); + mockHttpToError(500); try { - new UraClient("mocked").getStops(); + new UraClient(httpMock.baseUrl()).getStops(); } catch (RuntimeException e) { assertThat(e, is(instanceOf(IllegalStateException.class))); assertThat(e.getCause(), is(instanceOf(IOException.class))); - assertThat(e.getCause().getMessage(), is("Provoked Exception 1")); + assertThat(e.getCause().getMessage(), startsWith("Server returned HTTP response code: 500 for URL")); } } - public static InputStream request(String originalURL) throws IOException { - if (mockResource == null && mockException != null) { - IOException e = new IOException(mockException); - mockException = null; - throw e; - } - - InputStream res = UraClientTest.class.getResourceAsStream(mockResource); - mockResource = null; - return res; - } - @Test public void getStopsForLineTest() { // Mock the HTTP call. - mockHttpToFile("instant_V2_stops_line.txt"); + mockHttpToFile(2, "instant_V2_stops_line.txt"); // List stops and verify some values. - List stops = new UraClient("mocked").forLines("33").getStops(); + List stops = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream") + .forLines("33") + .getStops(); assertThat(stops, hasSize(47)); assertThat(stops.get(0).getId(), is("100000")); assertThat(stops.get(1).getName(), is("Kuckelkorn")); @@ -119,10 +109,10 @@ public class UraClientTest { @Test public void getStopsForPositionTest() { // Mock the HTTP call. - mockHttpToFile("instant_V1_stops_circle.txt"); + mockHttpToFile(1, "instant_V1_stops_circle.txt"); // List stops and verify some values. - List stops = new UraClient("mocked") + List stops = new UraClient(httpMock.baseUrl()) .forPosition(51.51009, -0.1345734, 200) .getStops(); assertThat(stops, hasSize(13)); @@ -133,8 +123,8 @@ public class UraClientTest { assertThat(stops.get(4).getLongitude(), is(-0.134172)); assertThat(stops.get(5).getIndicator(), is(nullValue())); - mockHttpToFile("instant_V1_stops_circle_name.txt"); - stops = new UraClient("mocked") + mockHttpToFile(1, "instant_V1_stops_circle_name.txt"); + stops = new UraClient(httpMock.baseUrl()) .forStopsByName("Piccadilly Circus") .forPosition(51.51009, -0.1345734, 200) .getStops(); @@ -145,16 +135,16 @@ public class UraClientTest { @Test public void getTripsForDestinationNamesTest() { // Mock the HTTP call. - mockHttpToFile("instant_V1_trips_destination.txt"); + mockHttpToFile(1, "instant_V1_trips_destination.txt"); // List stops and verify some values. - List trips = new UraClient("mocked").forDestinationNames("Piccadilly Circus").getTrips(); + List trips = new UraClient(httpMock.baseUrl()).forDestinationNames("Piccadilly Circus").getTrips(); assertThat(trips, hasSize(9)); assertThat(trips.stream().filter(t -> !t.getDestinationName().equals("Piccadilly Cir")).findAny(), is(Optional.empty())); - mockHttpToFile("instant_V1_trips_stop_destination.txt"); - trips = new UraClient("mocked") + mockHttpToFile(1, "instant_V1_trips_stop_destination.txt"); + trips = new UraClient(httpMock.baseUrl()) .forStops("156") .forDestinationNames("Marble Arch") .getTrips(); @@ -168,14 +158,14 @@ public class UraClientTest { @Test public void getTripsTowardsTest() { // Mock the HTTP call. - mockHttpToFile("instant_V1_trips_towards.txt"); + mockHttpToFile(1, "instant_V1_trips_towards.txt"); /* List stops and verify some values */ - List trips = new UraClient("mocked").towards("Marble Arch").getTrips(); + List trips = new UraClient(httpMock.baseUrl()).towards("Marble Arch").getTrips(); assertThat(trips, hasSize(10)); - mockHttpToFile("instant_V1_trips_stop_towards.txt"); - trips = new UraClient("mocked").forStops("156").towards("Marble Arch").getTrips(); + mockHttpToFile(1, "instant_V1_trips_stop_towards.txt"); + trips = new UraClient(httpMock.baseUrl()).forStops("156").towards("Marble Arch").getTrips(); assertThat(trips, hasSize(17)); assertThat(trips.stream().filter(t -> !t.getStop().getId().equals("156")).findAny(), is(Optional.empty())); } @@ -183,10 +173,10 @@ public class UraClientTest { @Test public void getTripsTest() { // Mock the HTTP call. - mockHttpToFile("instant_V1_trips_all.txt"); + mockHttpToFile(1, "instant_V1_trips_all.txt"); // Get trips without filters and verify some values. - List trips = new UraClient("mocked").getTrips(); + List trips = new UraClient(httpMock.baseUrl()).getTrips(); assertThat(trips, hasSize(10)); assertThat(trips.get(0).getId(), is("27000165015001")); assertThat(trips.get(1).getLineID(), is("55")); @@ -200,10 +190,11 @@ public class UraClientTest { assertThat(trips.get(9).getStop().getId(), is("100002")); // Repeat test for API V2. - mockHttpToFile("instant_V2_trips_all.txt"); + mockHttpToFile(2, "instant_V2_trips_all.txt"); // Get trips without filters and verify some values. - trips = new UraClient("mocked").getTrips(); + trips = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream") + .getTrips(); assertThat(trips, hasSize(10)); assertThat(trips.get(0).getId(), is("27000165015001")); assertThat(trips.get(1).getLineID(), is("55")); @@ -217,28 +208,28 @@ public class UraClientTest { assertThat(trips.get(9).getStop().getId(), is("100002")); // Get limited number of trips. - mockHttpToFile("instant_V1_trips_all.txt"); - trips = new UraClient("mocked").getTrips(5); + mockHttpToFile(1, "instant_V1_trips_all.txt"); + trips = new UraClient(httpMock.baseUrl()).getTrips(5); assertThat(trips, hasSize(5)); // Test mockException handling. - mockHttpToException("Provoked mockException 2"); + mockHttpToError(502); try { - new UraClient("mocked").getTrips(); + new UraClient(httpMock.baseUrl()).getTrips(); } catch (RuntimeException e) { assertThat(e, is(instanceOf(IllegalStateException.class))); assertThat(e.getCause(), is(instanceOf(IOException.class))); - assertThat(e.getCause().getMessage(), is("Provoked mockException 2")); + assertThat(e.getCause().getMessage(), startsWith("Server returned HTTP response code: 502 for URL")); } } @Test public void getTripsForStopTest() { // Mock the HTTP call. - mockHttpToFile("instant_V1_trips_stop.txt"); + mockHttpToFile(1, "instant_V1_trips_stop.txt"); // Get trips for stop ID 100000 (Aachen Bushof) and verify some values. - List trips = new UraClient("mocked") + List trips = new UraClient(httpMock.baseUrl()) .forStops("100000") .getTrips(); assertThat(trips, hasSize(10)); @@ -249,8 +240,8 @@ public class UraClientTest { assertThat(trips.get(3).getStop().getIndicator(), is("H.15")); // Get trips for stop name "Uniklinik" and verify some values. - mockHttpToFile("instant_V1_trips_stop_name.txt"); - trips = new UraClient("mocked") + mockHttpToFile(1, "instant_V1_trips_stop_name.txt"); + trips = new UraClient(httpMock.baseUrl()) .forStopsByName("Uniklinik") .getTrips(); assertThat(trips, hasSize(10)); @@ -265,10 +256,10 @@ public class UraClientTest { @Test public void getTripsForLine() { // Mock the HTTP call. - mockHttpToFile("instant_V1_trips_line.txt"); + mockHttpToFile(1, "instant_V1_trips_line.txt"); // Get trips for line ID 3 and verify some values. - List trips = new UraClient("mocked") + List trips = new UraClient(httpMock.baseUrl()) .forLines("3") .getTrips(); assertThat(trips, hasSize(10)); @@ -279,8 +270,8 @@ public class UraClientTest { assertThat(trips.get(3).getStop().getIndicator(), is("H.4 (Pontwall)")); // Get trips for line name "3.A" and verify some values. - mockHttpToFile("instant_V1_trips_line_name.txt"); - trips = new UraClient("mocked") + mockHttpToFile(1, "instant_V1_trips_line_name.txt"); + trips = new UraClient(httpMock.baseUrl()) .forLinesByName("3.A") .getTrips(); assertThat(trips, hasSize(10)); @@ -291,8 +282,8 @@ public class UraClientTest { assertThat(trips.get(3).getStop().getName(), is("Aachen Gartenstraße")); // Get trips for line 3 with direction 1 and verify some values. - mockHttpToFile("instant_V1_trips_line_direction.txt"); - trips = new UraClient("mocked") + mockHttpToFile(1, "instant_V1_trips_line_direction.txt"); + trips = new UraClient(httpMock.baseUrl()) .forLines("412") .forDirection(2) .getTrips(); @@ -301,8 +292,8 @@ public class UraClientTest { assertThat(trips.stream().filter(t -> !t.getDirectionID().equals(2)).findAny(), is(Optional.empty())); // Test lineID and direction in different order. - mockHttpToFile("instant_V1_trips_line_direction.txt"); - trips = new UraClient("mocked") + mockHttpToFile(1, "instant_V1_trips_line_direction.txt"); + trips = new UraClient(httpMock.baseUrl()) .forDirection(2) .forLines("412") .getTrips(); @@ -314,10 +305,10 @@ public class UraClientTest { @Test public void getTripsForStopAndLine() { // Mock the HTTP call. - mockHttpToFile("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. - List trips = new UraClient("mocked") + List trips = new UraClient(httpMock.baseUrl()) .forLines("25", "35") .forStops("100000") .getTrips(); @@ -335,10 +326,10 @@ public class UraClientTest { @Test public void getMessages() { // Mock the HTTP call. - mockHttpToFile("instant_V1_messages.txt"); + mockHttpToFile(1, "instant_V1_messages.txt"); // Get messages without filter and verify some values. - List messages = new UraClient("mocked") + List messages = new UraClient(httpMock.baseUrl()) .getMessages(); assertThat(messages, hasSize(2)); assertThat(messages.get(0).getStop().getId(), is("100707")); @@ -354,10 +345,10 @@ public class UraClientTest { @Test public void getMessagesForStop() { // Mock the HTTP call. - mockHttpToFile("instant_V2_messages_stop.txt"); + mockHttpToFile(2, "instant_V2_messages_stop.txt"); // Get trips for stop ID 100707 (Berensberger Str.) and verify some values. - List messages = new UraClient("mocked") + List messages = new UraClient(httpMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream") .forStops("100707") .getMessages(); assertThat(messages, hasSize(1)); @@ -369,11 +360,19 @@ public class UraClientTest { } - private static void mockHttpToFile(String newResourceFile) { - mockResource = newResourceFile; + private static void mockHttpToFile(int version, String resourceFile) { + WireMock.stubFor( + get(urlPathEqualTo("/interfaces/ura/instant_V" + version)).willReturn( + aResponse().withBodyFile(resourceFile) + ) + ); } - private static void mockHttpToException(String newException) { - mockException = newException; + private static void mockHttpToError(int code) { + WireMock.stubFor( + get(anyUrl()).willReturn( + aResponse().withStatus(code) + ) + ); } } diff --git a/src/test/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReaderTest.java b/src/test/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReaderTest.java index d56c03e..0f62da0 100644 --- a/src/test/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReaderTest.java +++ b/src/test/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReaderTest.java @@ -16,51 +16,59 @@ package de.stklcode.pubtrans.ura.reader; -import de.stklcode.pubtrans.ura.UraClientTest; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.common.FileSource; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import com.github.tomakehurst.wiremock.extension.Parameters; +import com.github.tomakehurst.wiremock.extension.ResponseTransformer; +import com.github.tomakehurst.wiremock.http.ChunkedDribbleDelay; +import com.github.tomakehurst.wiremock.http.Request; +import com.github.tomakehurst.wiremock.http.Response; import de.stklcode.pubtrans.ura.model.Trip; -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.agent.ByteBuddyAgent; -import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.io.*; +import java.io.IOException; import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; -import java.util.Queue; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static net.bytebuddy.implementation.MethodDelegation.to; -import static net.bytebuddy.matcher.ElementMatchers.named; +import static com.github.tomakehurst.wiremock.client.WireMock.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assumptions.assumeTrue; /** * Unit test for the asynchronous URA Trip reader. + *

+ * Because this test runs asynchronously, it might not work as expected in debugging environments. + * Stream input files are normalized to equal line length and split into chunks, one line each 500ms. * * @author Stefan Kalscheuer */ public class AsyncUraTripReaderTest { - private static final Queue MOCK_LINES = new ArrayDeque<>(); - private static PipedOutputStream mockOutputStream = new PipedOutputStream(); + private static WireMockServer httpMock; @BeforeAll - public static void initByteBuddy() { - // Install ByteBuddy Agent. - ByteBuddyAgent.install(); + public static void setUp() { + // Initialize HTTP mock. + httpMock = new WireMockServer(WireMockConfiguration.options().dynamicPort() + .asynchronousResponseEnabled(true) + .extensions(StreamTransformer.class) + ); + httpMock.start(); + WireMock.configureFor("localhost", httpMock.port()); + } - // Mock the URL.openStream() call. - new ByteBuddy().redefine(AsyncUraTripReader.class) - .method(named("getInputStream")) - .intercept(to(AsyncUraTripReaderTest.class)) - .make() - .load(AsyncUraTripReader.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + @AfterAll + public static void tearDown() { + httpMock.stop(); + httpMock = null; } /** @@ -80,10 +88,10 @@ public class AsyncUraTripReaderTest { Deque trips = new ConcurrentLinkedDeque<>(); // Start with V1 data and read file to mock list. - readLinesToMock(UraClientTest.class.getResource("stream_V1_stops_all.txt")); + readLinesToMock(1, "/__files/stream_V1_stops_all.txt", 8); AsyncUraTripReader tr = new AsyncUraTripReader( - UraClientTest.class.getResource("stream_V1_stops_all.txt"), + new URL(httpMock.baseUrl() + "/interfaces/ura/stream_V1"), Collections.singletonList( trip -> { trips.add(trip); @@ -98,38 +106,22 @@ public class AsyncUraTripReaderTest { TimeUnit.SECONDS.sleep(1); assumeTrue(trips.isEmpty(), "Trips should empty after 1s without reading"); - // Now write a single line to the stream pipe. - assumeTrue(writeNextLine(), "First line (version info) should be written"); - assumeTrue(writeNextLine(), "Second line (first record) should be written"); + // Wait another 1s for the callback to be triggered. + TimeUnit.SECONDS.sleep(1); - // Wait up to 1s for the callback to be triggered. - int i = 10; - while (counter.get() < 1 && i-- > 0) { - TimeUnit.MILLISECONDS.sleep(100); - } - - assertThat("Unexpected number of trips after first entry", trips.size(), is(1)); + assertThat("Unexpected number of trips after first entry", trips.size(), is(2)); // Flush all remaining lines. - while (writeNextLine()) { - TimeUnit.MILLISECONDS.sleep(10); - } - - i = 10; - counter.set(0); - while (counter.get() < 1 && i-- > 0) { - TimeUnit.MILLISECONDS.sleep(100); - } - - tr.close(); + TimeUnit.SECONDS.sleep(3); assertThat("Unexpected number of trips after all lines have been flushed", trips.size(), is(7)); // Clear trip list and repeat with V2 data. trips.clear(); - readLinesToMock(UraClientTest.class.getResource("stream_V2_stops_all.txt")); + readLinesToMock(2, "/__files/stream_V2_stops_all.txt", 8); + tr = new AsyncUraTripReader( - UraClientTest.class.getResource("stream_V2_stops_all.txt"), + new URL(httpMock.baseUrl() + "/interfaces/ura/stream_V2"), Collections.singletonList(trips::add) ); @@ -139,35 +131,20 @@ public class AsyncUraTripReaderTest { TimeUnit.SECONDS.sleep(1); assumeTrue(trips.isEmpty(), "Trips should empty after 1s without reading"); - assumeTrue(writeNextLine(), "First line of v2 (version info) should be written"); - assumeTrue(writeNextLine(), "Second line of v2 (first record) should be written"); - - i = 10; - counter.set(0); - while (counter.get() < 1 && i-- > 0) { - TimeUnit.MILLISECONDS.sleep(100); - } - assertThat("Unexpected number of v2 trips after first entry", trips.size(), is(1)); + TimeUnit.SECONDS.sleep(1); + assertThat("Unexpected number of v2 trips after first entry", trips.size(), is(2)); // Add a second consumer that pushes to another list. Deque trips2 = new ConcurrentLinkedDeque<>(); tr.addConsumer(trips2::add); // Flush all remaining lines. - while (writeNextLine()) { - TimeUnit.MILLISECONDS.sleep(10); - } - - i = 10; - counter.set(0); - while (counter.get() < 1 && i-- > 0) { - TimeUnit.MILLISECONDS.sleep(100); - } + TimeUnit.SECONDS.sleep(3); tr.close(); assertThat("Unexpected number of v2 trips after all lines have been flushed", trips.size(), is(7)); - assertThat("Unexpected number of v2 trips in list 2 after all lines have been flushed", trips2.size(), is(6)); + assertThat("Unexpected number of v2 trips in list 2 after all lines have been flushed", trips2.size(), is(5)); assertThat("Same object should have been pushed to both lists", trips.containsAll(trips2)); } @@ -186,10 +163,10 @@ public class AsyncUraTripReaderTest { Deque trips = new ConcurrentLinkedDeque<>(); // Start with V1 data and read file to mock list. - readLinesToMock(UraClientTest.class.getResource("stream_V1_stops_all.txt")); + readLinesToMock(1, "/__files/stream_V1_stops_all.txt", 8); AsyncUraTripReader tr = new AsyncUraTripReader( - UraClientTest.class.getResource("stream_V1_stops_all.txt"), + new URL(httpMock.baseUrl() + "/interfaces/ura/stream_V1"), Collections.singletonList( trip -> { trips.add(trip); @@ -205,29 +182,16 @@ public class AsyncUraTripReaderTest { TimeUnit.MILLISECONDS.sleep(100); assumeTrue(trips.isEmpty(), "Trips should empty after 100ms without reading"); - // Now write a single line to the stream pipe. - assumeTrue(writeNextLine(), "First line (version info) should be written"); - assumeTrue(writeNextLine(), "Second line (first record) should be written"); - - // Wait up to 1s for the callback to be triggered. - int i = 10; - while (counter.get() < 1 && i-- > 0) { - TimeUnit.MILLISECONDS.sleep(100); - } + // Wait for 1s for the callback to be triggered. + TimeUnit.SECONDS.sleep(1); assumeTrue(1 == trips.size(), "Unexpected number of trips after first entry"); // Close the stream. - mockOutputStream.close(); - - i = 10; - counter.set(0); - while (counter.get() < 1 && i-- > 0) { - TimeUnit.MILLISECONDS.sleep(100); - } - tr.close(); + // Wait for another second. + TimeUnit.MILLISECONDS.sleep(100); assertThat("Unexpected number of trips after all lines have been flushed", trips.size(), is(1)); } @@ -235,47 +199,34 @@ public class AsyncUraTripReaderTest { /** * Read an input file to the line buffer. * - * @param url Input URL. - * @throws IOException Error reading the data. + * @param version API version. + * @param resourceFile Resource file name. + * @param chunks Number of chunks. */ - private static void readLinesToMock(URL url) throws IOException { - try (InputStream is = url.openStream(); - BufferedReader br = new BufferedReader(new InputStreamReader(is))) { - String line = br.readLine(); - while (line != null) { - MOCK_LINES.add(line); - line = br.readLine(); - } - } + private void readLinesToMock(int version, String resourceFile, int chunks) { + WireMock.stubFor(get(urlPathEqualTo("/interfaces/ura/stream_V" + version)) + .willReturn(aResponse() + .withTransformer("stream-transformer", "source", resourceFile) + .withTransformer("stream-transformer", "chunks", chunks) + ) + ); } - /** - * Write next line from the buffer to the mocked stream pipe. - * - * @return {@code true} if a line has been written. - * @throws IOException Error writing the data. - */ - private static boolean writeNextLine() throws IOException { - String line = MOCK_LINES.poll(); - if (line != null) { - line += "\n"; - mockOutputStream.write(line.getBytes(StandardCharsets.UTF_8)); - mockOutputStream.flush(); - return true; - } else { - return false; + public static class StreamTransformer extends ResponseTransformer { + @Override + public Response transform(Request request, Response response, FileSource files, Parameters parameters) { + int chunks = parameters.getInt("chunks", 1); + return Response.Builder.like(response) + // Read source file to response. + .body(() -> AsyncUraTripReaderTest.class.getResourceAsStream(parameters.getString("source"))) + // Split response in given number of chunks with 500ms delay. + .chunkedDribbleDelay(new ChunkedDribbleDelay(chunks, chunks * 500)) + .build(); } - } - /** - * Function to mock the static {@code AsyncUraTripReader#getInputStream(URL)} method. - * - * @param url URL to read from. - * @return Input Stream. - * @throws IOException On errors. - */ - public static InputStream getInputStream(URL url) throws IOException { - mockOutputStream = new PipedOutputStream(); - return new PipedInputStream(mockOutputStream); + @Override + public String getName() { + return "stream-transformer"; + } } } diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_messages.txt b/src/test/resources/__files/instant_V1_messages.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_messages.txt rename to src/test/resources/__files/instant_V1_messages.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_stops_circle.txt b/src/test/resources/__files/instant_V1_stops_circle.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_stops_circle.txt rename to src/test/resources/__files/instant_V1_stops_circle.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_stops_circle_name.txt b/src/test/resources/__files/instant_V1_stops_circle_name.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_stops_circle_name.txt rename to src/test/resources/__files/instant_V1_stops_circle_name.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_all.txt b/src/test/resources/__files/instant_V1_trips_all.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_all.txt rename to src/test/resources/__files/instant_V1_trips_all.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_destination.txt b/src/test/resources/__files/instant_V1_trips_destination.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_destination.txt rename to src/test/resources/__files/instant_V1_trips_destination.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_line.txt b/src/test/resources/__files/instant_V1_trips_line.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_line.txt rename to src/test/resources/__files/instant_V1_trips_line.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_line_direction.txt b/src/test/resources/__files/instant_V1_trips_line_direction.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_line_direction.txt rename to src/test/resources/__files/instant_V1_trips_line_direction.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_line_name.txt b/src/test/resources/__files/instant_V1_trips_line_name.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_line_name.txt rename to src/test/resources/__files/instant_V1_trips_line_name.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop.txt b/src/test/resources/__files/instant_V1_trips_stop.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop.txt rename to src/test/resources/__files/instant_V1_trips_stop.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_destination.txt b/src/test/resources/__files/instant_V1_trips_stop_destination.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_destination.txt rename to src/test/resources/__files/instant_V1_trips_stop_destination.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_line.txt b/src/test/resources/__files/instant_V1_trips_stop_line.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_line.txt rename to src/test/resources/__files/instant_V1_trips_stop_line.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_name.txt b/src/test/resources/__files/instant_V1_trips_stop_name.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_name.txt rename to src/test/resources/__files/instant_V1_trips_stop_name.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_towards.txt b/src/test/resources/__files/instant_V1_trips_stop_towards.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_stop_towards.txt rename to src/test/resources/__files/instant_V1_trips_stop_towards.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_towards.txt b/src/test/resources/__files/instant_V1_trips_towards.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V1_trips_towards.txt rename to src/test/resources/__files/instant_V1_trips_towards.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V2_messages_stop.txt b/src/test/resources/__files/instant_V2_messages_stop.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V2_messages_stop.txt rename to src/test/resources/__files/instant_V2_messages_stop.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V2_stops.txt b/src/test/resources/__files/instant_V2_stops.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V2_stops.txt rename to src/test/resources/__files/instant_V2_stops.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V2_stops_line.txt b/src/test/resources/__files/instant_V2_stops_line.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V2_stops_line.txt rename to src/test/resources/__files/instant_V2_stops_line.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/instant_V2_trips_all.txt b/src/test/resources/__files/instant_V2_trips_all.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/instant_V2_trips_all.txt rename to src/test/resources/__files/instant_V2_trips_all.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/stream_V1_stops_all.txt b/src/test/resources/__files/stream_V1_stops_all.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/stream_V1_stops_all.txt rename to src/test/resources/__files/stream_V1_stops_all.txt diff --git a/src/test/resources/de/stklcode/pubtrans/ura/stream_V2_stops_all.txt b/src/test/resources/__files/stream_V2_stops_all.txt similarity index 100% rename from src/test/resources/de/stklcode/pubtrans/ura/stream_V2_stops_all.txt rename to src/test/resources/__files/stream_V2_stops_all.txt