]> git.basschouten.com Git - openhab-addons.git/blob
83847ae0da14f688ea811e6540fd5260b3f2c02b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.innogysmarthome.internal.handler;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.Mockito.*;
17
18 import java.net.ConnectException;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.concurrent.ScheduledExecutorService;
22 import java.util.concurrent.ScheduledFuture;
23
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.eclipse.jetty.client.HttpClient;
26 import org.junit.jupiter.api.BeforeEach;
27 import org.junit.jupiter.api.Test;
28 import org.openhab.binding.innogysmarthome.internal.InnogyBindingConstants;
29 import org.openhab.binding.innogysmarthome.internal.InnogyWebSocket;
30 import org.openhab.binding.innogysmarthome.internal.client.InnogyClient;
31 import org.openhab.binding.innogysmarthome.internal.client.entity.device.Device;
32 import org.openhab.binding.innogysmarthome.internal.client.entity.device.DeviceConfig;
33 import org.openhab.binding.innogysmarthome.internal.manager.FullDeviceManager;
34 import org.openhab.core.auth.client.oauth2.OAuthClientService;
35 import org.openhab.core.auth.client.oauth2.OAuthFactory;
36 import org.openhab.core.config.core.Configuration;
37 import org.openhab.core.thing.Bridge;
38 import org.openhab.core.thing.ThingUID;
39 import org.openhab.core.thing.binding.BaseThingHandler;
40 import org.slf4j.LoggerFactory;
41
42 import ch.qos.logback.classic.Level;
43 import ch.qos.logback.classic.Logger;
44
45 /**
46  * @author Sven Strohschein - Initial contribution
47  */
48 public class InnogyBridgeHandlerTest {
49
50     private static final int MAXIMUM_RETRY_EXECUTIONS = 10;
51
52     private InnogyBridgeHandlerAccessible bridgeHandler;
53     private Bridge bridgeMock;
54     private InnogyWebSocket webSocketMock;
55
56     @BeforeEach
57     public void before() throws Exception {
58         final Logger loggerBridge = (Logger) LoggerFactory.getLogger(InnogyBridgeHandler.class);
59         loggerBridge.setLevel(Level.OFF);
60
61         final Logger logerBaseHandler = (Logger) LoggerFactory.getLogger(BaseThingHandler.class);
62         logerBaseHandler.setLevel(Level.OFF);
63
64         bridgeMock = mock(Bridge.class);
65         when(bridgeMock.getUID()).thenReturn(new ThingUID("innogysmarthome", "bridge"));
66
67         webSocketMock = mock(InnogyWebSocket.class);
68
69         OAuthClientService oAuthService = mock(OAuthClientService.class);
70
71         OAuthFactory oAuthFactoryMock = mock(OAuthFactory.class);
72         when(oAuthFactoryMock.createOAuthClientService(any(), any(), any(), any(), any(), any(), any()))
73                 .thenReturn(oAuthService);
74
75         HttpClient httpClientMock = mock(HttpClient.class);
76
77         bridgeHandler = new InnogyBridgeHandlerAccessible(bridgeMock, oAuthFactoryMock, httpClientMock);
78     }
79
80     @Test
81     public void testInitializeBridgeNotAvailable() throws Exception {
82         Configuration bridgeConfig = new Configuration();
83         HashMap<String, Object> map = new HashMap<>();
84         map.put("brand", "XY");
85         bridgeConfig.setProperties(map);
86
87         when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
88
89         bridgeHandler.initialize();
90
91         verify(webSocketMock, never()).start();
92         assertEquals(0, bridgeHandler.getDirectExecutionCount());
93     }
94
95     @Test
96     public void testInitialize() throws Exception {
97         Configuration bridgeConfig = new Configuration();
98
99         when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
100
101         bridgeHandler.initialize();
102
103         verify(webSocketMock).start();
104         assertEquals(1, bridgeHandler.getDirectExecutionCount());
105     }
106
107     @Test
108     public void testInitializeErrorOnStartingWebSocket() throws Exception {
109         Configuration bridgeConfig = new Configuration();
110
111         when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
112
113         doThrow(new RuntimeException("Test-Exception")).when(webSocketMock).start();
114
115         bridgeHandler.initialize();
116
117         verify(webSocketMock, times(MAXIMUM_RETRY_EXECUTIONS)).start();
118         assertEquals(1, bridgeHandler.getDirectExecutionCount()); // only the first execution should be without a delay
119     }
120
121     @Test
122     public void testConnectionClosed() throws Exception {
123         Configuration bridgeConfig = new Configuration();
124
125         when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
126
127         bridgeHandler.initialize();
128
129         verify(webSocketMock).start();
130         assertEquals(1, bridgeHandler.getDirectExecutionCount());
131
132         bridgeHandler.connectionClosed();
133
134         verify(webSocketMock, times(2)).start(); // automatically restarted (with a delay)
135         assertEquals(1, bridgeHandler.getDirectExecutionCount());
136
137         bridgeHandler.connectionClosed();
138
139         verify(webSocketMock, times(3)).start(); // automatically restarted (with a delay)
140         assertEquals(1, bridgeHandler.getDirectExecutionCount());
141     }
142
143     @Test
144     public void testConnectionClosedReconnectNotPossible() throws Exception {
145         Configuration bridgeConfig = new Configuration();
146
147         when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
148
149         bridgeHandler.initialize();
150
151         verify(webSocketMock).start();
152         assertEquals(1, bridgeHandler.getDirectExecutionCount());
153
154         doThrow(new ConnectException("Connection refused")).when(webSocketMock).start();
155
156         bridgeHandler.connectionClosed();
157
158         verify(webSocketMock, times(10)).start(); // automatic reconnect attempts (with a delay)
159         assertEquals(1, bridgeHandler.getDirectExecutionCount());
160     }
161
162     @Test
163     public void testOnEventDisconnect() throws Exception {
164         final String disconnectEventJSON = "{ type: \"Disconnect\" }";
165
166         Configuration bridgeConfig = new Configuration();
167
168         when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
169
170         bridgeHandler.initialize();
171
172         verify(webSocketMock).start();
173         assertEquals(1, bridgeHandler.getDirectExecutionCount());
174
175         bridgeHandler.onEvent(disconnectEventJSON);
176
177         verify(webSocketMock, times(2)).start(); // automatically restarted (with a delay)
178         assertEquals(1, bridgeHandler.getDirectExecutionCount());
179
180         bridgeHandler.onEvent(disconnectEventJSON);
181
182         verify(webSocketMock, times(3)).start(); // automatically restarted (with a delay)
183         assertEquals(1, bridgeHandler.getDirectExecutionCount());
184     }
185
186     private class InnogyBridgeHandlerAccessible extends InnogyBridgeHandler {
187
188         private final InnogyClient innogyClientMock;
189         private final FullDeviceManager fullDeviceManagerMock;
190         private final ScheduledExecutorService schedulerMock;
191         private int executionCount;
192         private int directExecutionCount;
193
194         private InnogyBridgeHandlerAccessible(Bridge bridge, OAuthFactory oAuthFactory, HttpClient httpClient)
195                 throws Exception {
196             super(bridge, oAuthFactory, httpClient);
197
198             Device bridgeDevice = new Device();
199             bridgeDevice.setId("bridgeId");
200             bridgeDevice.setType(InnogyBindingConstants.DEVICE_SHC);
201             bridgeDevice.setConfig(new DeviceConfig());
202
203             innogyClientMock = mock(InnogyClient.class);
204             fullDeviceManagerMock = mock(FullDeviceManager.class);
205             when(fullDeviceManagerMock.getFullDevices()).thenReturn(Collections.singletonList(bridgeDevice));
206
207             schedulerMock = mock(ScheduledExecutorService.class);
208
209             doAnswer(invocationOnMock -> {
210                 if (executionCount <= MAXIMUM_RETRY_EXECUTIONS) {
211                     executionCount++;
212                     invocationOnMock.getArgument(0, Runnable.class).run();
213                 }
214                 return null;
215             }).when(schedulerMock).execute(any());
216
217             doAnswer(invocationOnMock -> {
218                 if (executionCount <= MAXIMUM_RETRY_EXECUTIONS) {
219                     executionCount++;
220                     long seconds = invocationOnMock.getArgument(1);
221                     if (seconds <= 0) {
222                         directExecutionCount++;
223                     }
224
225                     invocationOnMock.getArgument(0, Runnable.class).run();
226                 }
227                 return mock(ScheduledFuture.class);
228             }).when(schedulerMock).schedule(any(Runnable.class), anyLong(), any());
229         }
230
231         public int getDirectExecutionCount() {
232             return directExecutionCount;
233         }
234
235         @Override
236         @NonNull
237         FullDeviceManager createFullDeviceManager(@NonNull InnogyClient client) {
238             return fullDeviceManagerMock;
239         }
240
241         @Override
242         @NonNull
243         InnogyClient createInnogyClient(@NonNull OAuthClientService oAuthService, @NonNull HttpClient httpClient) {
244             return innogyClientMock;
245         }
246
247         @Override
248         @NonNull
249         InnogyWebSocket createWebSocket() {
250             return webSocketMock;
251         }
252
253         @Override
254         @NonNull
255         ScheduledExecutorService getScheduler() {
256             return schedulerMock;
257         }
258     }
259 }