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.bluetooth.discovery.internal;
15 import static org.hamcrest.CoreMatchers.*;
17 import java.util.Collections;
18 import java.util.List;
20 import java.util.concurrent.CountDownLatch;
21 import java.util.concurrent.atomic.AtomicInteger;
22 import java.util.function.BiConsumer;
24 import org.apache.commons.lang.RandomStringUtils;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.junit.Assert;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.mockito.ArgumentCaptor;
33 import org.mockito.ArgumentMatchers;
34 import org.mockito.Mock;
35 import org.mockito.Mockito;
36 import org.mockito.Spy;
37 import org.mockito.junit.MockitoJUnitRunner;
38 import org.openhab.binding.bluetooth.BluetoothAdapter;
39 import org.openhab.binding.bluetooth.BluetoothAddress;
40 import org.openhab.binding.bluetooth.BluetoothBindingConstants;
41 import org.openhab.binding.bluetooth.BluetoothCharacteristic.GattCharacteristic;
42 import org.openhab.binding.bluetooth.BluetoothDevice;
43 import org.openhab.binding.bluetooth.MockBluetoothAdapter;
44 import org.openhab.binding.bluetooth.MockBluetoothDevice;
45 import org.openhab.binding.bluetooth.TestUtils;
46 import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice;
47 import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant;
48 import org.openhab.binding.bluetooth.notification.BluetoothConnectionStatusNotification;
49 import org.openhab.core.config.discovery.DiscoveryListener;
50 import org.openhab.core.config.discovery.DiscoveryResult;
51 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
52 import org.openhab.core.thing.ThingTypeUID;
53 import org.openhab.core.thing.ThingUID;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
58 * Tests {@link BluetoothDiscoveryService}.
60 * @author Connor Petty - Initial contribution
63 @RunWith(MockitoJUnitRunner.class)
64 public class BluetoothDiscoveryServiceTest {
66 private static final int TIMEOUT = 2000;
68 private final Logger logger = LoggerFactory.getLogger(BluetoothDiscoveryServiceTest.class);
70 private @NonNullByDefault({}) BluetoothDiscoveryService discoveryService;
73 private @NonNullByDefault({}) MockDiscoveryParticipant participant1 = new MockDiscoveryParticipant();
76 private @NonNullByDefault({}) DiscoveryListener mockDiscoveryListener;
80 discoveryService = new BluetoothDiscoveryService();
81 discoveryService.addDiscoveryListener(mockDiscoveryListener);
82 discoveryService.addBluetoothDiscoveryParticipant(participant1);
86 public void ignoreDuplicateTest() {
87 BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
88 BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
89 discoveryService.deviceDiscovered(device);
90 // this second call should not produce another result
91 discoveryService.deviceDiscovered(device);
93 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingDiscovered(
94 ArgumentMatchers.same(discoveryService),
95 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)));
99 public void ignoreOtherDuplicateTest() {
100 BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
101 BluetoothAdapter mockAdapter2 = new MockBluetoothAdapter();
102 BluetoothAddress address = TestUtils.randomAddress();
103 BluetoothDevice device1 = mockAdapter1.getDevice(address);
104 BluetoothDevice device2 = mockAdapter2.getDevice(address);
105 discoveryService.deviceDiscovered(device1);
106 discoveryService.deviceDiscovered(device2);
107 // this should not produce another result
108 discoveryService.deviceDiscovered(device1);
110 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2)).thingDiscovered(
111 ArgumentMatchers.same(discoveryService),
112 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)));
116 public void ignoreRssiDuplicateTest() {
117 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
118 MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
119 discoveryService.deviceDiscovered(device);
120 // changing the rssi should not result in a new discovery
122 discoveryService.deviceDiscovered(device);
124 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingDiscovered(
125 ArgumentMatchers.same(discoveryService),
126 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)));
130 public void nonDuplicateNameTest() throws InterruptedException {
131 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
132 MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
133 discoveryService.deviceDiscovered(device);
134 // this second call should produce another result
135 device.setName("sdfad");
136 discoveryService.deviceDiscovered(device);
138 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2)).thingDiscovered(
139 ArgumentMatchers.same(discoveryService),
140 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)));
144 public void nonDuplicateTxPowerTest() {
145 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
146 MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
147 discoveryService.deviceDiscovered(device);
148 // this second call should produce another result
149 device.setTxPower(10);
150 discoveryService.deviceDiscovered(device);
152 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2)).thingDiscovered(
153 ArgumentMatchers.same(discoveryService),
154 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)));
158 public void nonDuplicateManufacturerIdTest() {
159 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
160 MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
161 discoveryService.deviceDiscovered(device);
162 // this second call should produce another result
163 device.setManufacturerId(100);
164 discoveryService.deviceDiscovered(device);
166 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2)).thingDiscovered(
167 ArgumentMatchers.same(discoveryService),
168 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)));
172 public void useResultFromAnotherAdapterTest() {
173 BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
174 BluetoothAdapter mockAdapter2 = new MockBluetoothAdapter();
175 BluetoothAddress address = TestUtils.randomAddress();
177 discoveryService.deviceDiscovered(mockAdapter1.getDevice(address));
178 discoveryService.deviceDiscovered(mockAdapter2.getDevice(address));
180 ArgumentCaptor<DiscoveryResult> resultCaptor = ArgumentCaptor.forClass(DiscoveryResult.class);
181 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2))
182 .thingDiscovered(ArgumentMatchers.same(discoveryService), resultCaptor.capture());
184 List<DiscoveryResult> results = resultCaptor.getAllValues();
185 DiscoveryResult result1 = results.get(0);
186 DiscoveryResult result2 = results.get(1);
188 Assert.assertNotEquals(result1.getBridgeUID(), result2.getBridgeUID());
189 Assert.assertThat(result1.getBridgeUID(), anyOf(is(mockAdapter1.getUID()), is(mockAdapter2.getUID())));
190 Assert.assertThat(result2.getBridgeUID(), anyOf(is(mockAdapter1.getUID()), is(mockAdapter2.getUID())));
191 Assert.assertEquals(result1.getThingUID().getId(), result2.getThingUID().getId());
192 Assert.assertEquals(result1.getLabel(), result2.getLabel());
193 Assert.assertEquals(result1.getRepresentationProperty(), result2.getRepresentationProperty());
197 public void connectionParticipantTest() {
198 Mockito.doReturn(true).when(participant1).requiresConnection(ArgumentMatchers.any());
199 BluetoothAddress address = TestUtils.randomAddress();
201 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
202 MockBluetoothDevice mockDevice = mockAdapter1.getDevice(address);
203 String deviceName = RandomStringUtils.randomAlphanumeric(10);
204 mockDevice.setDeviceName(deviceName);
206 BluetoothDevice device = Mockito.spy(mockDevice);
208 discoveryService.deviceDiscovered(device);
210 Mockito.verify(device, Mockito.timeout(TIMEOUT).times(1)).connect();
211 Mockito.verify(device, Mockito.timeout(TIMEOUT).times(1)).readCharacteristic(
212 ArgumentMatchers.argThat(ch -> ch.getGattCharacteristic() == GattCharacteristic.DEVICE_NAME));
213 Mockito.verify(device, Mockito.timeout(TIMEOUT).times(1)).disconnect();
215 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingDiscovered(
216 ArgumentMatchers.same(discoveryService),
217 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)
218 && arg.getThingUID().getId().equals(deviceName)));
222 public void multiDiscoverySingleConnectionTest() {
223 Mockito.doReturn(true).when(participant1).requiresConnection(ArgumentMatchers.any());
224 BluetoothAddress address = TestUtils.randomAddress();
226 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
227 MockBluetoothAdapter mockAdapter2 = new MockBluetoothAdapter();
228 MockBluetoothDevice mockDevice1 = mockAdapter1.getDevice(address);
229 MockBluetoothDevice mockDevice2 = mockAdapter2.getDevice(address);
230 String deviceName = RandomStringUtils.randomAlphanumeric(10);
231 mockDevice1.setDeviceName(deviceName);
232 mockDevice2.setDeviceName(deviceName);
234 BluetoothDevice device1 = Mockito.spy(mockDevice1);
235 BluetoothDevice device2 = Mockito.spy(mockDevice2);
237 discoveryService.deviceDiscovered(device1);
239 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingDiscovered(
240 ArgumentMatchers.same(discoveryService),
241 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)
242 && mockAdapter1.getUID().equals(arg.getBridgeUID())
243 && arg.getThingUID().getId().equals(deviceName)));
245 Mockito.verify(device1, Mockito.times(1)).connect();
246 Mockito.verify(device1, Mockito.times(1)).readCharacteristic(
247 ArgumentMatchers.argThat(ch -> ch.getGattCharacteristic() == GattCharacteristic.DEVICE_NAME));
248 Mockito.verify(device1, Mockito.times(1)).disconnect();
250 discoveryService.deviceDiscovered(device2);
252 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingDiscovered(
253 ArgumentMatchers.same(discoveryService),
254 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)
255 && mockAdapter2.getUID().equals(arg.getBridgeUID())
256 && arg.getThingUID().getId().equals(deviceName)));
258 Mockito.verify(device2, Mockito.never()).connect();
259 Mockito.verify(device2, Mockito.never()).readCharacteristic(
260 ArgumentMatchers.argThat(ch -> ch.getGattCharacteristic() == GattCharacteristic.DEVICE_NAME));
261 Mockito.verify(device2, Mockito.never()).disconnect();
265 public void nonConnectionParticipantTest() {
266 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
267 MockBluetoothDevice mockDevice = mockAdapter1.getDevice(TestUtils.randomAddress());
268 String deviceName = RandomStringUtils.randomAlphanumeric(10);
269 mockDevice.setDeviceName(deviceName);
271 BluetoothDevice device = Mockito.spy(mockDevice);
273 discoveryService.deviceDiscovered(device);
275 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingDiscovered(
276 ArgumentMatchers.same(discoveryService),
277 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant1.typeUID)
278 && !arg.getThingUID().getId().equals(deviceName)));
279 Mockito.verify(device, Mockito.never()).connect();
280 Mockito.verify(device, Mockito.never()).readCharacteristic(
281 ArgumentMatchers.argThat(ch -> ch.getGattCharacteristic() == GattCharacteristic.DEVICE_NAME));
282 Mockito.verify(device, Mockito.never()).disconnect();
286 public void defaultResultTest() {
287 Mockito.doReturn(null).when(participant1).createResult(ArgumentMatchers.any());
288 BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
289 BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
290 discoveryService.deviceDiscovered(device);
292 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1))
293 .thingDiscovered(ArgumentMatchers.same(discoveryService), ArgumentMatchers
294 .argThat(arg -> arg.getThingTypeUID().equals(BluetoothBindingConstants.THING_TYPE_BEACON)));
298 public void removeDefaultDeviceTest() {
299 Mockito.doReturn(null).when(participant1).createResult(ArgumentMatchers.any());
300 BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
301 BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
302 discoveryService.deviceDiscovered(device);
303 discoveryService.deviceRemoved(device);
305 ArgumentCaptor<DiscoveryResult> resultCaptor = ArgumentCaptor.forClass(DiscoveryResult.class);
306 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1))
307 .thingDiscovered(ArgumentMatchers.same(discoveryService), resultCaptor.capture());
309 DiscoveryResult result = resultCaptor.getValue();
311 Assert.assertEquals(BluetoothBindingConstants.THING_TYPE_BEACON, result.getThingTypeUID());
313 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingRemoved(
314 ArgumentMatchers.same(discoveryService),
315 ArgumentMatchers.argThat(arg -> arg.equals(result.getThingUID())));
319 public void removeUpdatedDefaultDeviceTest() {
320 Mockito.doReturn(null).when(participant1).createResult(ArgumentMatchers.any());
321 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
322 MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
323 discoveryService.deviceDiscovered(device);
324 device.setName("somename");
325 discoveryService.deviceDiscovered(device);
327 ArgumentCaptor<DiscoveryResult> resultCaptor = ArgumentCaptor.forClass(DiscoveryResult.class);
328 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2))
329 .thingDiscovered(ArgumentMatchers.same(discoveryService), resultCaptor.capture());
331 DiscoveryResult result = resultCaptor.getValue();
333 Assert.assertEquals(BluetoothBindingConstants.THING_TYPE_BEACON, result.getThingTypeUID());
335 discoveryService.deviceRemoved(device);
337 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingRemoved(
338 ArgumentMatchers.same(discoveryService),
339 ArgumentMatchers.argThat(arg -> arg.equals(result.getThingUID())));
343 public void bluezConnectionTimeoutTest() {
344 Mockito.doReturn(true).when(participant1).requiresConnection(ArgumentMatchers.any());
346 BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
347 BadConnectionDevice device = new BadConnectionDevice(mockAdapter1, TestUtils.randomAddress(), 100);
348 discoveryService.deviceDiscovered(device);
350 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1))
351 .thingDiscovered(ArgumentMatchers.same(discoveryService), ArgumentMatchers
352 .argThat(arg -> arg.getThingTypeUID().equals(BluetoothBindingConstants.THING_TYPE_BEACON)));
356 public void replaceOlderDiscoveryTest() {
357 Mockito.doReturn(null).when(participant1).createResult(ArgumentMatchers.any());
359 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
360 MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
362 MockDiscoveryParticipant participant2 = new MockDiscoveryParticipant() {
364 public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) {
365 Integer manufacturer = device.getManufacturerId();
366 if (manufacturer != null && manufacturer.equals(10)) {
367 // without a device name it should produce a random ThingUID
368 return super.createResult(device);
374 discoveryService.addBluetoothDiscoveryParticipant(participant2);
376 // lets start with producing a default result
377 discoveryService.deviceDiscovered(device);
379 ArgumentCaptor<DiscoveryResult> resultCaptor = ArgumentCaptor.forClass(DiscoveryResult.class);
380 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1))
381 .thingDiscovered(ArgumentMatchers.same(discoveryService), resultCaptor.capture());
383 DiscoveryResult result = resultCaptor.getValue();
385 Assert.assertEquals(BluetoothBindingConstants.THING_TYPE_BEACON, result.getThingTypeUID());
387 device.setManufacturerId(10);
389 // lets start with producing a default result
390 discoveryService.deviceDiscovered(device);
392 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingRemoved(
393 ArgumentMatchers.same(discoveryService),
394 ArgumentMatchers.argThat(arg -> arg.equals(result.getThingUID())));
396 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(1)).thingDiscovered(
397 ArgumentMatchers.same(discoveryService),
398 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant2.typeUID)));
402 public void recursiveFutureTest() throws InterruptedException {
404 * 1. deviceDiscovered(device1)
405 * 2. cause discovery to pause at participant1
406 * participant1 should make a field non-null for device1 upon unpause
407 * 3. make the same field non-null for device2
408 * 4. deviceDiscovered(device2)
409 * this discovery should be waiting for first discovery to finish
410 * 5. unpause participant
412 * - participant should only have been called once
413 * - thingDiscovered should have been called twice
415 Mockito.doReturn(null).when(participant1).createResult(ArgumentMatchers.any());
417 AtomicInteger callCount = new AtomicInteger(0);
418 final CountDownLatch pauseLatch = new CountDownLatch(1);
420 BluetoothAddress address = TestUtils.randomAddress();
421 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
422 MockBluetoothAdapter mockAdapter2 = new MockBluetoothAdapter();
423 MockBluetoothDevice mockDevice1 = mockAdapter1.getDevice(address);
424 MockBluetoothDevice mockDevice2 = mockAdapter2.getDevice(address);
425 String deviceName = RandomStringUtils.randomAlphanumeric(10);
427 MockDiscoveryParticipant participant2 = new MockDiscoveryParticipant() {
429 public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) {
432 } catch (InterruptedException e) {
435 ((BluetoothDeviceSnapshot) device).setName(deviceName);
436 callCount.incrementAndGet();
437 return super.createResult(device);
441 discoveryService.addBluetoothDiscoveryParticipant(participant2);
443 discoveryService.deviceDiscovered(mockDevice1);
444 mockDevice2.setName(deviceName);
445 discoveryService.deviceDiscovered(mockDevice2);
447 pauseLatch.countDown();
449 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2)).thingDiscovered(
450 ArgumentMatchers.same(discoveryService),
451 ArgumentMatchers.argThat(arg -> arg.getThingTypeUID().equals(participant2.typeUID)));
453 Assert.assertEquals(1, callCount.get());
457 public void roamingDiscoveryTest() {
458 RoamingDiscoveryParticipant roamingParticipant = new RoamingDiscoveryParticipant();
459 MockBluetoothAdapter roamingAdapter = roamingParticipant.roamingAdapter;
460 discoveryService.addBluetoothDiscoveryParticipant(roamingParticipant);
462 BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
463 BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
464 discoveryService.deviceDiscovered(device);
466 ArgumentCaptor<DiscoveryResult> resultCaptor = ArgumentCaptor.forClass(DiscoveryResult.class);
467 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2))
468 .thingDiscovered(ArgumentMatchers.same(discoveryService), resultCaptor.capture());
470 List<DiscoveryResult> results = resultCaptor.getAllValues();
471 DiscoveryResult result1 = results.get(0);
472 DiscoveryResult result2 = results.get(1);
474 Assert.assertNotEquals(result1.getBridgeUID(), result2.getBridgeUID());
475 Assert.assertThat(result1.getBridgeUID(), anyOf(is(mockAdapter1.getUID()), is(roamingAdapter.getUID())));
476 Assert.assertThat(result2.getBridgeUID(), anyOf(is(mockAdapter1.getUID()), is(roamingAdapter.getUID())));
477 Assert.assertEquals(result1.getThingUID().getId(), result2.getThingUID().getId());
478 Assert.assertEquals(result1.getLabel(), result2.getLabel());
479 Assert.assertEquals(result1.getRepresentationProperty(), result2.getRepresentationProperty());
483 public void roamingDiscoveryRetractionTest() {
484 RoamingDiscoveryParticipant roamingParticipant = new RoamingDiscoveryParticipant();
485 MockBluetoothAdapter roamingAdapter = roamingParticipant.roamingAdapter;
486 discoveryService.addBluetoothDiscoveryParticipant(roamingParticipant);
488 MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter();
489 MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress());
490 discoveryService.deviceDiscovered(device);
491 device.setName("dasf");
492 discoveryService.deviceDiscovered(device);
494 ArgumentCaptor<ThingUID> resultCaptor = ArgumentCaptor.forClass(ThingUID.class);
495 Mockito.verify(mockDiscoveryListener, Mockito.timeout(TIMEOUT).times(2))
496 .thingRemoved(ArgumentMatchers.same(discoveryService), resultCaptor.capture());
498 List<ThingUID> results = resultCaptor.getAllValues();
499 ThingUID result1 = results.get(0);
500 ThingUID result2 = results.get(1);
502 Assert.assertNotEquals(result1.getBridgeIds(), result2.getBridgeIds());
503 Assert.assertThat(result1.getBridgeIds().get(0),
504 anyOf(is(mockAdapter1.getUID().getId()), is(roamingAdapter.getUID().getId())));
505 Assert.assertThat(result2.getBridgeIds().get(0),
506 anyOf(is(mockAdapter1.getUID().getId()), is(roamingAdapter.getUID().getId())));
507 Assert.assertEquals(result1.getId(), result2.getId());
510 private class RoamingDiscoveryParticipant implements BluetoothDiscoveryParticipant {
512 private MockBluetoothAdapter roamingAdapter = new MockBluetoothAdapter();
515 public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
516 return Collections.emptySet();
520 public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) {
525 public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device) {
530 public void publishAdditionalResults(DiscoveryResult result,
531 BiConsumer<BluetoothAdapter, DiscoveryResult> publisher) {
532 publisher.accept(roamingAdapter, result);
536 private class MockDiscoveryParticipant implements BluetoothDiscoveryParticipant {
538 private ThingTypeUID typeUID;
540 public MockDiscoveryParticipant() {
541 this.typeUID = new ThingTypeUID("mock", RandomStringUtils.randomAlphabetic(6));
545 public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
546 return Collections.singleton(typeUID);
550 public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) {
551 return DiscoveryResultBuilder.create(getThingUID(device)).withLabel(RandomStringUtils.randomAlphabetic(6))
552 .withRepresentationProperty(RandomStringUtils.randomAlphabetic(6))
553 .withBridge(device.getAdapter().getUID()).build();
557 public @NonNull ThingUID getThingUID(BluetoothDiscoveryDevice device) {
558 String id = device.getName() != null ? device.getName() : RandomStringUtils.randomAlphabetic(6);
559 return new ThingUID(typeUID, device.getAdapter().getUID(), id);
563 private class BadConnectionDevice extends MockBluetoothDevice {
565 private int sleepTime;
567 public BadConnectionDevice(BluetoothAdapter adapter, BluetoothAddress address, int sleepTime) {
568 super(adapter, address);
569 this.sleepTime = sleepTime;
573 public boolean connect() {
574 notifyListeners(BluetoothEventType.CONNECTION_STATE,
575 new BluetoothConnectionStatusNotification(ConnectionState.CONNECTED));
577 Thread.sleep(sleepTime);
578 } catch (InterruptedException e) {
581 notifyListeners(BluetoothEventType.CONNECTION_STATE,
582 new BluetoothConnectionStatusNotification(ConnectionState.DISCONNECTED));