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