]> git.basschouten.com Git - openhab-addons.git/blob
3e45b1e95436367d53cd066cc84845c90a09b7ce
[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.hue.internal;
14
15 import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
16 import static org.hamcrest.CoreMatchers.*;
17 import static org.junit.Assert.*;
18 import static org.openhab.binding.hue.internal.HueBindingConstants.*;
19
20 import java.io.IOException;
21 import java.lang.reflect.Field;
22 import java.util.Collection;
23 import java.util.concurrent.atomic.AtomicBoolean;
24 import java.util.concurrent.atomic.AtomicReference;
25
26 import org.openhab.core.config.core.Configuration;
27 import org.openhab.core.config.discovery.DiscoveryListener;
28 import org.openhab.core.config.discovery.DiscoveryResult;
29 import org.openhab.core.config.discovery.DiscoveryResultFlag;
30 import org.openhab.core.config.discovery.DiscoveryService;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.ThingRegistry;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.ThingStatusDetail;
35 import org.openhab.core.thing.ThingStatusInfo;
36 import org.openhab.core.thing.ThingTypeUID;
37 import org.openhab.core.thing.ThingUID;
38 import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
39 import org.junit.After;
40 import org.junit.Assert;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.openhab.binding.hue.internal.discovery.HueLightDiscoveryService;
44 import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
45
46 /**
47  * Tests for {@link HueLightDiscoveryService}.
48  *
49  * @author Kai Kreuzer - Initial contribution
50  * @author Andre Fuechsel - added test 'assert start search is called()'
51  *         - modified tests after introducing the generic thing types
52  * @author Denis Dudnik - switched to internally integrated source of Jue library
53  * @author Markus Rathgeb - migrated to plain Java test
54  */
55 public class HueLightDiscoveryServiceOSGiTest extends AbstractHueOSGiTestParent {
56
57     protected HueThingHandlerFactory hueThingHandlerFactory;
58     protected DiscoveryListener discoveryListener;
59     protected ThingRegistry thingRegistry;
60     protected Bridge hueBridge;
61     protected HueBridgeHandler hueBridgeHandler;
62     protected HueLightDiscoveryService discoveryService;
63
64     protected final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID("hue", "bridge");
65     protected final ThingUID BRIDGE_THING_UID = new ThingUID(BRIDGE_THING_TYPE_UID, "testBridge");
66
67     @Before
68     public void setUp() {
69         registerVolatileStorageService();
70
71         thingRegistry = getService(ThingRegistry.class, ThingRegistry.class);
72         assertThat(thingRegistry, is(notNullValue()));
73
74         Configuration configuration = new Configuration();
75         configuration.put(HOST, "1.2.3.4");
76         configuration.put(USER_NAME, "testUserName");
77         configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
78
79         hueBridge = (Bridge) thingRegistry.createThingOfType(BRIDGE_THING_TYPE_UID, BRIDGE_THING_UID, null, "Bridge",
80                 configuration);
81
82         assertThat(hueBridge, is(notNullValue()));
83         thingRegistry.add(hueBridge);
84
85         hueBridgeHandler = getThingHandler(hueBridge, HueBridgeHandler.class);
86         assertThat(hueBridgeHandler, is(notNullValue()));
87
88         discoveryService = getService(DiscoveryService.class, HueLightDiscoveryService.class);
89         assertThat(discoveryService, is(notNullValue()));
90     }
91
92     @After
93     public void cleanUp() {
94         thingRegistry.remove(BRIDGE_THING_UID);
95         waitForAssert(() -> {
96             assertNull(getService(DiscoveryService.class, HueLightDiscoveryService.class));
97         });
98     }
99
100     private void registerDiscoveryListener(DiscoveryListener discoveryListener) {
101         unregisterCurrentDiscoveryListener();
102         this.discoveryListener = discoveryListener;
103         discoveryService.addDiscoveryListener(this.discoveryListener);
104     }
105
106     private void unregisterCurrentDiscoveryListener() {
107         if (this.discoveryListener != null) {
108             discoveryService.removeDiscoveryListener(this.discoveryListener);
109         }
110     }
111
112     @Test
113     public void hueLightRegistration() {
114         FullLight light = new FullLight();
115         light.setId("1");
116         light.setModelID("LCT001");
117         light.setType("Extended color light");
118
119         AtomicReference<DiscoveryResult> resultWrapper = new AtomicReference<>();
120
121         registerDiscoveryListener(new DiscoveryListener() {
122             @Override
123             public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
124                 resultWrapper.set(result);
125             }
126
127             @Override
128             public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
129             }
130
131             @Override
132             public Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
133                     Collection<ThingTypeUID> thingTypeUIDs, ThingUID bridgeUID) {
134                 return null;
135             }
136         });
137
138         discoveryService.addLightDiscovery(light);
139         waitForAssert(() -> {
140             assertTrue(resultWrapper.get() != null);
141         });
142
143         final DiscoveryResult result = resultWrapper.get();
144         assertThat(result.getFlag(), is(DiscoveryResultFlag.NEW));
145         assertThat(result.getThingUID().toString(), is("hue:0210:testBridge:" + light.getId()));
146         assertThat(result.getThingTypeUID(), is(THING_TYPE_EXTENDED_COLOR_LIGHT));
147         assertThat(result.getBridgeUID(), is(hueBridge.getUID()));
148         assertThat(result.getProperties().get(LIGHT_ID), is(light.getId()));
149     }
150
151     @Test
152     public void startSearchIsCalled() {
153         final AtomicBoolean searchHasBeenTriggered = new AtomicBoolean(false);
154
155         MockedHttpClient mockedHttpClient = new MockedHttpClient() {
156
157             @Override
158             public Result put(String address, String body) throws IOException {
159                 return new Result("", 200);
160             }
161
162             @Override
163             public Result get(String address) throws IOException {
164                 if (address.endsWith("testUserName")) {
165                     String body = "{\"lights\":{}}";
166                     return new Result(body, 200);
167                 } else if (address.endsWith("lights") || address.endsWith("sensors")) {
168                     String body = "{}";
169                     return new Result(body, 200);
170                 } else if (address.endsWith("testUserName/config")) {
171                     String body = "{ \"apiversion\": \"1.26.0\"}";
172                     return new Result(body, 200);
173                 } else {
174                     return new Result("", 404);
175                 }
176             }
177
178             @Override
179             public Result post(String address, String body) throws IOException {
180                 if (address.endsWith("lights")) {
181                     String bodyReturn = "{\"success\": {\"/lights\": \"Searching for new devices\"}}";
182                     searchHasBeenTriggered.set(true);
183                     return new Result(bodyReturn, 200);
184                 } else {
185                     return new Result("", 404);
186                 }
187             }
188         };
189
190         installHttpClientMock(hueBridgeHandler, mockedHttpClient);
191
192         ThingStatusInfo online = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
193         waitForAssert(() -> {
194             assertThat(hueBridge.getStatusInfo(), is(online));
195         });
196
197         discoveryService.startScan();
198         waitForAssert(() -> {
199             assertTrue(searchHasBeenTriggered.get());
200         });
201     }
202
203     private void installHttpClientMock(HueBridgeHandler hueBridgeHandler, MockedHttpClient mockedHttpClient) {
204         waitForAssert(() -> {
205             try {
206                 // mock HttpClient
207                 final Field hueBridgeField = HueBridgeHandler.class.getDeclaredField("hueBridge");
208                 hueBridgeField.setAccessible(true);
209                 final Object hueBridgeValue = hueBridgeField.get(hueBridgeHandler);
210                 assertThat(hueBridgeValue, is(notNullValue()));
211
212                 final Field httpClientField = HueBridge.class.getDeclaredField("http");
213                 httpClientField.setAccessible(true);
214                 httpClientField.set(hueBridgeValue, mockedHttpClient);
215
216                 final Field usernameField = HueBridge.class.getDeclaredField("username");
217                 usernameField.setAccessible(true);
218                 usernameField.set(hueBridgeValue, hueBridgeHandler.getThing().getConfiguration().get(USER_NAME));
219             } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) {
220                 Assert.fail("Reflection usage error");
221             }
222         });
223         hueBridgeHandler.initialize();
224     }
225 }