From 74371d563cde04977535994fcbe59a5032a8c454 Mon Sep 17 00:00:00 2001 From: Jean-Kevin KPADEY Date: Wed, 16 Sep 2026 10:55:26 +0200 Subject: [PATCH] test(spi): use offline OurAirports fixtures --- .../impl/OurAirportsAirportProvider.java | 52 +++++++++++++++---- .../impl/OurAirportsAirportProviderTest.java | 24 ++++++++- .../test/resources/ourairports/airports.csv | 2 + .../test/resources/ourairports/countries.csv | 2 + 4 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 metarParser-spi/src/test/resources/ourairports/airports.csv create mode 100644 metarParser-spi/src/test/resources/ourairports/countries.csv diff --git a/metarParser-spi/src/main/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProvider.java b/metarParser-spi/src/main/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProvider.java index 7cb54945..9dd4a0d4 100644 --- a/metarParser-spi/src/main/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProvider.java +++ b/metarParser-spi/src/main/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProvider.java @@ -36,6 +36,8 @@ public final class OurAirportsAirportProvider implements AirportProvider { private final Map countries; /** Map of airports. */ private final Map airports; + /** HTTP client used to retrieve airport data. */ + private final HttpClient httpClient; /** Common CSV format. */ private final CSVFormat csvFormat; @@ -46,8 +48,25 @@ public final class OurAirportsAirportProvider implements AirportProvider { * @throws URISyntaxException when the URI is invalid */ public OurAirportsAirportProvider() throws IOException, URISyntaxException, InterruptedException { + this(HttpClient.newBuilder().build()); + } + + /** + * Creates a provider with the supplied HTTP client. + * + *

This constructor is package-private to support deterministic tests without changing + * the public HTTP-based provider API. + * + * @param client HTTP client used to retrieve OurAirports data + * @throws IOException when network error + * @throws URISyntaxException when a URI is invalid + * @throws InterruptedException when the request is interrupted + */ + OurAirportsAirportProvider(final HttpClient client) + throws IOException, URISyntaxException, InterruptedException { countries = new HashMap<>(); airports = new HashMap<>(); + httpClient = client; csvFormat = CSVFormat.RFC4180; buildCountries(); buildAirport(); @@ -67,10 +86,18 @@ public void buildCountries() throws URISyntaxException, IOException, Interrupted .timeout(Duration.ofSeconds(5)) .build(); - HttpResponse response = HttpClient.newBuilder() - .build() - .send(request, HttpResponse.BodyHandlers.ofInputStream()); - try (CSVParser parser = csvFormat.parse(new InputStreamReader(response.body(), StandardCharsets.UTF_8))) { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); + parseCountries(response.body()); + } + + /** + * Parses countries CSV data and adds the records to the country map. + * + * @param countriesStream stream containing countries.csv data + * @throws IOException when the stream cannot be parsed + */ + private void parseCountries(final InputStream countriesStream) throws IOException { + try (CSVParser parser = csvFormat.parse(new InputStreamReader(countriesStream, StandardCharsets.UTF_8))) { for (CSVRecord line: parser) { Country c = new Country(); c.setName(line.get(2)); @@ -93,10 +120,18 @@ public void buildAirport() throws URISyntaxException, IOException, InterruptedEx .timeout(Duration.ofSeconds(5)) .build(); - HttpResponse response = HttpClient.newBuilder() - .build() - .send(request, HttpResponse.BodyHandlers.ofInputStream()); - try (CSVParser parser = csvFormat.parse(new InputStreamReader(response.body(), StandardCharsets.UTF_8))) { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); + parseAirports(response.body()); + } + + /** + * Parses airports CSV data and adds the records to the airport map. + * + * @param airportsStream stream containing airports.csv data + * @throws IOException when the stream cannot be parsed + */ + private void parseAirports(final InputStream airportsStream) throws IOException { + try (CSVParser parser = csvFormat.parse(new InputStreamReader(airportsStream, StandardCharsets.UTF_8))) { for (CSVRecord line : parser) { Airport airport = new Airport(); airport.setIcao(line.get(1)); @@ -117,4 +152,3 @@ public Map getAirports() { return Collections.unmodifiableMap(airports); } } - diff --git a/metarParser-spi/src/test/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProviderTest.java b/metarParser-spi/src/test/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProviderTest.java index 6c7597a0..67bc19e8 100644 --- a/metarParser-spi/src/test/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProviderTest.java +++ b/metarParser-spi/src/test/java/io/github/mivek/provider/airport/impl/OurAirportsAirportProviderTest.java @@ -5,12 +5,20 @@ import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.not; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import io.github.mivek.model.Airport; import io.github.mivek.provider.airport.AirportProvider; import java.io.IOException; +import java.io.InputStream; import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.Map; +import java.util.Objects; import org.junit.jupiter.api.Test; /** @@ -19,8 +27,15 @@ class OurAirportsAirportProviderTest { @Test - void testGetAirport() throws IOException, URISyntaxException, InterruptedException { - AirportProvider provider = new OurAirportsAirportProvider(); + void testGetAirport() throws IOException, InterruptedException, URISyntaxException { + HttpClient client = mock(HttpClient.class); + HttpResponse countriesResponse = mock(HttpResponse.class); + HttpResponse airportsResponse = mock(HttpResponse.class); + doReturn(fixture("countries.csv")).when(countriesResponse).body(); + doReturn(fixture("airports.csv")).when(airportsResponse).body(); + doReturn(countriesResponse, airportsResponse).when(client).send(any(HttpRequest.class), any()); + + AirportProvider provider = new OurAirportsAirportProvider(client); Map airports = provider.getAirports(); @@ -28,4 +43,9 @@ void testGetAirport() throws IOException, URISyntaxException, InterruptedExcepti assertThat(airports, hasKey("LFPG")); assertNotNull(airports.get("LFPG")); } + + private static InputStream fixture(final String name) { + return Objects.requireNonNull( + OurAirportsAirportProviderTest.class.getResourceAsStream("/ourairports/" + name)); + } } diff --git a/metarParser-spi/src/test/resources/ourairports/airports.csv b/metarParser-spi/src/test/resources/ourairports/airports.csv new file mode 100644 index 00000000..b8f7bf79 --- /dev/null +++ b/metarParser-spi/src/test/resources/ourairports/airports.csv @@ -0,0 +1,2 @@ +id,ident,type,name,latitude_deg,longitude_deg,elevation_ft,continent,iso_country,iso_region,municipality,scheduled_service,gps_code,iata_code,local_code,home_link,wikipedia_link,keywords +6523,LFPG,large_airport,Paris Charles de Gaulle Airport,49.01279830932617,2.55,392,EU,FR,FR-IDF,Paris,yes,LFPG,CDG,LFPG,,, diff --git a/metarParser-spi/src/test/resources/ourairports/countries.csv b/metarParser-spi/src/test/resources/ourairports/countries.csv new file mode 100644 index 00000000..1b6281b2 --- /dev/null +++ b/metarParser-spi/src/test/resources/ourairports/countries.csv @@ -0,0 +1,2 @@ +id,code,name +83,FR,France