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