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.hue.internal.handler;
15 import static org.hamcrest.CoreMatchers.equalTo;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.*;
18 import static org.openhab.binding.hue.internal.HueBindingConstants.*;
19 import static org.openhab.binding.hue.internal.config.HueBridgeConfig.HTTP;
20 import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
22 import java.io.IOException;
23 import java.lang.reflect.Field;
24 import java.util.concurrent.ScheduledExecutorService;
26 import org.junit.jupiter.api.BeforeEach;
27 import org.junit.jupiter.api.Test;
28 import org.openhab.binding.hue.internal.AbstractHueOSGiTestParent;
29 import org.openhab.binding.hue.internal.HueBridge;
30 import org.openhab.binding.hue.internal.HueConfigStatusMessage;
31 import org.openhab.binding.hue.internal.exceptions.ApiException;
32 import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
33 import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
34 import org.openhab.core.common.ThreadPoolManager;
35 import org.openhab.core.config.core.Configuration;
36 import org.openhab.core.config.core.status.ConfigStatusMessage;
37 import org.openhab.core.thing.Bridge;
38 import org.openhab.core.thing.ThingRegistry;
39 import org.openhab.core.thing.ThingStatus;
40 import org.openhab.core.thing.ThingStatusDetail;
41 import org.openhab.core.thing.ThingTypeUID;
42 import org.openhab.core.thing.ThingUID;
45 * Tests for {@link HueBridgeHandler}.
47 * @author Oliver Libutzki - Initial contribution
48 * @author Michael Grammling - Initial contribution
49 * @author Denis Dudnik - switched to internally integrated source of Jue library
51 public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
53 private final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "bridge");
54 private static final String TEST_USER_NAME = "eshTestUser";
55 private static final String DUMMY_HOST = "1.2.3.4";
57 private ThingRegistry thingRegistry;
59 private ScheduledExecutorService scheduler;
63 registerVolatileStorageService();
64 thingRegistry = getService(ThingRegistry.class, ThingRegistry.class);
65 assertNotNull(thingRegistry);
67 scheduler = ThreadPoolManager.getScheduledPool("hueBridgeTest");
71 public void assertThatANewUserIsAddedToConfigIfNotExistingYet() {
72 Configuration configuration = new Configuration();
73 configuration.put(HOST, DUMMY_HOST);
74 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
75 Bridge bridge = createBridgeThing(configuration);
77 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
78 hueBridgeHandler.thingUpdated(bridge);
80 injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
82 public String link(String deviceType) throws IOException, ApiException {
83 return TEST_USER_NAME;
87 hueBridgeHandler.onNotAuthenticated();
89 assertThat(bridge.getConfiguration().get(USER_NAME), equalTo(TEST_USER_NAME));
93 public void assertThatAnExistingUserIsUsedIfAuthenticationWasSuccessful() {
94 Configuration configuration = new Configuration();
95 configuration.put(HOST, DUMMY_HOST);
96 configuration.put(USER_NAME, TEST_USER_NAME);
97 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
98 Bridge bridge = createBridgeThing(configuration);
100 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
101 hueBridgeHandler.thingUpdated(bridge);
103 injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
105 public void authenticate(String userName) throws IOException, ApiException {
109 hueBridgeHandler.onNotAuthenticated();
111 assertThat(bridge.getConfiguration().get(USER_NAME), equalTo(TEST_USER_NAME));
115 public void assertCorrectStatusIfAuthenticationFailedForOldUser() {
116 Configuration configuration = new Configuration();
117 configuration.put(HOST, DUMMY_HOST);
118 configuration.put(USER_NAME, "notAuthenticatedUser");
119 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
120 Bridge bridge = createBridgeThing(configuration);
122 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
123 hueBridgeHandler.thingUpdated(bridge);
125 injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
127 public void authenticate(String userName) throws IOException, ApiException {
128 throw new UnauthorizedException();
132 hueBridgeHandler.onNotAuthenticated();
134 assertEquals("notAuthenticatedUser", bridge.getConfiguration().get(USER_NAME));
135 assertEquals(ThingStatus.OFFLINE, bridge.getStatus());
136 assertEquals(ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, bridge.getStatusInfo().getStatusDetail());
140 public void verifyStatusIfLinkButtonIsNotPressed() {
141 Configuration configuration = new Configuration();
142 configuration.put(HOST, DUMMY_HOST);
143 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
144 Bridge bridge = createBridgeThing(configuration);
146 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
147 hueBridgeHandler.thingUpdated(bridge);
149 injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
151 public String link(String deviceType) throws IOException, ApiException {
152 throw new LinkButtonException();
156 hueBridgeHandler.onNotAuthenticated();
158 assertNull(bridge.getConfiguration().get(USER_NAME));
159 assertEquals(ThingStatus.OFFLINE, bridge.getStatus());
160 assertEquals(ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, bridge.getStatusInfo().getStatusDetail());
164 public void verifyStatusIfNewUserCannotBeCreated() {
165 Configuration configuration = new Configuration();
166 configuration.put(HOST, DUMMY_HOST);
167 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
168 Bridge bridge = createBridgeThing(configuration);
170 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
171 hueBridgeHandler.thingUpdated(bridge);
173 injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
175 public String link(String deviceType) throws IOException, ApiException {
176 throw new ApiException();
180 hueBridgeHandler.onNotAuthenticated();
182 assertNull(bridge.getConfiguration().get(USER_NAME));
183 assertEquals(ThingStatus.OFFLINE, bridge.getStatus());
184 assertEquals(ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, bridge.getStatusInfo().getStatusDetail());
188 public void verifyOfflineIsSetWithoutBridgeOfflineStatus() {
189 Configuration configuration = new Configuration();
190 configuration.put(HOST, DUMMY_HOST);
191 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
192 Bridge bridge = createBridgeThing(configuration);
194 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
195 hueBridgeHandler.thingUpdated(bridge);
197 hueBridgeHandler.onConnectionLost();
199 assertEquals(ThingStatus.OFFLINE, bridge.getStatus());
200 assertNotEquals(ThingStatusDetail.BRIDGE_OFFLINE, bridge.getStatusInfo().getStatusDetail());
204 public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsNull() {
205 Configuration configuration = new Configuration();
206 configuration.put(HOST, null);
207 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
209 Bridge bridge = createBridgeThing(configuration);
211 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
213 ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST)
214 .withMessageKeySuffix(HueConfigStatusMessage.IP_ADDRESS_MISSING).withArguments(HOST).build();
216 waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
220 public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsAnEmptyString() {
221 Configuration configuration = new Configuration();
222 configuration.put(HOST, "");
223 configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
225 Bridge bridge = createBridgeThing(configuration);
227 HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
229 ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST)
230 .withMessageKeySuffix(HueConfigStatusMessage.IP_ADDRESS_MISSING).withArguments(HOST).build();
232 waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
235 private Bridge createBridgeThing(Configuration configuration) {
236 Bridge bridge = (Bridge) thingRegistry.createThingOfType(BRIDGE_THING_TYPE_UID,
237 new ThingUID(BRIDGE_THING_TYPE_UID, "testBridge"), null, "Bridge", configuration);
239 assertNotNull(bridge);
240 thingRegistry.add(bridge);
244 private void injectBridge(HueBridgeHandler hueBridgeHandler, HueBridge bridge) {
246 Field hueBridgeField = hueBridgeHandler.getClass().getDeclaredField("hueBridge");
247 hueBridgeField.setAccessible(true);
248 hueBridgeField.set(hueBridgeHandler, bridge);
249 } catch (Exception e) {
250 throw new AssertionError(e);