2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.innogysmarthome.internal.handler;
15 import static org.junit.Assert.assertEquals;
16 import static org.mockito.Mockito.*;
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;
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.eclipse.jetty.client.HttpClient;
26 import org.junit.Before;
27 import org.junit.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;
40 * @author Sven Strohschein - Initial contribution
42 public class InnogyBridgeHandlerTest {
44 private static final int MAXIMUM_RETRY_EXECUTIONS = 10;
46 private InnogyBridgeHandlerAccessible bridgeHandler;
47 private Bridge bridgeMock;
48 private InnogyWebSocket webSocketMock;
51 public void before() throws Exception {
52 bridgeMock = mock(Bridge.class);
53 when(bridgeMock.getUID()).thenReturn(new ThingUID("innogysmarthome", "bridge"));
55 webSocketMock = mock(InnogyWebSocket.class);
57 OAuthClientService oAuthService = mock(OAuthClientService.class);
59 OAuthFactory oAuthFactoryMock = mock(OAuthFactory.class);
60 when(oAuthFactoryMock.createOAuthClientService(any(), any(), any(), any(), any(), any(), any()))
61 .thenReturn(oAuthService);
63 HttpClient httpClientMock = mock(HttpClient.class);
65 bridgeHandler = new InnogyBridgeHandlerAccessible(bridgeMock, oAuthFactoryMock, httpClientMock);
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);
75 when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
77 bridgeHandler.initialize();
79 verify(webSocketMock, never()).start();
80 assertEquals(0, bridgeHandler.getDirectExecutionCount());
84 public void testInitialize() throws Exception {
85 Configuration bridgeConfig = new Configuration();
87 when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
89 bridgeHandler.initialize();
91 verify(webSocketMock).start();
92 assertEquals(1, bridgeHandler.getDirectExecutionCount());
96 public void testInitializeErrorOnStartingWebSocket() throws Exception {
97 Configuration bridgeConfig = new Configuration();
99 when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
101 doThrow(new RuntimeException("Test-Exception")).when(webSocketMock).start();
103 bridgeHandler.initialize();
105 verify(webSocketMock, times(MAXIMUM_RETRY_EXECUTIONS)).start();
106 assertEquals(1, bridgeHandler.getDirectExecutionCount()); // only the first execution should be without a delay
110 public void testConnectionClosed() throws Exception {
111 Configuration bridgeConfig = new Configuration();
113 when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
115 bridgeHandler.initialize();
117 verify(webSocketMock).start();
118 assertEquals(1, bridgeHandler.getDirectExecutionCount());
120 bridgeHandler.connectionClosed();
122 verify(webSocketMock, times(2)).start(); // automatically restarted (with a delay)
123 assertEquals(1, bridgeHandler.getDirectExecutionCount());
125 bridgeHandler.connectionClosed();
127 verify(webSocketMock, times(3)).start(); // automatically restarted (with a delay)
128 assertEquals(1, bridgeHandler.getDirectExecutionCount());
132 public void testConnectionClosedReconnectNotPossible() throws Exception {
133 Configuration bridgeConfig = new Configuration();
135 when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
137 bridgeHandler.initialize();
139 verify(webSocketMock).start();
140 assertEquals(1, bridgeHandler.getDirectExecutionCount());
142 doThrow(new ConnectException("Connection refused")).when(webSocketMock).start();
144 bridgeHandler.connectionClosed();
146 verify(webSocketMock, times(10)).start(); // automatic reconnect attempts (with a delay)
147 assertEquals(1, bridgeHandler.getDirectExecutionCount());
151 public void testOnEventDisconnect() throws Exception {
152 final String disconnectEventJSON = "{ type: \"Disconnect\" }";
154 Configuration bridgeConfig = new Configuration();
156 when(bridgeMock.getConfiguration()).thenReturn(bridgeConfig);
158 bridgeHandler.initialize();
160 verify(webSocketMock).start();
161 assertEquals(1, bridgeHandler.getDirectExecutionCount());
163 bridgeHandler.onEvent(disconnectEventJSON);
165 verify(webSocketMock, times(2)).start(); // automatically restarted (with a delay)
166 assertEquals(1, bridgeHandler.getDirectExecutionCount());
168 bridgeHandler.onEvent(disconnectEventJSON);
170 verify(webSocketMock, times(3)).start(); // automatically restarted (with a delay)
171 assertEquals(1, bridgeHandler.getDirectExecutionCount());
174 private class InnogyBridgeHandlerAccessible extends InnogyBridgeHandler {
176 private final InnogyClient innogyClientMock;
177 private final ScheduledExecutorService schedulerMock;
178 private int executionCount;
179 private int directExecutionCount;
181 private InnogyBridgeHandlerAccessible(Bridge bridge, OAuthFactory oAuthFactory, HttpClient httpClient)
183 super(bridge, oAuthFactory, httpClient);
185 Device bridgeDevice = new Device();
186 bridgeDevice.setId("bridgeId");
187 bridgeDevice.setType(InnogyBindingConstants.DEVICE_SHC);
188 bridgeDevice.setConfig(new DeviceConfig());
190 innogyClientMock = mock(InnogyClient.class);
191 when(innogyClientMock.getFullDevices()).thenReturn(Collections.singletonList(bridgeDevice));
193 schedulerMock = mock(ScheduledExecutorService.class);
195 doAnswer(invocationOnMock -> {
196 if (executionCount <= MAXIMUM_RETRY_EXECUTIONS) {
198 invocationOnMock.getArgument(0, Runnable.class).run();
201 }).when(schedulerMock).execute(any());
203 doAnswer(invocationOnMock -> {
204 if (executionCount <= MAXIMUM_RETRY_EXECUTIONS) {
206 long seconds = invocationOnMock.getArgument(1);
208 directExecutionCount++;
211 invocationOnMock.getArgument(0, Runnable.class).run();
213 return mock(ScheduledFuture.class);
214 }).when(schedulerMock).schedule(any(Runnable.class), anyLong(), any());
217 public int getDirectExecutionCount() {
218 return directExecutionCount;
223 InnogyClient createInnogyClient(@NonNull OAuthClientService oAuthService, @NonNull HttpClient httpClient) {
224 return innogyClientMock;
229 InnogyWebSocket createWebSocket() {
230 return webSocketMock;
235 ScheduledExecutorService getScheduler() {
236 return schedulerMock;