From e4917c3b4a41a178c5176b75d786dfd383c807ee Mon Sep 17 00:00:00 2001 From: lolodomo Date: Thu, 22 Sep 2022 00:28:28 +0200 Subject: [PATCH] [ecowatt] Unit tests for methods getting channel state from API response (#13419) Signed-off-by: Laurent Garnier --- .../internal/handler/EcowattHandler.java | 20 +- .../internal/restapi/EcowattRestApi.java | 2 + .../internal/EcowattApiResponseTest.java | 175 ++++++++++++++++++ .../src/test/resources/ApiResponse.json | 4 + 4 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java create mode 100644 bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json diff --git a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java index d6530b9b3..fdfad37ed 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java +++ b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java @@ -220,14 +220,28 @@ public class EcowattHandler extends BaseThingHandler { return retryDelay; } - private State getDaySignalState(@Nullable EcowattApiResponse response, ZonedDateTime dateTime) { + /** + * Get the signal applicable for a given day from the API response + * + * @param response the API response + * @param dateTime the date and time to consider + * @return the found valid signal as a channel state or UndefType.UNDEF if not found + */ + public static State getDaySignalState(@Nullable EcowattApiResponse response, ZonedDateTime dateTime) { EcowattDaySignals signals = response == null ? null : response.getDaySignals(dateTime); return signals != null && signals.getDaySignal() >= 1 && signals.getDaySignal() <= 3 ? new DecimalType(signals.getDaySignal()) : UnDefType.UNDEF; } - private State getHourSignalState(@Nullable EcowattApiResponse response, ZonedDateTime dateTime) { + /** + * Get the signal applicable for a given day and hour from the API response + * + * @param response the API response + * @param dateTime the date and time to consider + * @return the found valid signal as a channel state or UndefType.UNDEF if not found + */ + public static State getHourSignalState(@Nullable EcowattApiResponse response, ZonedDateTime dateTime) { EcowattDaySignals signals = response == null ? null : response.getDaySignals(dateTime); ZonedDateTime day = signals == null ? null : signals.getDay(); if (signals != null && day != null) { @@ -235,7 +249,7 @@ public class EcowattHandler extends BaseThingHandler { // hour index in these data int hour = dateTime.withZoneSameInstant(day.getZone()).getHour(); int value = signals.getHourSignal(hour); - logger.debug("hour {} value {}", hour, value); + LoggerFactory.getLogger(EcowattHandler.class).debug("hour {} value {}", hour, value); if (value >= 1 && value <= 3) { return new DecimalType(value); } diff --git a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java index 084274ae7..7497d5381 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java +++ b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java @@ -94,6 +94,8 @@ public class EcowattRestApi { int statusCode = response.getStatus(); + logger.trace("API response statusCode={} content={}", statusCode, response.getContentAsString()); + if (statusCode == HttpStatus.TOO_MANY_REQUESTS_429) { int retryAfter = -1; if (response.getHeaders().contains(HttpHeader.RETRY_AFTER)) { diff --git a/bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java b/bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java new file mode 100644 index 000000000..5884137f8 --- /dev/null +++ b/bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java @@ -0,0 +1,175 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.ecowatt.internal; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openhab.binding.ecowatt.internal.handler.EcowattHandler; +import org.openhab.binding.ecowatt.internal.restapi.EcowattApiResponse; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializer; + +/** + * Tests of methods getting channel state from API response + * + * @author Laurent Garnier - Initial contribution + */ +@NonNullByDefault +public class EcowattApiResponseTest { + + private static final DecimalType STATE_ONE = new DecimalType(1); + private static final DecimalType STATE_TWO = new DecimalType(2); + private static final DecimalType STATE_THREE = new DecimalType(3); + + private final Gson gson = new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, + (JsonDeserializer) (json, type, jsonDeserializationContext) -> OffsetDateTime + .parse(json.getAsJsonPrimitive().getAsString()).toZonedDateTime()) + .create(); + private static @Nullable EcowattApiResponse apiResponse; + + @BeforeEach + public void loadApiResponse() throws IOException { + InputStream resourceStream = getClass().getResourceAsStream("/ApiResponse.json"); + assertNotNull(resourceStream); + final String response = new String(resourceStream.readAllBytes(), StandardCharsets.UTF_8); + apiResponse = gson.fromJson(response, EcowattApiResponse.class); + assertNotNull(apiResponse); + } + + @Test + public void getDaySignalStateWithNullResponse() { + assertEquals(UnDefType.UNDEF, + EcowattHandler.getDaySignalState(null, ZonedDateTime.parse("2022-09-19T21:30:00+02:00"))); + } + + @Test + public void getDaySignalStateWithSameOffset() { + ZonedDateTime dateTime = ZonedDateTime.parse("2022-09-19T21:30:00+02:00"); + assertEquals(UnDefType.UNDEF, EcowattHandler.getDaySignalState(apiResponse, dateTime.minusDays(1))); + assertEquals(STATE_THREE, EcowattHandler.getDaySignalState(apiResponse, dateTime)); + assertEquals(STATE_TWO, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(1))); + assertEquals(STATE_ONE, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(2))); + assertEquals(STATE_ONE, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(3))); + assertEquals(UnDefType.UNDEF, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(4))); + } + + @Test + public void getDaySignalStateWithOtherOffset() { + ZonedDateTime dateTime = ZonedDateTime.parse("2022-09-20T00:30:00+05:00"); + assertEquals(UnDefType.UNDEF, EcowattHandler.getDaySignalState(apiResponse, dateTime.minusDays(1))); + assertEquals(STATE_THREE, EcowattHandler.getDaySignalState(apiResponse, dateTime)); + assertEquals(STATE_TWO, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(1))); + assertEquals(STATE_ONE, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(2))); + assertEquals(STATE_ONE, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(3))); + assertEquals(UnDefType.UNDEF, EcowattHandler.getDaySignalState(apiResponse, dateTime.plusDays(4))); + } + + @Test + public void getHourSignalStateWithNullResponse() { + assertEquals(UnDefType.UNDEF, + EcowattHandler.getHourSignalState(null, ZonedDateTime.parse("2022-09-19T00:30:00+02:00"))); + } + + @Test + public void getHourSignalStateWithSameOffset() { + ZonedDateTime dateTime = ZonedDateTime.parse("2022-09-19T00:30:00+02:00"); + + assertEquals(UnDefType.UNDEF, EcowattHandler.getHourSignalState(apiResponse, dateTime.minusHours(1))); + + State expectedState; + for (int h = 0; h < 24; h++) { + switch (h) { + case 7: + case 11: + case 19: + case 21: + expectedState = STATE_TWO; + break; + case 8: + case 9: + case 10: + case 20: + expectedState = STATE_THREE; + break; + default: + expectedState = STATE_ONE; + } + assertEquals(expectedState, EcowattHandler.getHourSignalState(apiResponse, dateTime.plusHours(h))); + } + + dateTime = dateTime.plusDays(1); + for (int h = 0; h < 24; h++) { + expectedState = h == 20 ? STATE_TWO : STATE_ONE; + assertEquals(expectedState, EcowattHandler.getHourSignalState(apiResponse, dateTime.plusHours(h))); + } + + dateTime = dateTime.plusDays(1); + for (int h = 0; h < 24; h++) { + expectedState = STATE_ONE; + assertEquals(expectedState, EcowattHandler.getHourSignalState(apiResponse, dateTime.plusHours(h))); + } + + dateTime = dateTime.plusDays(1); + for (int h = 0; h < 24; h++) { + expectedState = h == 23 ? UnDefType.UNDEF : STATE_ONE; + assertEquals(expectedState, EcowattHandler.getHourSignalState(apiResponse, dateTime.plusHours(h))); + } + + dateTime = dateTime.plusDays(1); + assertEquals(UnDefType.UNDEF, EcowattHandler.getHourSignalState(apiResponse, dateTime)); + } + + @Test + public void getHourSignalStateWithOtherOffset() { + ZonedDateTime dateTime = ZonedDateTime.parse("2022-09-19T00:30:00+05:00"); + State expectedState; + for (int h = 0; h < 24; h++) { + switch (h) { + case 0: + case 1: + case 2: + expectedState = UnDefType.UNDEF; + break; + case 10: + case 14: + case 22: + expectedState = STATE_TWO; + break; + case 11: + case 12: + case 13: + case 23: + expectedState = STATE_THREE; + break; + default: + expectedState = STATE_ONE; + } + assertEquals(expectedState, EcowattHandler.getHourSignalState(apiResponse, dateTime.plusHours(h))); + } + } +} diff --git a/bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json b/bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json new file mode 100644 index 000000000..c5ac41b74 --- /dev/null +++ b/bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json @@ -0,0 +1,4 @@ +{"signals":[{"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-22T00:00:00+02:00","dvalue":1,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":1},{"pas":8,"hvalue":1},{"pas":9,"hvalue":1},{"pas":10,"hvalue":1},{"pas":11,"hvalue":1},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":1},{"pas":20,"hvalue":1},{"pas":21,"hvalue":1},{"pas":22,"hvalue":1}]}, +{"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-20T00:00:00+02:00","dvalue":2,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":1},{"pas":8,"hvalue":1},{"pas":9,"hvalue":1},{"pas":10,"hvalue":1},{"pas":11,"hvalue":1},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":1},{"pas":20,"hvalue":2},{"pas":21,"hvalue":1},{"pas":22,"hvalue":1},{"pas":23,"hvalue":1}]}, +{"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-21T00:00:00+02:00","dvalue":1,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":1},{"pas":8,"hvalue":1},{"pas":9,"hvalue":1},{"pas":10,"hvalue":1},{"pas":11,"hvalue":1},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":1},{"pas":20,"hvalue":1},{"pas":21,"hvalue":1},{"pas":22,"hvalue":1},{"pas":23,"hvalue":1}]}, +{"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-19T00:00:00+02:00","dvalue":3,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":2},{"pas":8,"hvalue":3},{"pas":9,"hvalue":3},{"pas":10,"hvalue":3},{"pas":11,"hvalue":2},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":2},{"pas":20,"hvalue":3},{"pas":21,"hvalue":2},{"pas":22,"hvalue":1},{"pas":23,"hvalue":1}]}]}