]> git.basschouten.com Git - openhab-addons.git/blob
b90d3f1ed0f5df4f9ec0108264772607335e9e77
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.awattar.internal.handler;
14
15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.Matchers.*;
17 import static org.mockito.ArgumentMatchers.*;
18 import static org.mockito.Mockito.*;
19 import static org.openhab.binding.awattar.internal.AwattarBindingConstants.*;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.nio.charset.StandardCharsets;
24 import java.time.ZoneId;
25 import java.util.Map;
26 import java.util.Objects;
27 import java.util.SortedSet;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.TimeUnit;
30 import java.util.concurrent.TimeoutException;
31 import java.util.stream.Stream;
32
33 import org.eclipse.jdt.annotation.NonNullByDefault;
34 import org.eclipse.jetty.client.HttpClient;
35 import org.eclipse.jetty.client.api.ContentResponse;
36 import org.eclipse.jetty.client.api.Request;
37 import org.eclipse.jetty.http.HttpMethod;
38 import org.eclipse.jetty.http.HttpStatus;
39 import org.junit.jupiter.api.BeforeEach;
40 import org.junit.jupiter.api.Test;
41 import org.junit.jupiter.api.extension.ExtendWith;
42 import org.junit.jupiter.params.ParameterizedTest;
43 import org.junit.jupiter.params.provider.Arguments;
44 import org.junit.jupiter.params.provider.MethodSource;
45 import org.mockito.Mock;
46 import org.mockito.junit.jupiter.MockitoExtension;
47 import org.mockito.junit.jupiter.MockitoSettings;
48 import org.mockito.quality.Strictness;
49 import org.openhab.binding.awattar.internal.AwattarBindingConstants;
50 import org.openhab.binding.awattar.internal.AwattarPrice;
51 import org.openhab.core.config.core.Configuration;
52 import org.openhab.core.i18n.TimeZoneProvider;
53 import org.openhab.core.library.types.DateTimeType;
54 import org.openhab.core.library.types.StringType;
55 import org.openhab.core.test.java.JavaTest;
56 import org.openhab.core.thing.Bridge;
57 import org.openhab.core.thing.ChannelUID;
58 import org.openhab.core.thing.Thing;
59 import org.openhab.core.thing.ThingUID;
60 import org.openhab.core.thing.binding.ThingHandlerCallback;
61 import org.openhab.core.types.State;
62
63 /**
64  * The {@link AwattarBridgeHandlerTest} contains tests for the {@link AwattarBridgeHandler}
65  *
66  * @author Jan N. Klug - Initial contribution
67  */
68 @ExtendWith(MockitoExtension.class)
69 @MockitoSettings(strictness = Strictness.LENIENT)
70 @NonNullByDefault
71 public class AwattarBridgeHandlerTest extends JavaTest {
72     public static final ThingUID BRIDGE_UID = new ThingUID(AwattarBindingConstants.THING_TYPE_BRIDGE, "testBridge");
73
74     // bridge mocks
75     private @Mock @NonNullByDefault({}) Bridge bridgeMock;
76     private @Mock @NonNullByDefault({}) ThingHandlerCallback bridgeCallbackMock;
77     private @Mock @NonNullByDefault({}) HttpClient httpClientMock;
78     private @Mock @NonNullByDefault({}) TimeZoneProvider timeZoneProviderMock;
79     private @Mock @NonNullByDefault({}) Request requestMock;
80     private @Mock @NonNullByDefault({}) ContentResponse contentResponseMock;
81
82     // best price handler mocks
83     private @Mock @NonNullByDefault({}) Thing bestpriceMock;
84     private @Mock @NonNullByDefault({}) ThingHandlerCallback bestPriceCallbackMock;
85
86     private @NonNullByDefault({}) AwattarBridgeHandler bridgeHandler;
87
88     @BeforeEach
89     public void setUp() throws IOException, ExecutionException, InterruptedException, TimeoutException {
90         try (InputStream inputStream = AwattarBridgeHandlerTest.class.getResourceAsStream("api_response.json")) {
91             if (inputStream == null) {
92                 throw new IOException("inputstream is null");
93             }
94             byte[] bytes = inputStream.readAllBytes();
95             if (bytes == null) {
96                 throw new IOException("Resulting byte-array empty");
97             }
98             when(contentResponseMock.getContentAsString()).thenReturn(new String(bytes, StandardCharsets.UTF_8));
99         }
100         when(contentResponseMock.getStatus()).thenReturn(HttpStatus.OK_200);
101         when(httpClientMock.newRequest(anyString())).thenReturn(requestMock);
102         when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
103         when(requestMock.timeout(10, TimeUnit.SECONDS)).thenReturn(requestMock);
104         when(requestMock.send()).thenReturn(contentResponseMock);
105
106         when(timeZoneProviderMock.getTimeZone()).thenReturn(ZoneId.of("GMT+2"));
107
108         when(bridgeMock.getUID()).thenReturn(BRIDGE_UID);
109         bridgeHandler = new AwattarBridgeHandler(bridgeMock, httpClientMock, timeZoneProviderMock);
110         bridgeHandler.setCallback(bridgeCallbackMock);
111         bridgeHandler.refreshIfNeeded();
112         when(bridgeMock.getHandler()).thenReturn(bridgeHandler);
113
114         // other mocks
115         when(bestpriceMock.getBridgeUID()).thenReturn(BRIDGE_UID);
116
117         when(bestPriceCallbackMock.getBridge(any())).thenReturn(bridgeMock);
118         when(bestPriceCallbackMock.isChannelLinked(any())).thenReturn(true);
119     }
120
121     @Test
122     public void testPricesRetrieval() {
123         SortedSet<AwattarPrice> prices = bridgeHandler.getPrices();
124
125         assertThat(prices, hasSize(72));
126
127         Objects.requireNonNull(prices);
128
129         // check if first and last element are correct
130         assertThat(prices.first().timerange().start(), is(1718316000000L));
131         assertThat(prices.last().timerange().end(), is(1718575200000L));
132     }
133
134     @Test
135     public void testGetPriceForSuccess() {
136         AwattarPrice price = bridgeHandler.getPriceFor(1718503200000L);
137
138         assertThat(price, is(notNullValue()));
139         Objects.requireNonNull(price);
140         assertThat(price.netPrice(), is(closeTo(0.219, 0.001)));
141     }
142
143     @Test
144     public void testGetPriceForFail() {
145         AwattarPrice price = bridgeHandler.getPriceFor(1518503200000L);
146
147         assertThat(price, is(nullValue()));
148     }
149
150     @Test
151     public void testContainsPrizeFor() {
152         assertThat(bridgeHandler.containsPriceFor(1618503200000L), is(false));
153         assertThat(bridgeHandler.containsPriceFor(1718503200000L), is(true));
154         assertThat(bridgeHandler.containsPriceFor(1818503200000L), is(false));
155     }
156
157     public static Stream<Arguments> testBestpriceHandler() {
158         return Stream.of( //
159                 Arguments.of(1, true, CHANNEL_START, new DateTimeType("2024-06-15T14:00:00.000+0200")),
160                 Arguments.of(1, true, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
161                 Arguments.of(1, true, CHANNEL_HOURS, new StringType("14")),
162                 Arguments.of(1, false, CHANNEL_START, new DateTimeType("2024-06-15T14:00:00.000+0200")),
163                 Arguments.of(1, false, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
164                 Arguments.of(1, false, CHANNEL_HOURS, new StringType("14")),
165                 Arguments.of(2, true, CHANNEL_START, new DateTimeType("2024-06-15T13:00:00.000+0200")),
166                 Arguments.of(2, true, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
167                 Arguments.of(2, true, CHANNEL_HOURS, new StringType("13,14")),
168                 Arguments.of(2, false, CHANNEL_START, new DateTimeType("2024-06-15T13:00:00.000+0200")),
169                 Arguments.of(2, false, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
170                 Arguments.of(2, false, CHANNEL_HOURS, new StringType("13,14")));
171     }
172
173     @ParameterizedTest
174     @MethodSource
175     public void testBestpriceHandler(int length, boolean consecutive, String channelId, State expectedState) {
176         ThingUID bestPriceUid = new ThingUID(AwattarBindingConstants.THING_TYPE_BESTPRICE, "foo");
177         Map<String, Object> config = Map.of("length", length, "consecutive", consecutive);
178         when(bestpriceMock.getConfiguration()).thenReturn(new Configuration(config));
179
180         AwattarBestPriceHandler handler = new AwattarBestPriceHandler(bestpriceMock, timeZoneProviderMock) {
181             @Override
182             protected TimeRange getRange(int start, int duration, ZoneId zoneId) {
183                 return new TimeRange(1718402400000L, 1718488800000L);
184             }
185         };
186
187         handler.setCallback(bestPriceCallbackMock);
188
189         ChannelUID channelUID = new ChannelUID(bestPriceUid, channelId);
190         handler.refreshChannel(channelUID);
191         verify(bestPriceCallbackMock).stateUpdated(channelUID, expectedState);
192     }
193 }