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