]> git.basschouten.com Git - openhab-addons.git/blob
fcebe767808041dc333ccbc03a05b5349e374f38
[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.hue.internal.handler;
14
15 import static org.eclipse.jdt.annotation.Checks.requireNonNull;
16 import static org.hamcrest.CoreMatchers.equalTo;
17 import static org.hamcrest.MatcherAssert.assertThat;
18 import static org.junit.jupiter.api.Assertions.*;
19 import static org.mockito.Mockito.mock;
20 import static org.openhab.binding.hue.internal.HueBindingConstants.*;
21
22 import java.io.IOException;
23 import java.lang.reflect.Field;
24 import java.util.concurrent.ScheduledExecutorService;
25
26 import org.eclipse.jetty.client.HttpClient;
27 import org.junit.jupiter.api.BeforeEach;
28 import org.junit.jupiter.api.Test;
29 import org.openhab.binding.hue.internal.AbstractHueOSGiTestParent;
30 import org.openhab.binding.hue.internal.config.HueBridgeConfig;
31 import org.openhab.binding.hue.internal.connection.HueBridge;
32 import org.openhab.binding.hue.internal.exceptions.ApiException;
33 import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
34 import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
35 import org.openhab.core.common.ThreadPoolManager;
36 import org.openhab.core.config.core.Configuration;
37 import org.openhab.core.config.core.status.ConfigStatusMessage;
38 import org.openhab.core.thing.Bridge;
39 import org.openhab.core.thing.Thing;
40 import org.openhab.core.thing.ThingRegistry;
41 import org.openhab.core.thing.ThingStatus;
42 import org.openhab.core.thing.ThingStatusDetail;
43 import org.openhab.core.thing.ThingTypeUID;
44 import org.openhab.core.thing.ThingUID;
45
46 /**
47  * Tests for {@link HueBridgeHandler}.
48  *
49  * @author Oliver Libutzki - Initial contribution
50  * @author Michael Grammling - Initial contribution
51  * @author Denis Dudnik - switched to internally integrated source of Jue library
52  */
53 public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
54
55     private static final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "bridge");
56     private static final String TEST_USER_NAME = "eshTestUser";
57     private static final String DUMMY_HOST = "1.2.3.4";
58
59     private ThingRegistry thingRegistry;
60
61     private ScheduledExecutorService scheduler;
62
63     @BeforeEach
64     public void setUp() {
65         registerVolatileStorageService();
66         thingRegistry = getService(ThingRegistry.class, ThingRegistry.class);
67         assertNotNull(thingRegistry);
68
69         scheduler = ThreadPoolManager.getScheduledPool("hueBridgeTest");
70     }
71
72     @Test
73     public void assertThatANewUserIsAddedToConfigIfNotExistingYet() {
74         Configuration configuration = new Configuration();
75         configuration.put(HOST, DUMMY_HOST);
76         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
77         Bridge bridge = createBridgeThing(configuration);
78
79         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
80         hueBridgeHandler.thingUpdated(bridge);
81
82         injectBridge(hueBridgeHandler,
83                 new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
84                     @Override
85                     public String link(String deviceType) throws IOException, ApiException {
86                         return TEST_USER_NAME;
87                     }
88                 });
89
90         hueBridgeHandler.onNotAuthenticated();
91
92         assertThat(bridge.getConfiguration().get(USER_NAME), equalTo(TEST_USER_NAME));
93     }
94
95     @Test
96     public void assertThatAnExistingUserIsUsedIfAuthenticationWasSuccessful() {
97         Configuration configuration = new Configuration();
98         configuration.put(HOST, DUMMY_HOST);
99         configuration.put(USER_NAME, TEST_USER_NAME);
100         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
101         Bridge bridge = createBridgeThing(configuration);
102
103         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
104         hueBridgeHandler.thingUpdated(bridge);
105
106         injectBridge(hueBridgeHandler,
107                 new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
108                     @Override
109                     public void authenticate(String userName) throws IOException, ApiException {
110                     }
111                 });
112
113         hueBridgeHandler.onNotAuthenticated();
114
115         assertThat(bridge.getConfiguration().get(USER_NAME), equalTo(TEST_USER_NAME));
116     }
117
118     @Test
119     public void assertCorrectStatusIfAuthenticationFailedForOldUser() {
120         Configuration configuration = new Configuration();
121         configuration.put(HOST, DUMMY_HOST);
122         configuration.put(USER_NAME, "notAuthenticatedUser");
123         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
124         Bridge bridge = createBridgeThing(configuration);
125
126         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
127         hueBridgeHandler.thingUpdated(bridge);
128
129         injectBridge(hueBridgeHandler,
130                 new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
131                     @Override
132                     public void authenticate(String userName) throws IOException, ApiException {
133                         throw new UnauthorizedException();
134                     }
135                 });
136
137         hueBridgeHandler.onNotAuthenticated();
138
139         assertEquals("notAuthenticatedUser", bridge.getConfiguration().get(USER_NAME));
140         waitForAssert(() -> assertEquals(ThingStatus.OFFLINE, bridge.getStatus()));
141         assertEquals(ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, bridge.getStatusInfo().getStatusDetail());
142     }
143
144     @Test
145     public void verifyStatusIfLinkButtonIsNotPressed() {
146         Configuration configuration = new Configuration();
147         configuration.put(HOST, DUMMY_HOST);
148         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
149         Bridge bridge = createBridgeThing(configuration);
150
151         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
152         hueBridgeHandler.thingUpdated(bridge);
153
154         injectBridge(hueBridgeHandler,
155                 new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
156                     @Override
157                     public String link(String deviceType) throws IOException, ApiException {
158                         throw new LinkButtonException();
159                     }
160                 });
161
162         hueBridgeHandler.onNotAuthenticated();
163
164         assertNull(bridge.getConfiguration().get(USER_NAME));
165         waitForAssert(() -> assertEquals(ThingStatus.OFFLINE, bridge.getStatus()));
166         assertEquals(ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, bridge.getStatusInfo().getStatusDetail());
167     }
168
169     @Test
170     public void verifyStatusIfNewUserCannotBeCreated() {
171         Configuration configuration = new Configuration();
172         configuration.put(HOST, DUMMY_HOST);
173         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
174         Bridge bridge = createBridgeThing(configuration);
175
176         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
177         hueBridgeHandler.thingUpdated(bridge);
178
179         injectBridge(hueBridgeHandler,
180                 new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
181                     @Override
182                     public String link(String deviceType) throws IOException, ApiException {
183                         throw new ApiException();
184                     }
185                 });
186
187         hueBridgeHandler.onNotAuthenticated();
188
189         assertNull(bridge.getConfiguration().get(USER_NAME));
190         waitForAssert(() -> assertEquals(ThingStatus.OFFLINE, bridge.getStatus()));
191         waitForAssert(() -> assertEquals(ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
192                 bridge.getStatusInfo().getStatusDetail()));
193     }
194
195     @Test
196     public void verifyOfflineIsSetWithoutBridgeOfflineStatus() {
197         Configuration configuration = new Configuration();
198         configuration.put(HOST, DUMMY_HOST);
199         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
200         Bridge bridge = createBridgeThing(configuration);
201
202         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
203         hueBridgeHandler.thingUpdated(bridge);
204
205         hueBridgeHandler.onConnectionLost();
206
207         waitForAssert(() -> assertEquals(ThingStatus.OFFLINE, bridge.getStatus()));
208         assertNotEquals(ThingStatusDetail.BRIDGE_OFFLINE, bridge.getStatusInfo().getStatusDetail());
209     }
210
211     @Test
212     public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsNull() {
213         Configuration configuration = new Configuration();
214         configuration.put(HOST, null);
215         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
216         Bridge bridge = createBridgeThing(configuration);
217
218         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
219
220         ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST).withMessageKeySuffix(IP_ADDRESS_MISSING)
221                 .withArguments(HOST).build();
222
223         waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
224     }
225
226     @Test
227     public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsAnEmptyString() {
228         Configuration configuration = new Configuration();
229         configuration.put(HOST, "");
230         configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
231         Bridge bridge = createBridgeThing(configuration);
232
233         HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
234
235         ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST).withMessageKeySuffix(IP_ADDRESS_MISSING)
236                 .withArguments(HOST).build();
237
238         waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
239     }
240
241     private Bridge createBridgeThing(Configuration configuration) {
242         configuration.put("useSelfSignedCertificate", false);
243         Bridge bridge = (Bridge) thingRegistry.createThingOfType(BRIDGE_THING_TYPE_UID,
244                 new ThingUID(BRIDGE_THING_TYPE_UID, "testBridge"), null, "Bridge", configuration);
245
246         bridge = requireNonNull(bridge, "Bridge is null");
247         thingRegistry.add(bridge);
248         return bridge;
249     }
250
251     private void injectBridge(HueBridgeHandler hueBridgeHandler, HueBridge bridge) {
252         try {
253             Field hueBridgeField = hueBridgeHandler.getClass().getDeclaredField("hueBridge");
254             hueBridgeField.setAccessible(true);
255             hueBridgeField.set(hueBridgeHandler, bridge);
256         } catch (Exception e) {
257             throw new AssertionError(e);
258         }
259     }
260 }