]> git.basschouten.com Git - openhab-addons.git/blob
706f84414e268580d6695b017cbe38053e4aa213
[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.discovery;
14
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.assertTrue;
18 import static org.mockito.Mockito.mock;
19 import static org.openhab.binding.hue.internal.HueBindingConstants.*;
20 import static org.openhab.core.config.discovery.inbox.InboxPredicates.forThingTypeUID;
21
22 import java.io.IOException;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.stream.Collectors;
28
29 import org.eclipse.jdt.annotation.NonNull;
30 import org.junit.jupiter.api.BeforeEach;
31 import org.junit.jupiter.api.Test;
32 import org.openhab.core.config.discovery.DiscoveryListener;
33 import org.openhab.core.config.discovery.DiscoveryResult;
34 import org.openhab.core.config.discovery.DiscoveryService;
35 import org.openhab.core.config.discovery.inbox.Inbox;
36 import org.openhab.core.test.java.JavaOSGiTest;
37 import org.openhab.core.test.storage.VolatileStorageService;
38 import org.openhab.core.thing.ThingRegistry;
39 import org.openhab.core.thing.ThingTypeUID;
40 import org.openhab.core.thing.ThingUID;
41
42 /**
43  * @author Christoph Knauf - Initial contribution
44  * @author Markus Rathgeb - migrated to plain Java test
45  */
46 public class HueBridgeNupnpDiscoveryOSGITest extends JavaOSGiTest {
47
48     HueBridgeNupnpDiscovery sut;
49     VolatileStorageService volatileStorageService = new VolatileStorageService();
50     DiscoveryListener discoveryListener;
51     Inbox inbox;
52
53     final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID("hue", "bridge");
54     final String ip1 = "192.168.31.17";
55     final String ip2 = "192.168.30.28";
56     final String sn1 = "001788fffe20057f";
57     final String sn2 = "001788fffe141b41";
58     final ThingUID BRIDGE_THING_UID_1 = new ThingUID(BRIDGE_THING_TYPE_UID, sn1);
59     final ThingUID BRIDGE_THING_UID_2 = new ThingUID(BRIDGE_THING_TYPE_UID, sn2);
60     final String validBridgeDiscoveryResult = "[{\"id\":\"" + sn1 + "\",\"internalipaddress\":" + ip1 + "},{\"id\":\""
61             + sn2 + "\",\"internalipaddress\":" + ip2 + "}]";
62     String discoveryResult;
63     String expBridgeDescription = "{\"name\":\"Philips hue\",\"datastoreversion\":\"149\",\"swversion\":\"1957113050\",\"apiversion\":\"1.57.0\",\"mac\":\"00:11:22:33:44\",\"bridgeid\":\"$SN\",\"factorynew\":false,\"replacesbridgeid\":null,\"modelid\":\"BSB002\",\"starterkitid\":\"\"}";
64
65     private void checkDiscoveryResult(DiscoveryResult result, String expIp, String expSn) {
66         assertThat(result.getBridgeUID(), nullValue());
67         assertThat(result.getLabel(), is(String.format(DISCOVERY_LABEL_PATTERN, expIp)));
68         assertThat(result.getProperties().get("ipAddress"), is(expIp));
69         assertThat(result.getProperties().get("serialNumber"), is(expSn));
70     }
71
72     private void registerDiscoveryListener(DiscoveryListener discoveryListener) {
73         unregisterCurrentDiscoveryListener();
74         this.discoveryListener = discoveryListener;
75         sut.addDiscoveryListener(this.discoveryListener);
76     }
77
78     private void unregisterCurrentDiscoveryListener() {
79         if (this.discoveryListener != null) {
80             sut.removeDiscoveryListener(this.discoveryListener);
81         }
82     }
83
84     // Mock class which only overrides the doGetRequest method in order to make the class testable
85     class ConfigurableBridgeNupnpDiscoveryMock extends HueBridgeNupnpDiscovery {
86         public ConfigurableBridgeNupnpDiscoveryMock(ThingRegistry thingRegistry) {
87             super(thingRegistry);
88         }
89
90         @Override
91         protected String doGetRequest(String url) throws IOException {
92             if (url.contains("meethue")) {
93                 return discoveryResult;
94             } else if (url.contains(ip1)) {
95                 return expBridgeDescription.replaceAll("$SN", sn1);
96             } else if (url.contains(ip2)) {
97                 return expBridgeDescription.replaceAll("$SN", sn2);
98             }
99             throw new IOException();
100         }
101
102         @Override
103         protected boolean isClip2Supported(@NonNull String ipAddress) {
104             return false;
105         }
106     }
107
108     @BeforeEach
109     public void setUp() {
110         registerService(volatileStorageService);
111
112         sut = getService(DiscoveryService.class, HueBridgeNupnpDiscovery.class);
113         assertThat(sut, is(notNullValue()));
114
115         inbox = getService(Inbox.class);
116         assertThat(inbox, is(notNullValue()));
117
118         unregisterCurrentDiscoveryListener();
119     }
120
121     @Test
122     public void bridgeThingTypeIsSupported() {
123         assertThat(sut.getSupportedThingTypes().size(), is(2));
124         assertThat(sut.getSupportedThingTypes().contains(THING_TYPE_BRIDGE), is(true));
125     }
126
127     @Test
128     public void validBridgesAreDiscovered() {
129         List<DiscoveryResult> oldResults = inbox.stream().filter(forThingTypeUID(BRIDGE_THING_TYPE_UID))
130                 .collect(Collectors.toList());
131         for (final DiscoveryResult oldResult : oldResults) {
132             inbox.remove(oldResult.getThingUID());
133         }
134
135         sut = new ConfigurableBridgeNupnpDiscoveryMock(mock(ThingRegistry.class));
136         registerService(sut, DiscoveryService.class.getName());
137         discoveryResult = validBridgeDiscoveryResult;
138         final Map<ThingUID, DiscoveryResult> results = new HashMap<>();
139         registerDiscoveryListener(new DiscoveryListener() {
140             @Override
141             public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
142                 results.put(result.getThingUID(), result);
143             }
144
145             @Override
146             public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
147             }
148
149             @Override
150             public Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
151                     Collection<ThingTypeUID> thingTypeUIDs, ThingUID bridgeUID) {
152                 return null;
153             }
154         });
155
156         sut.startScan();
157
158         waitForAssert(() -> {
159             assertThat(results.size(), is(2));
160             assertThat(results.get(BRIDGE_THING_UID_1), is(notNullValue()));
161             checkDiscoveryResult(results.get(BRIDGE_THING_UID_1), ip1, sn1);
162             assertThat(results.get(BRIDGE_THING_UID_2), is(notNullValue()));
163             checkDiscoveryResult(results.get(BRIDGE_THING_UID_2), ip2, sn2);
164
165             final List<DiscoveryResult> inboxResults = inbox.stream().filter(forThingTypeUID(BRIDGE_THING_TYPE_UID))
166                     .collect(Collectors.toList());
167             assertTrue(inboxResults.size() >= 2);
168
169             assertThat(inboxResults.stream().filter(result -> result.getThingUID().equals(BRIDGE_THING_UID_1))
170                     .findFirst().orElse(null), is(notNullValue()));
171             assertThat(inboxResults.stream().filter(result -> result.getThingUID().equals(BRIDGE_THING_UID_2))
172                     .findFirst().orElse(null), is(notNullValue()));
173         });
174     }
175
176     @Test
177     public void invalidBridgesAreNotDiscovered() {
178         List<DiscoveryResult> oldResults = inbox.stream().filter(forThingTypeUID(BRIDGE_THING_TYPE_UID))
179                 .collect(Collectors.toList());
180         for (final DiscoveryResult oldResult : oldResults) {
181             inbox.remove(oldResult.getThingUID());
182         }
183
184         sut = new ConfigurableBridgeNupnpDiscoveryMock(mock(ThingRegistry.class));
185         registerService(sut, DiscoveryService.class.getName());
186         final Map<ThingUID, DiscoveryResult> results = new HashMap<>();
187         registerDiscoveryListener(new DiscoveryListener() {
188             @Override
189             public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
190                 results.put(result.getThingUID(), result);
191             }
192
193             @Override
194             public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
195             }
196
197             @Override
198             public Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
199                     Collection<ThingTypeUID> thingTypeUIDs, ThingUID bridgeUID) {
200                 return null;
201             }
202         });
203
204         // missing ip
205         discoveryResult = "[{\"id\":\"001788fffe20057f\",\"internalipaddress\":}]";
206         sut.startScan();
207         waitForAssert(() -> {
208             assertThat(results.size(), is(0));
209         });
210
211         // missing id
212         discoveryResult = "[{\"id\":\"\",\"internalipaddress\":192.168.30.22}]";
213         sut.startScan();
214         waitForAssert(() -> {
215             assertThat(results.size(), is(0));
216         });
217
218         // id < 10
219         discoveryResult = "[{\"id\":\"012345678\",\"internalipaddress\":192.168.30.22}]";
220         sut.startScan();
221         waitForAssert(() -> {
222             assertThat(results.size(), is(0));
223         });
224
225         // bridge indicator not part of id
226         discoveryResult = "[{\"id\":\"0123456789\",\"internalipaddress\":192.168.30.22}]";
227         sut.startScan();
228         waitForAssert(() -> {
229             assertThat(results.size(), is(0));
230         });
231
232         // bridge indicator at wrong position (-1)
233         discoveryResult = "[{\"id\":\"01234" + HueBridgeNupnpDiscovery.BRIDGE_INDICATOR
234                 + "7891\",\"internalipaddress\":192.168.30.22}]";
235         sut.startScan();
236         waitForAssert(() -> {
237             assertThat(results.size(), is(0));
238         });
239
240         // bridge indicator at wrong position (+1)
241         discoveryResult = "[{\"id\":\"0123456" + HueBridgeNupnpDiscovery.BRIDGE_INDICATOR
242                 + "7891\",\"internalipaddress\":192.168.30.22}]";
243         sut.startScan();
244         waitForAssert(() -> {
245             assertThat(results.size(), is(0));
246         });
247
248         // bridge not reachable
249         discoveryResult = "[{\"id\":\"001788fffe20057f\",\"internalipaddress\":192.168.30.1}]";
250         sut.startScan();
251         waitForAssert(() -> {
252             assertThat(results.size(), is(0));
253         });
254
255         // invalid bridge description
256         expBridgeDescription = "";
257         discoveryResult = "[{\"id\":\"001788fffe20057f\",\"internalipaddress\":" + ip1 + "}]";
258         sut.startScan();
259         waitForAssert(() -> {
260             assertThat(results.size(), is(0));
261         });
262
263         waitForAssert(() -> {
264             assertThat(
265                     inbox.stream().filter(forThingTypeUID(BRIDGE_THING_TYPE_UID)).collect(Collectors.toList()).size(),
266                     is(0));
267         });
268     }
269 }