Wait for thing-type available in PersistentInbox (#2981)

Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
J-N-K 2022-07-17 21:15:48 +02:00 committed by GitHub
parent 603988a963
commit 836ae89489
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 236 additions and 23 deletions

View File

@ -13,6 +13,7 @@
package org.openhab.core.config.discovery.inbox;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -57,7 +58,7 @@ public interface Inbox {
* @param result the discovery result to be added to this inbox (could be null)
* @return true if the specified discovery result could be added or updated, otherwise false
*/
boolean add(@Nullable DiscoveryResult result);
CompletableFuture<Boolean> add(@Nullable DiscoveryResult result);
/**
* Removes the {@link DiscoveryResult} associated with the specified {@code Thing} ID from

View File

@ -26,9 +26,11 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -140,6 +142,8 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
private final Storage<DiscoveryResult> discoveryResultStorage;
private final Map<DiscoveryResult, Class<?>> resultDiscovererMap = new ConcurrentHashMap<>();
private @NonNullByDefault({}) ScheduledFuture<?> timeToLiveChecker;
private @NonNullByDefault({}) ScheduledFuture<?> delayedDiscoveryResultProcessor;
private @Nullable EventPublisher eventPublisher;
private final List<ThingHandlerFactory> thingHandlerFactories = new CopyOnWriteArrayList<>();
@ -163,8 +167,11 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
protected void activate() {
discoveryServiceRegistry.addDiscoveryListener(this);
thingRegistry.addRegistryChangeListener(this);
timeToLiveChecker = ThreadPoolManager.getScheduledPool("discovery")
.scheduleWithFixedDelay(new TimeToLiveCheckingThread(this), 0, 30, TimeUnit.SECONDS);
ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool("discovery");
timeToLiveChecker = scheduler.scheduleWithFixedDelay(new TimeToLiveCheckingThread(this), 0, 30,
TimeUnit.SECONDS);
delayedDiscoveryResultProcessor = scheduler.scheduleWithFixedDelay(
() -> Set.copyOf(delayedDiscoveryResults.values()).forEach(this::internalAdd), 0, 15, TimeUnit.SECONDS);
}
@Deactivate
@ -173,6 +180,8 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
discoveryServiceRegistry.removeDiscoveryListener(this);
listeners.clear();
timeToLiveChecker.cancel(true);
delayedDiscoveryResultProcessor.cancel(true);
delayedDiscoveryResults.values().forEach(dr -> dr.future.complete(false));
}
@Override
@ -219,14 +228,47 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
return newThing;
}
private Map<ThingUID, DiscoveryResultWrapper> delayedDiscoveryResults = new ConcurrentHashMap<>();
@Override
public synchronized boolean add(final @Nullable DiscoveryResult discoveryResult) throws IllegalStateException {
public synchronized CompletableFuture<Boolean> add(final @Nullable DiscoveryResult discoveryResult)
throws IllegalStateException {
if (discoveryResult == null) {
return false;
return CompletableFuture.completedFuture(false);
}
CompletableFuture<Boolean> future = new CompletableFuture<>();
internalAdd(new DiscoveryResultWrapper(discoveryResult, future));
return future;
}
private void internalAdd(DiscoveryResultWrapper discoveryResultWrapper) {
DiscoveryResult discoveryResult = discoveryResultWrapper.discoveryResult;
// if we already have a result for the same ThingUID that is not added yet, delete it from the delayed map
delayedDiscoveryResults.remove(discoveryResult.getThingUID());
ThingType thingType = thingTypeRegistry.getThingType(discoveryResult.getThingTypeUID());
List<String> configurationParameters = thingType != null ? getConfigDescParams(thingType).stream()
.map(ConfigDescriptionParameter::getName).collect(Collectors.toList()) : List.of();
if (thingType == null) {
discoveryResultWrapper.retryCount++;
if (discoveryResultWrapper.retryCount >= 20) {
logger.info(
"ThingTypeUID {} for discovery result with ThingUID {} not found, retried 20 times, aborting",
discoveryResult.getThingTypeUID(), discoveryResult.getThingUID());
discoveryResultWrapper.future.complete(false);
} else {
logger.trace(
"ThingTypeUID {} for discovery result with ThingUID {} not found, delaying add, retry {}/20",
discoveryResult.getThingTypeUID(), discoveryResult.getThingUID(),
discoveryResultWrapper.retryCount);
delayedDiscoveryResults.put(discoveryResult.getThingUID(), discoveryResultWrapper);
}
return;
}
List<String> configurationParameters = getConfigDescParams(thingType).stream()
.map(ConfigDescriptionParameter::getName).collect(Collectors.toList());
discoveryResult.normalizePropertiesOnConfigDescription(configurationParameters);
@ -240,7 +282,7 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
discoveryResultStorage.put(discoveryResult.getThingUID().toString(), discoveryResult);
notifyListeners(discoveryResult, EventType.ADDED);
logger.info("Added new thing '{}' to inbox.", thingUID);
return true;
discoveryResultWrapper.future.complete(true);
} else {
if (inboxResult instanceof DiscoveryResultImpl) {
DiscoveryResultImpl resultImpl = (DiscoveryResultImpl) inboxResult;
@ -248,7 +290,7 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
discoveryResultStorage.put(discoveryResult.getThingUID().toString(), resultImpl);
notifyListeners(resultImpl, EventType.UPDATED);
logger.debug("Updated discovery result for '{}'.", thingUID);
return true;
discoveryResultWrapper.future.complete(true);
} else {
logger.warn("Cannot synchronize result with implementation class '{}'.",
inboxResult.getClass().getName());
@ -269,7 +311,7 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
}
}
return false;
discoveryResultWrapper.future.complete(false);
}
private boolean synchronizeConfiguration(ThingTypeUID thingTypeUID, Map<String, Object> properties,
@ -377,9 +419,11 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
@Override
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
if (add(result)) {
resultDiscovererMap.put(result, source.getClass());
}
add(result).thenAccept(success -> {
if (success) {
resultDiscovererMap.put(result, source.getClass());
}
});
}
@Override
@ -606,6 +650,13 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
.scheduleWithFixedDelay(new TimeToLiveCheckingThread(this), 0, interval, TimeUnit.SECONDS);
}
void setDiscoveryResultAddRetryInterval(int interval) {
delayedDiscoveryResultProcessor.cancel(true);
delayedDiscoveryResultProcessor = ThreadPoolManager.getScheduledPool("discovery").scheduleWithFixedDelay(
() -> Set.copyOf(delayedDiscoveryResults.values()).forEach(this::internalAdd), 0, interval,
TimeUnit.SECONDS);
}
@Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
protected void setEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
@ -623,4 +674,15 @@ public final class PersistentInbox implements Inbox, DiscoveryListener, ThingReg
protected void removeThingHandlerFactory(ThingHandlerFactory thingHandlerFactory) {
this.thingHandlerFactories.remove(thingHandlerFactory);
}
private static class DiscoveryResultWrapper {
public final CompletableFuture<Boolean> future;
public final DiscoveryResult discoveryResult;
public int retryCount = 0;
public DiscoveryResultWrapper(DiscoveryResult discoveryResult, CompletableFuture<Boolean> future) {
this.discoveryResult = discoveryResult;
this.future = future;
}
}
}

View File

@ -84,9 +84,12 @@ public class PersistentInboxTest {
private @Mock @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistryMock;
private @Mock @NonNullByDefault({}) ConfigDescriptionRegistry configDescriptionRegistryMock;
private @Mock @NonNullByDefault({}) ThingHandlerFactory thingHandlerFactoryMock;
private @Mock @NonNullByDefault({}) ThingType thingTypeMock;
@BeforeEach
public void setup() {
when(thingTypeMock.getConfigDescriptionURI()).thenReturn(null);
when(thingTypeRegistryMock.getThingType(any())).thenReturn(thingTypeMock);
when(storageServiceMock.getStorage(any(String.class), any(ClassLoader.class))).thenReturn(storageMock);
doAnswer(invocation -> lastAddedThing = (Thing) invocation.getArguments()[0]).when(thingRegistryMock)
.add(any(Thing.class));

View File

@ -29,10 +29,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openhab.core.config.discovery.inbox.Inbox;
import org.openhab.core.config.discovery.test.DummyThingTypeProvider;
import org.openhab.core.test.java.JavaOSGiTest;
import org.openhab.core.thing.ThingRegistry;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.type.ThingTypeBuilder;
import org.osgi.framework.ServiceRegistration;
/**
@ -56,12 +58,18 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
private static final String ANY_BINDING_ID_1 = "any2BindingId1";
private static final String ANY_THING_TYPE_1 = "any2ThingType1";
private static final ThingTypeUID ANY_BINDING_ID_1_ANY_THING_TYPE_1_UID = new ThingTypeUID(ANY_BINDING_ID_1,
ANY_THING_TYPE_1);
private static final String ANY_BINDING_ID_2 = "any2BindingId2";
private static final String ANY_THING_TYPE_2 = "any2ThingType2";
private static final ThingTypeUID ANY_BINDING_ID_2_ANY_THING_TYPE_2_UID = new ThingTypeUID(ANY_BINDING_ID_2,
ANY_THING_TYPE_2);
private static final String ANY_BINDING_ID_3 = "any2BindingId3";
private static final String ANY_THING_TYPE_3 = "any2ThingType3";
private static final ThingTypeUID ANY_BINDING_ID_3_ANY_THING_TYPE_3_UID = new ThingTypeUID(ANY_BINDING_ID_3,
ANY_THING_TYPE_3);
private static final ThingUID BRIDGE_UID_1 = new ThingUID(ANY_BINDING_ID_3, "bridge", "1");
private static final ThingUID BRIDGE_UID_2 = new ThingUID(ANY_BINDING_ID_3, "bridge", "2");
@ -88,20 +96,30 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
private @Mock @NonNullByDefault({}) DiscoveryListener discoveryListenerMock;
private @NonNullByDefault({}) DummyThingTypeProvider dummyThingTypeProvider;
@BeforeEach
public void beforeEach() {
registerVolatileStorageService();
dummyThingTypeProvider = new DummyThingTypeProvider();
registerService(dummyThingTypeProvider);
dummyThingTypeProvider.add(ANY_BINDING_ID_1_ANY_THING_TYPE_1_UID,
ThingTypeBuilder.instance(ANY_BINDING_ID_1_ANY_THING_TYPE_1_UID, "label1").build());
dummyThingTypeProvider.add(ANY_BINDING_ID_2_ANY_THING_TYPE_2_UID,
ThingTypeBuilder.instance(ANY_BINDING_ID_2_ANY_THING_TYPE_2_UID, "label2").build());
dummyThingTypeProvider.add(ANY_BINDING_ID_3_ANY_THING_TYPE_3_UID,
ThingTypeBuilder.instance(ANY_BINDING_ID_3_ANY_THING_TYPE_3_UID, "label3").build());
thingRegistry = getService(ThingRegistry.class);
assertNotNull(thingRegistry);
inbox = getService(Inbox.class);
assertNotNull(inbox);
discoveryServiceMockForBinding1 = new DiscoveryServiceMock(new ThingTypeUID(ANY_BINDING_ID_1, ANY_THING_TYPE_1),
1);
discoveryServiceMockForBinding2 = new DiscoveryServiceMock(new ThingTypeUID(ANY_BINDING_ID_2, ANY_THING_TYPE_2),
3);
discoveryServiceMockForBinding1 = new DiscoveryServiceMock(ANY_BINDING_ID_1_ANY_THING_TYPE_1_UID, 1);
discoveryServiceMockForBinding2 = new DiscoveryServiceMock(ANY_BINDING_ID_2_ANY_THING_TYPE_2_UID, 3);
discoveryServiceMockForBinding3Bridge1 = new DiscoveryServiceMockOfBridge(
new ThingTypeUID(ANY_BINDING_ID_3, ANY_THING_TYPE_3), 1, BRIDGE_UID_1);
@ -270,7 +288,7 @@ public class DiscoveryServiceRegistryOSGiTest extends JavaOSGiTest {
ScanListener mockScanListener1 = mock(ScanListener.class);
discoveryServiceRegistry.addDiscoveryListener(discoveryListenerMock);
discoveryServiceRegistry.startScan(new ThingTypeUID(ANY_BINDING_ID_3, ANY_THING_TYPE_3), mockScanListener1);
discoveryServiceRegistry.startScan(ANY_BINDING_ID_3_ANY_THING_TYPE_3_UID, mockScanListener1);
waitForAssert(() -> verify(mockScanListener1, times(1)).onFinished());
verify(discoveryListenerMock, times(2)).thingDiscovered(any(), any());

View File

@ -31,6 +31,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -54,6 +56,7 @@ import org.openhab.core.config.discovery.inbox.InboxListener;
import org.openhab.core.config.discovery.inbox.events.InboxAddedEvent;
import org.openhab.core.config.discovery.inbox.events.InboxRemovedEvent;
import org.openhab.core.config.discovery.inbox.events.InboxUpdatedEvent;
import org.openhab.core.config.discovery.test.DummyThingTypeProvider;
import org.openhab.core.events.Event;
import org.openhab.core.events.EventFilter;
import org.openhab.core.events.EventSubscriber;
@ -140,7 +143,7 @@ public class InboxOSGiTest extends JavaOSGiTest {
private final String discoveryResultLabel = "MyLabel";
@SuppressWarnings("serial")
private final Map<String, Object> discoveryResultProperties = new LinkedHashMap<String, Object>() {
private final Map<String, Object> discoveryResultProperties = new LinkedHashMap<>() {
{
put("ip", "192.168.3.99");
put("pnr", 1234455);
@ -172,6 +175,10 @@ public class InboxOSGiTest extends JavaOSGiTest {
private @NonNullByDefault({}) ManagedThingProvider managedThingProvider;
private @NonNullByDefault({}) ThingRegistry registry;
private @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistry;
private @NonNullByDefault({}) DummyThingTypeProvider dummyThingTypeProvider;
@BeforeEach
public void setUp() {
registerVolatileStorageService();
@ -179,6 +186,16 @@ public class InboxOSGiTest extends JavaOSGiTest {
discoveryResults.clear();
inboxListeners.clear();
dummyThingTypeProvider = new DummyThingTypeProvider();
registerService(dummyThingTypeProvider);
dummyThingTypeProvider.add(testTypeUID, testThingType);
dummyThingTypeProvider.add(THING_TYPE_UID, testThingType);
dummyThingTypeProvider.add(BRIDGE_THING_TYPE_UID, testThingType);
thingTypeRegistry = getService(ThingTypeRegistry.class);
assertThat(thingTypeRegistry, is(notNullValue()));
inbox = (PersistentInbox) getService(Inbox.class);
assertThat(inbox, is(notNullValue()));
@ -237,11 +254,15 @@ public class InboxOSGiTest extends JavaOSGiTest {
}
private boolean addDiscoveryResult(DiscoveryResult discoveryResult) {
boolean result = inbox.add(discoveryResult);
if (result) {
discoveryResults.put(discoveryResult.getThingUID(), discoveryResult);
CompletableFuture<Boolean> future = inbox.add(discoveryResult);
waitForAssert(() -> assertThat(future.isDone(), is(true)));
try {
return future.get();
} catch (ExecutionException | InterruptedException ignored) {
}
return result;
return false;
}
private boolean removeDiscoveryResult(ThingUID thingUID) {
@ -261,6 +282,7 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatGetAllIncludesPreviouslyAddedDiscoveryResult() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -294,6 +316,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatGetAllIncludesPreviouslyUpdatedDiscoveryResult() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -335,6 +359,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatGetAllIncludesTwoPreviouslyAddedDiscoveryResults() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -358,6 +384,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatGetAllNotIncludesRemovedDiscoveryResult() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -384,6 +412,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatGetAllIncludesRemovedUpdatedDiscoveryResult() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -423,6 +453,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatInboxListenerIsNotifiedAboutPreviouslyAddedDiscoveryResult() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -488,6 +520,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatInboxListenerIsNotifiedAboutPreviouslyUpdatedDiscoveryResult() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -560,6 +594,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatInboxListenerIsNotifiedAboutPreviouslyRemovedDiscoveryResult() {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
List<DiscoveryResult> allDiscoveryResults = inbox.getAll();
@ -628,6 +664,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
assertThat(inbox.getAll().size(), is(0));
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
Map<String, Object> props = new HashMap<>();
@ -653,6 +691,7 @@ public class InboxOSGiTest extends JavaOSGiTest {
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId", "dummyThingType");
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
managedThingProvider.add(ThingBuilder.create(thingTypeUID, "dummyThingId").build());
@ -673,6 +712,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
assertThat(inbox.getAll().size(), is(0));
ThingTypeUID thingTypeUID = new ThingTypeUID("dummyBindingId2", "dummyThingType");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "dummyThingId");
managedThingProvider.add(ThingBuilder.create(thingTypeUID, "dummyThingId").build());
@ -699,6 +740,8 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
public void assertThatInboxEventSubscribersReceiveEventsAboutDiscoveryResultChanges() {
ThingTypeUID thingTypeUID = new ThingTypeUID("some", "thing");
dummyThingTypeProvider.add(thingTypeUID, testThingType);
ThingUID thingUID = new ThingUID(thingTypeUID, "uid");
final AsyncResultWrapper<Event> receivedEvent = new AsyncResultWrapper<>();
@ -914,6 +957,7 @@ public class InboxOSGiTest extends JavaOSGiTest {
@Test
@SuppressWarnings("null")
public void assertThatApproveSetsTheDiscoveredLabelIfNoOtherIsGiven() {
inbox.add(testDiscoveryResult);
Thing approvedThing = inbox.approve(testThing.getUID(), null, null);
Thing addedThing = registry.get(testThing.getUID());
@ -1025,6 +1069,40 @@ public class InboxOSGiTest extends JavaOSGiTest {
assertThat(inbox.getAll().size(), is(0));
}
@Test
public void assertThatResultWithMissingThingTypeNotAdded() throws ExecutionException, InterruptedException {
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId", "missingThingType");
ThingUID thingUID = new ThingUID("bindingId", "missingThingType", "thingId");
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID).build();
// reduce time between retries to ensure the test does not time out
inbox.setDiscoveryResultAddRetryInterval(1);
CompletableFuture future = inbox.add(discoveryResult);
waitForAssert(() -> future.isDone(), 30, 5);
assertThat(future.get(), is(false));
}
@Test
public void assertThatResultWithLaterAddedThingTypeIsAdded() throws ExecutionException, InterruptedException {
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId", "missingThingType");
ThingUID thingUID = new ThingUID("bindingId", "missingThingType", "thingId");
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID).build();
// reduce time between retries to ensure the test does not time out
inbox.setDiscoveryResultAddRetryInterval(1);
CompletableFuture future = inbox.add(discoveryResult);
dummyThingTypeProvider.add(thingTypeUID, ThingTypeBuilder.instance(thingTypeUID, "label").build());
waitForAssert(() -> future.isDone(), 30, 5);
assertThat(future.get(), is(true));
}
class DummyThingHandlerFactory extends BaseThingHandlerFactory {
public DummyThingHandlerFactory(ComponentContext context) {

View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.config.discovery.test;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.ThingTypeProvider;
import org.openhab.core.thing.type.ThingType;
import org.osgi.service.component.annotations.Component;
/**
* The {@link DummyThingTypeProvider} is used in tests to provide thing types
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
@Component(immediate = true)
public class DummyThingTypeProvider implements ThingTypeProvider {
private final Map<ThingTypeUID, ThingType> thingTypeMap = new HashMap<>();
@Override
public Collection<ThingType> getThingTypes(@Nullable Locale locale) {
return thingTypeMap.values();
}
@Override
public @Nullable ThingType getThingType(ThingTypeUID thingTypeUID, @Nullable Locale locale) {
return thingTypeMap.get(thingTypeUID);
}
public void add(ThingTypeUID thingTypeUID, ThingType thingType) {
thingTypeMap.put(thingTypeUID, thingType);
}
}