From 68abfe66fa536286093ebab5ae8eaf03695ac2c3 Mon Sep 17 00:00:00 2001 From: Martin Eyben Date: Sun, 24 Nov 2024 00:18:19 +0100 Subject: [PATCH] feat: OpenWeatherMap tests --- src/main/java/eirb/pg203/OpenWeatherMap.java | 24 +- src/test/java/eirb/pg203/WeatherAPITest.java | 14 - .../java/eirb/pg203/WeatherDataAPITest.java | 60 +- .../FakeJSONFetcherOpenWeatherMap.java | 33 + .../Bordeaux-partial-cloudy-rain-sunny.json | 1475 +++++++++++++++++ .../OpenWeatherMap/wrong-apikey.json | 4 + 6 files changed, 1579 insertions(+), 31 deletions(-) create mode 100644 src/test/java/eirb/pg203/fakeJSONFetcher/FakeJSONFetcherOpenWeatherMap.java create mode 100644 src/test/resources/OpenWeatherMap/Bordeaux-partial-cloudy-rain-sunny.json create mode 100644 src/test/resources/OpenWeatherMap/wrong-apikey.json diff --git a/src/main/java/eirb/pg203/OpenWeatherMap.java b/src/main/java/eirb/pg203/OpenWeatherMap.java index 9a54da3..580b57f 100644 --- a/src/main/java/eirb/pg203/OpenWeatherMap.java +++ b/src/main/java/eirb/pg203/OpenWeatherMap.java @@ -9,6 +9,7 @@ import eirb.pg203.utils.JSONFetcher; import java.io.IOException; import java.net.URI; import java.net.URL; +import java.time.Clock; import java.time.DayOfWeek; import java.time.Instant; import java.time.ZoneId; @@ -23,29 +24,29 @@ import eirb.pg203.WeatherData.Condition; public class OpenWeatherMap implements WeatherDataAPI { private static final String forecastBaseURL = "https://api.openweathermap.org/data/2.5/forecast"; private String APIKey; - private static final JSONFetcherInterface JSONFetcher = new JSONFetcher(); + Clock clock = Clock.systemUTC(); + JSONFetcherInterface JSONFetcher = new JSONFetcher(); OpenWeatherMap(String APIKey) { this.APIKey = APIKey; } - private JSONObject fetchWeather(int days, City city) throws IOException { + private JSONObject fetchWeather(City city) throws IOException { URL url = URI.create( String.format(Locale.ENGLISH, forecastBaseURL + "?appid=%s&lat=%.2f&lon=%.2f&units=metric", APIKey, city.getCityCoords().getLat(), - city.getCityCoords().getLon(), - days + city.getCityCoords().getLon() ) ).toURL(); return JSONFetcher.fetch(url); } - private static WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) { + private WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) { JSONArray list = response.getJSONArray("list"); - DayOfWeek targetedDay = Instant.now().plusSeconds(day * 24 * 3600).atZone(ZoneId.systemDefault()).getDayOfWeek(); + DayOfWeek targetedDay = Instant.now(clock).plusSeconds(day * 24 * 3600).atZone(ZoneId.systemDefault()).getDayOfWeek(); DayOfWeek dayOfWeek; int dataCount = 0; float temp_c = 0; @@ -91,7 +92,7 @@ public class OpenWeatherMap implements WeatherDataAPI { return new WeatherData( new City(city), - Instant.now().plusSeconds(day * 24 * 3600), + Instant.now(clock).plusSeconds(day * 24 * 3600), temp_c, windSpeed, windDirection, @@ -104,7 +105,7 @@ public class OpenWeatherMap implements WeatherDataAPI { */ @Override public WeatherData getTemperature(int day, String city) throws IOException { - JSONObject result = fetchWeather(day+1, new City(city)); + JSONObject result = fetchWeather(new City(city)); return getWeatherDataFromForecast(result, day, city); } @@ -116,7 +117,7 @@ public class OpenWeatherMap implements WeatherDataAPI { @Override public ArrayList getTemperatures(int days, String city) throws IOException { - JSONObject result = fetchWeather(days, new City(city)); + JSONObject result = fetchWeather(new City(city)); ArrayList weatherDatas = new ArrayList<>(); @@ -133,4 +134,9 @@ public class OpenWeatherMap implements WeatherDataAPI { public String getAPIName() { return "OpenWeatherMap"; } + + @Override + public String toString() { + return this.getAPIName(); + } } diff --git a/src/test/java/eirb/pg203/WeatherAPITest.java b/src/test/java/eirb/pg203/WeatherAPITest.java index 0a29db9..907ab10 100644 --- a/src/test/java/eirb/pg203/WeatherAPITest.java +++ b/src/test/java/eirb/pg203/WeatherAPITest.java @@ -14,7 +14,6 @@ import java.util.stream.Stream; public class WeatherAPITest { private static final String APIKey = "realKey"; - private static final float epsilon = 0.01F; private WeatherAPI weatherAPI; @BeforeEach @@ -23,19 +22,6 @@ public class WeatherAPITest { this.weatherAPI.JSONFetcher = new FakeJSONFetcherWeatherAPI(); } - /** - * For coverage (hour not yet implemented) - * @throws IOException never - */ - @Test - public void testGetTemperatureByHour() throws IOException { - String city = "Bordeaux"; - Assertions.assertAll( - () -> weatherAPI.getTemperature(0,1, city) - ); - - } - @Test public void testGetAPIName() { Assertions.assertEquals("WeatherAPI", weatherAPI.getAPIName()); diff --git a/src/test/java/eirb/pg203/WeatherDataAPITest.java b/src/test/java/eirb/pg203/WeatherDataAPITest.java index 8826cc7..21df664 100644 --- a/src/test/java/eirb/pg203/WeatherDataAPITest.java +++ b/src/test/java/eirb/pg203/WeatherDataAPITest.java @@ -1,5 +1,6 @@ package eirb.pg203; +import eirb.pg203.fakeJSONFetcher.FakeJSONFetcherOpenWeatherMap; import eirb.pg203.fakeJSONFetcher.FakeJSONFetcherWeatherAPI; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -9,6 +10,9 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import java.io.IOException; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; import java.util.ArrayList; import java.util.stream.Stream; @@ -22,6 +26,18 @@ public class WeatherDataAPITest { return weatherAPI; } + private static OpenWeatherMap openWeatherMap(){ + // Fix clock for testing + String instantExpected = "2024-11-24T00:00:00.00Z"; + Clock clock = Clock.fixed(Instant.parse(instantExpected), ZoneId.systemDefault()); + + OpenWeatherMap openWeatherMap= new OpenWeatherMap(APIKey); + openWeatherMap.JSONFetcher = new FakeJSONFetcherOpenWeatherMap(); + openWeatherMap.clock = clock; + return openWeatherMap; + } + + /** * List of args for Temperature testing * @return Args for testing @@ -32,7 +48,11 @@ public class WeatherDataAPITest { Arguments.arguments(weatherAPI(), 0, 8.1F,WeatherData.Condition.PARTIAL, 17.45F, 142.08F), Arguments.arguments(weatherAPI(), 1, 13F, WeatherData.Condition.SUNNY, 23.03F, 142.58F), Arguments.arguments(weatherAPI(), 2, 12.7F, WeatherData.Condition.RAINY, 13.19F, 222.92F), - Arguments.arguments(weatherAPI(), 3, 8.1F,WeatherData.Condition.CLOUDY, 17.45F, 142.08F) + Arguments.arguments(weatherAPI(), 3, 8.1F,WeatherData.Condition.CLOUDY, 17.45F, 142.08F), + Arguments.arguments(openWeatherMap(), 0, 13.41F,WeatherData.Condition.PARTIAL, 5.74F, 142.13F), + Arguments.arguments(openWeatherMap(), 1, 13.29F,WeatherData.Condition.CLOUDY, 3.62F, 225.25F), + Arguments.arguments(openWeatherMap(), 2, 10.06F,WeatherData.Condition.RAINY, 2.22F, 191.75F), + Arguments.arguments(openWeatherMap(), 3, 9.88F,WeatherData.Condition.SUNNY, 2.00F, 160.00F) ); } @@ -44,12 +64,12 @@ public class WeatherDataAPITest { weatherData = weatherDataAPI.getTemperature(day, city); /* Temperatures */ - Assertions.assertEquals(expectedTemp, weatherData.getTemp()); + Assertions.assertEquals(expectedTemp, weatherData.getTemp(), epsilon); /* Condition */ Assertions.assertEquals(expectedCond, weatherData.getCondition()); /* Wind */ - Assertions.assertTrue(expectedWindSpeed - weatherData.getWindSpeed() < epsilon); - Assertions.assertTrue(expectedWindAngle - weatherData.getWindDirectionAngle() < epsilon); + Assertions.assertEquals(expectedWindSpeed, weatherData.getWindSpeed(), epsilon); + Assertions.assertEquals(expectedWindAngle, weatherData.getWindDirectionAngle(),epsilon); } private static Stream testGetTemperatures() { @@ -57,8 +77,15 @@ public class WeatherDataAPITest { WeatherData.Condition[] weatherAPIExpectedConditions = {WeatherData.Condition.PARTIAL, WeatherData.Condition.SUNNY, WeatherData.Condition.RAINY, WeatherData.Condition.CLOUDY}; float[] weatherAPIExpectedWindSpeed = {17.45F, 23.03F, 13.19F, 17.45F}; float[] weatherAPIExpectedWindDirection = {142.08F, 142.58F, 222.92F, 142.08F}; + + float[] openWeatherMapExpectedTemperatures = {13.41F, 13.29F, 10.06F, 9.88F}; + WeatherData.Condition[] openWeatherMapExpectedConditions = {WeatherData.Condition.PARTIAL, WeatherData.Condition.CLOUDY, WeatherData.Condition.RAINY, WeatherData.Condition.SUNNY}; + float[] openWeatherMapExpectedWindSpeed = {5.74F, 3.62F, 2.22F, 2.00F}; + float[] openWeatherMapExpectedWindDirection = {142.13F, 225.25F, 191.75F, 160F}; + return Stream.of( - Arguments.arguments(weatherAPI(), 4, weatherAPIExpectedTemperatures, weatherAPIExpectedConditions, weatherAPIExpectedWindSpeed, weatherAPIExpectedWindDirection) + Arguments.arguments(weatherAPI(), 4, weatherAPIExpectedTemperatures, weatherAPIExpectedConditions, weatherAPIExpectedWindSpeed, weatherAPIExpectedWindDirection), + Arguments.arguments(openWeatherMap(), 4, openWeatherMapExpectedTemperatures, openWeatherMapExpectedConditions, openWeatherMapExpectedWindSpeed, openWeatherMapExpectedWindDirection) ); } @@ -75,12 +102,29 @@ public class WeatherDataAPITest { weatherData = weatherDatas.get(index); /* Temperatures */ - Assertions.assertEquals(expectedTemperatures[index], weatherData.getTemp()); + Assertions.assertEquals(expectedTemperatures[index], weatherData.getTemp(), epsilon); /* Weather condition */ Assertions.assertEquals(expectedConditions[index], weatherData.getCondition()); /* Wind */ - Assertions.assertTrue(expectedWindSpeed[index] - weatherData.getWindSpeed() < epsilon); - Assertions.assertTrue(expectedWindDirection[index] - weatherData.getWindDirectionAngle() < epsilon); + Assertions.assertEquals(expectedWindSpeed[index],weatherData.getWindSpeed(), epsilon); + Assertions.assertEquals(expectedWindDirection[index], weatherData.getWindDirectionAngle(), epsilon); } } + + private static Stream testGetTemperatureByHours() { + + return Stream.of( + Arguments.arguments(weatherAPI()), + Arguments.arguments(openWeatherMap()) + ); + } + @ParameterizedTest(name = "[{0}] Get temperature for a specific hour") + @MethodSource + public void testGetTemperatureByHours(WeatherDataAPI weatherDataAPI) { + String city = "Bordeaux"; + Assertions.assertAll( + () -> weatherDataAPI.getTemperature(0,1, city) + ); + + } } diff --git a/src/test/java/eirb/pg203/fakeJSONFetcher/FakeJSONFetcherOpenWeatherMap.java b/src/test/java/eirb/pg203/fakeJSONFetcher/FakeJSONFetcherOpenWeatherMap.java new file mode 100644 index 0000000..5583f31 --- /dev/null +++ b/src/test/java/eirb/pg203/fakeJSONFetcher/FakeJSONFetcherOpenWeatherMap.java @@ -0,0 +1,33 @@ +package eirb.pg203.fakeJSONFetcher; + +import eirb.pg203.utils.FileResourcesUtils; +import eirb.pg203.utils.JSONFetcherInterface; +import eirb.pg203.utils.SplitQueryUrl; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.net.URL; +import java.time.Instant; +import java.util.Map; + +public class FakeJSONFetcherOpenWeatherMap implements JSONFetcherInterface { + private final String apiKey = "realKey"; + private final JSONObject wrongKeyResponse = FileResourcesUtils.getFileFromResourceAsJson("OpenWeatherMap/wrong-apikey.json"); + + private JSONObject responseExample() { + return FileResourcesUtils.getFileFromResourceAsJson("OpenWeatherMap/Bordeaux-partial-cloudy-rain-sunny.json"); + } + @Override + public JSONObject fetch(URL url) throws IOException { + Map params = SplitQueryUrl.splitQuery(url); + if (!params.getOrDefault("appid", "").contentEquals(apiKey)) + return wrongKeyResponse; + return responseExample(); + } + + @Override + public JSONArray fetchArray(URL url) throws IOException { + return null; + } +} diff --git a/src/test/resources/OpenWeatherMap/Bordeaux-partial-cloudy-rain-sunny.json b/src/test/resources/OpenWeatherMap/Bordeaux-partial-cloudy-rain-sunny.json new file mode 100644 index 0000000..21735d5 --- /dev/null +++ b/src/test/resources/OpenWeatherMap/Bordeaux-partial-cloudy-rain-sunny.json @@ -0,0 +1,1475 @@ +{ + "cod": "200", + "message": 0, + "cnt": 40, + "list": [ + { + "dt": 1732406400, + "main": { + "temp": 10.2, + "feels_like": 9.23, + "temp_min": 10.18, + "temp_max": 10.2, + "pressure": 1017, + "sea_level": 1017, + "grnd_level": 1012, + "humidity": 75, + "temp_kf": 0.02 + }, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03n" + } + ], + "clouds": { + "all": 33 + }, + "wind": { + "speed": 4.79, + "deg": 140, + "gust": 13.02 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-24 00:00:00" + }, + { + "dt": 1732417200, + "main": { + "temp": 10.26, + "feels_like": 9.22, + "temp_min": 10.26, + "temp_max": 10.29, + "pressure": 1016, + "sea_level": 1016, + "grnd_level": 1011, + "humidity": 72, + "temp_kf": -0.03 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 67 + }, + "wind": { + "speed": 5.15, + "deg": 135, + "gust": 13.89 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-24 03:00:00" + }, + { + "dt": 1732428000, + "main": { + "temp": 10.15, + "feels_like": 9.18, + "temp_min": 10.15, + "temp_max": 10.15, + "pressure": 1016, + "sea_level": 1016, + "grnd_level": 1011, + "humidity": 75, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 93 + }, + "wind": { + "speed": 5.71, + "deg": 138, + "gust": 14.58 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-24 06:00:00" + }, + { + "dt": 1732438800, + "main": { + "temp": 11.77, + "feels_like": 10.91, + "temp_min": 11.77, + "temp_max": 11.77, + "pressure": 1016, + "sea_level": 1016, + "grnd_level": 1011, + "humidity": 73, + "temp_kf": 0 + }, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02d" + } + ], + "clouds": { + "all": 13 + }, + "wind": { + "speed": 5.93, + "deg": 134, + "gust": 14.45 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-24 09:00:00" + }, + { + "dt": 1732449600, + "main": { + "temp": 16.48, + "feels_like": 15.72, + "temp_min": 16.48, + "temp_max": 16.48, + "pressure": 1013, + "sea_level": 1013, + "grnd_level": 1009, + "humidity": 59, + "temp_kf": 0 + }, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ], + "clouds": { + "all": 10 + }, + "wind": { + "speed": 6.38, + "deg": 140, + "gust": 13.55 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-24 12:00:00" + }, + { + "dt": 1732460400, + "main": { + "temp": 17.25, + "feels_like": 16.55, + "temp_min": 17.25, + "temp_max": 17.25, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1007, + "humidity": 58, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 65 + }, + "wind": { + "speed": 6.31, + "deg": 146, + "gust": 15.59 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-24 15:00:00" + }, + { + "dt": 1732471200, + "main": { + "temp": 15.26, + "feels_like": 14.59, + "temp_min": 15.26, + "temp_max": 15.26, + "pressure": 1012, + "sea_level": 1012, + "grnd_level": 1007, + "humidity": 67, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 84 + }, + "wind": { + "speed": 5.73, + "deg": 149, + "gust": 15.31 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-24 18:00:00" + }, + { + "dt": 1732482000, + "main": { + "temp": 15.9, + "feels_like": 15.14, + "temp_min": 15.9, + "temp_max": 15.9, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1006, + "humidity": 61, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 5.9, + "deg": 155, + "gust": 17.26 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-24 21:00:00" + }, + { + "dt": 1732492800, + "main": { + "temp": 16.01, + "feels_like": 15.13, + "temp_min": 16.01, + "temp_max": 16.01, + "pressure": 1009, + "sea_level": 1009, + "grnd_level": 1004, + "humidity": 56, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 6.95, + "deg": 150, + "gust": 18.68 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-25 00:00:00" + }, + { + "dt": 1732503600, + "main": { + "temp": 16.52, + "feels_like": 15.59, + "temp_min": 16.52, + "temp_max": 16.52, + "pressure": 1007, + "sea_level": 1007, + "grnd_level": 1002, + "humidity": 52, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 99 + }, + "wind": { + "speed": 5.13, + "deg": 161, + "gust": 15.28 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-25 03:00:00" + }, + { + "dt": 1732514400, + "main": { + "temp": 16.06, + "feels_like": 15.37, + "temp_min": 16.06, + "temp_max": 16.06, + "pressure": 1008, + "sea_level": 1008, + "grnd_level": 1003, + "humidity": 63, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.59, + "deg": 215, + "gust": 7.05 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-25 06:00:00" + }, + { + "dt": 1732525200, + "main": { + "temp": 13.58, + "feels_like": 13.4, + "temp_min": 13.58, + "temp_max": 13.58, + "pressure": 1011, + "sea_level": 1011, + "grnd_level": 1007, + "humidity": 92, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "light rain", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 3.32, + "deg": 296, + "gust": 8.35 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 1.97 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-25 09:00:00" + }, + { + "dt": 1732536000, + "main": { + "temp": 11.61, + "feels_like": 11.18, + "temp_min": 11.61, + "temp_max": 11.61, + "pressure": 1015, + "sea_level": 1015, + "grnd_level": 1010, + "humidity": 90, + "temp_kf": 0 + }, + "weather": [ + { + "id": 501, + "main": "Rain", + "description": "moderate rain", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.99, + "deg": 286, + "gust": 8.29 + }, + "visibility": 8895, + "pop": 1, + "rain": { + "3h": 5.34 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-25 12:00:00" + }, + { + "dt": 1732546800, + "main": { + "temp": 12.13, + "feels_like": 11.57, + "temp_min": 12.13, + "temp_max": 12.13, + "pressure": 1016, + "sea_level": 1016, + "grnd_level": 1012, + "humidity": 83, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "light rain", + "icon": "10d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 3.33, + "deg": 253, + "gust": 7.07 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 2.12 + }, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-25 15:00:00" + }, + { + "dt": 1732557600, + "main": { + "temp": 10.97, + "feels_like": 10.34, + "temp_min": 10.97, + "temp_max": 10.97, + "pressure": 1019, + "sea_level": 1019, + "grnd_level": 1014, + "humidity": 85, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "light rain", + "icon": "10n" + } + ], + "clouds": { + "all": 99 + }, + "wind": { + "speed": 2.57, + "deg": 224, + "gust": 6.92 + }, + "visibility": 10000, + "pop": 1, + "rain": { + "3h": 0.73 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-25 18:00:00" + }, + { + "dt": 1732568400, + "main": { + "temp": 9.43, + "feels_like": 8.47, + "temp_min": 9.43, + "temp_max": 9.43, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1017, + "humidity": 91, + "temp_kf": 0 + }, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "light rain", + "icon": "10n" + } + ], + "clouds": { + "all": 40 + }, + "wind": { + "speed": 2.07, + "deg": 217, + "gust": 3.77 + }, + "visibility": 10000, + "pop": 0.36, + "rain": { + "3h": 0.24 + }, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-25 21:00:00" + }, + { + "dt": 1732579200, + "main": { + "temp": 8.75, + "feels_like": 7.73, + "temp_min": 8.75, + "temp_max": 8.75, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1017, + "humidity": 91, + "temp_kf": 0 + }, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02n" + } + ], + "clouds": { + "all": 21 + }, + "wind": { + "speed": 2.01, + "deg": 206, + "gust": 3.19 + }, + "visibility": 10000, + "pop": 9000, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-26 00:00:00" + }, + { + "dt": 1732590000, + "main": { + "temp": 8.39, + "feels_like": 7.37, + "temp_min": 8.39, + "temp_max": 8.39, + "pressure": 1023, + "sea_level": 1023, + "grnd_level": 1018, + "humidity": 92, + "temp_kf": 0 + }, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03n" + } + ], + "clouds": { + "all": 31 + }, + "wind": { + "speed": 1.94, + "deg": 213, + "gust": 2.61 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-26 03:00:00" + }, + { + "dt": 1732600800, + "main": { + "temp": 8.51, + "feels_like": 7.16, + "temp_min": 8.51, + "temp_max": 8.51, + "pressure": 1023, + "sea_level": 1023, + "grnd_level": 1018, + "humidity": 93, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 61 + }, + "wind": { + "speed": 2.36, + "deg": 181, + "gust": 4.11 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-26 06:00:00" + }, + { + "dt": 1732611600, + "main": { + "temp": 10.55, + "feels_like": 9.96, + "temp_min": 10.55, + "temp_max": 10.55, + "pressure": 1024, + "sea_level": 1024, + "grnd_level": 1019, + "humidity": 88, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.54, + "deg": 202, + "gust": 6.63 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-26 09:00:00" + }, + { + "dt": 1732622400, + "main": { + "temp": 12.51, + "feels_like": 11.88, + "temp_min": 12.51, + "temp_max": 12.51, + "pressure": 1023, + "sea_level": 1023, + "grnd_level": 1018, + "humidity": 79, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.43, + "deg": 205, + "gust": 4.14 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-26 12:00:00" + }, + { + "dt": 1732633200, + "main": { + "temp": 12.24, + "feels_like": 11.63, + "temp_min": 12.24, + "temp_max": 12.24, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1018, + "humidity": 81, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 2.67, + "deg": 189, + "gust": 4.81 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-26 15:00:00" + }, + { + "dt": 1732644000, + "main": { + "temp": 10.6, + "feels_like": 9.88, + "temp_min": 10.6, + "temp_max": 10.6, + "pressure": 1023, + "sea_level": 1023, + "grnd_level": 1018, + "humidity": 83, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 100 + }, + "wind": { + "speed": 1.63, + "deg": 172, + "gust": 2.51 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-26 18:00:00" + }, + { + "dt": 1732654800, + "main": { + "temp": 8.95, + "feels_like": 7.85, + "temp_min": 8.95, + "temp_max": 8.95, + "pressure": 1023, + "sea_level": 1023, + "grnd_level": 1018, + "humidity": 85, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 72 + }, + "wind": { + "speed": 2.14, + "deg": 166, + "gust": 3.57 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-26 21:00:00" + }, + { + "dt": 1732665600, + "main": { + "temp": 8.1, + "feels_like": 6.71, + "temp_min": 8.1, + "temp_max": 8.1, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1017, + "humidity": 89, + "temp_kf": 0 + }, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03n" + } + ], + "clouds": { + "all": 0 + }, + "wind": { + "speed": 2.32, + "deg": 151, + "gust": 4.57 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-27 00:00:00" + }, + { + "dt": 1732676400, + "main": { + "temp": 7.55, + "feels_like": 5.92, + "temp_min": 7.55, + "temp_max": 7.55, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 88, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 0 + }, + "wind": { + "speed": 2.5, + "deg": 154, + "gust": 5.91 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-27 03:00:00" + }, + { + "dt": 1732687200, + "main": { + "temp": 7.47, + "feels_like": 5.8, + "temp_min": 7.47, + "temp_max": 7.47, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 84, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 0 + }, + "wind": { + "speed": 2.54, + "deg": 159, + "gust": 5.65 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-27 06:00:00" + }, + { + "dt": 1732698000, + "main": { + "temp": 9.35, + "feels_like": 8.38, + "temp_min": 9.35, + "temp_max": 9.35, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1017, + "humidity": 74, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 0 + }, + "wind": { + "speed": 2.07, + "deg": 161, + "gust": 4.74 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-27 09:00:00" + }, + { + "dt": 1732708800, + "main": { + "temp": 11.8, + "feels_like": 10.73, + "temp_min": 11.8, + "temp_max": 11.8, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 65, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 0 + }, + "wind": { + "speed": 1.46, + "deg": 173, + "gust": 3.12 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-27 12:00:00" + }, + { + "dt": 1732719600, + "main": { + "temp": 14.28, + "feels_like": 13.23, + "temp_min": 14.28, + "temp_max": 14.28, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 56, + "temp_kf": 0 + }, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ], + "clouds": { + "all": 0 + }, + "wind": { + "speed": 1.34, + "deg": 158, + "gust": 1.71 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-27 15:00:00" + }, + { + "dt": 1732730400, + "main": { + "temp": 10.81, + "feels_like": 9.7, + "temp_min": 10.81, + "temp_max": 10.81, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 67, + "temp_kf": 0 + }, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03n" + } + ], + "clouds": { + "all": 0 + }, + "wind": { + "speed": 1.81, + "deg": 164, + "gust": 1.94 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-27 18:00:00" + }, + { + "dt": 1732741200, + "main": { + "temp": 9.66, + "feels_like": 8.85, + "temp_min": 9.66, + "temp_max": 9.66, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1017, + "humidity": 72, + "temp_kf": 0 + }, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03n" + } + ], + "clouds": { + "all": 48 + }, + "wind": { + "speed": 1.93, + "deg": 160, + "gust": 2.05 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-27 21:00:00" + }, + { + "dt": 1732752000, + "main": { + "temp": 9.16, + "feels_like": 8.53, + "temp_min": 9.16, + "temp_max": 9.16, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 74, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 57 + }, + "wind": { + "speed": 1.66, + "deg": 167, + "gust": 1.66 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-28 00:00:00" + }, + { + "dt": 1732762800, + "main": { + "temp": 9.04, + "feels_like": 8.02, + "temp_min": 9.04, + "temp_max": 9.04, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 73, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 82 + }, + "wind": { + "speed": 2.06, + "deg": 172, + "gust": 2.47 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-28 03:00:00" + }, + { + "dt": 1732773600, + "main": { + "temp": 8.56, + "feels_like": 7.61, + "temp_min": 8.56, + "temp_max": 8.56, + "pressure": 1021, + "sea_level": 1021, + "grnd_level": 1016, + "humidity": 74, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 86 + }, + "wind": { + "speed": 1.89, + "deg": 193, + "gust": 1.99 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-28 06:00:00" + }, + { + "dt": 1732784400, + "main": { + "temp": 10.51, + "feels_like": 9.52, + "temp_min": 10.51, + "temp_max": 10.51, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1017, + "humidity": 73, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 93 + }, + "wind": { + "speed": 1.5, + "deg": 203, + "gust": 2.77 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-28 09:00:00" + }, + { + "dt": 1732795200, + "main": { + "temp": 13.48, + "feels_like": 12.79, + "temp_min": 13.48, + "temp_max": 13.48, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1017, + "humidity": 73, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 91 + }, + "wind": { + "speed": 2.13, + "deg": 223, + "gust": 3.44 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-28 12:00:00" + }, + { + "dt": 1732806000, + "main": { + "temp": 15.76, + "feels_like": 15.27, + "temp_min": 15.76, + "temp_max": 15.76, + "pressure": 1022, + "sea_level": 1022, + "grnd_level": 1017, + "humidity": 72, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04d" + } + ], + "clouds": { + "all": 64 + }, + "wind": { + "speed": 1.82, + "deg": 262, + "gust": 3.62 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "d" + }, + "dt_txt": "2024-11-28 15:00:00" + }, + { + "dt": 1732816800, + "main": { + "temp": 12.48, + "feels_like": 12.16, + "temp_min": 12.48, + "temp_max": 12.48, + "pressure": 1023, + "sea_level": 1023, + "grnd_level": 1018, + "humidity": 91, + "temp_kf": 0 + }, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 63 + }, + "wind": { + "speed": 1.09, + "deg": 273, + "gust": 0.73 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-28 18:00:00" + }, + { + "dt": 1732827600, + "main": { + "temp": 12.51, + "feels_like": 12.04, + "temp_min": 12.51, + "temp_max": 12.51, + "pressure": 1024, + "sea_level": 1024, + "grnd_level": 1019, + "humidity": 85, + "temp_kf": 0 + }, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04n" + } + ], + "clouds": { + "all": 89 + }, + "wind": { + "speed": 2.32, + "deg": 96, + "gust": 4.52 + }, + "visibility": 10000, + "pop": 0, + "sys": { + "pod": "n" + }, + "dt_txt": "2024-11-28 21:00:00" + } + ], + "city": { + "id": 3031582, + "name": "Bordeaux", + "coord": { + "lat": 44.85, + "lon": -0.59 + }, + "country": "FR", + "population": 231844, + "timezone": 3600, + "sunrise": 1732345841, + "sunset": 1732379244 + } +} \ No newline at end of file diff --git a/src/test/resources/OpenWeatherMap/wrong-apikey.json b/src/test/resources/OpenWeatherMap/wrong-apikey.json new file mode 100644 index 0000000..0ba9c1e --- /dev/null +++ b/src/test/resources/OpenWeatherMap/wrong-apikey.json @@ -0,0 +1,4 @@ +{ + "cod": 401, + "message": "Invalid API key. Please see https://openweathermap.org/faq#error401 for more info." +} \ No newline at end of file