mirror of
https://github.com/danieldemus/openhab-core.git
synced 2026-07-29 12:34:22 +02:00
Refactor ThingManagerImpl (#3330)
* Refactor ThingManagerImpl This - moves config description URI to type-base class - decouples the thing manager from bundle loading - makes sure that all thing/channel-types and config descriptions are available when the thing is initialized - enables thing type updates Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
+81
-65
@@ -166,7 +166,7 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
// check getBridge works
|
||||
assertThat(getBridge().getUID().toString(), is("bindingId:type1:bridgeId"));
|
||||
assertThat(getBridge().getUID().toString(), is(BINDING_ID + ":type1:bridgeId"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -206,12 +206,17 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
|
||||
ThingTypeUID bridgeTypeUID = new ThingTypeUID("bindingId:type1");
|
||||
ThingUID bridgeUID = new ThingUID("bindingId:type1:bridgeId");
|
||||
ThingTypeUID bridgeTypeUID = new ThingTypeUID(BINDING_ID, "type1");
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, "type2");
|
||||
|
||||
ThingType bridgeType = ThingTypeBuilder.instance(bridgeTypeUID, "bridge").buildBridge();
|
||||
ThingType thingType = ThingTypeBuilder.instance(thingTypeUID, "thing").build();
|
||||
registerThingTypeProvider(bridgeType, thingType);
|
||||
|
||||
ThingUID bridgeUID = new ThingUID(BINDING_ID, "type1", "bridgeId");
|
||||
Bridge bridge = BridgeBuilder.create(bridgeTypeUID, bridgeUID).build();
|
||||
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type2");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type2:thingId");
|
||||
ThingUID thingUID = new ThingUID(BINDING_ID, "type2", "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID).withBridge(bridge.getUID()).build();
|
||||
|
||||
managedThingProvider.add(bridge);
|
||||
@@ -234,7 +239,7 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
});
|
||||
|
||||
// the assertion is in handle command
|
||||
handler.handleCommand(new ChannelUID("bindingId:type2:thingId:channel"), RefreshType.REFRESH);
|
||||
handler.handleCommand(new ChannelUID(thingUID, "thingId", "channel"), RefreshType.REFRESH);
|
||||
|
||||
unregisterService(ThingHandlerFactory.class.getName());
|
||||
thingHandlerFactory.deactivate(componentContextMock);
|
||||
@@ -245,10 +250,12 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
ConfigStatusProviderThingHandlerFactory thingHandlerFactory = new ConfigStatusProviderThingHandlerFactory();
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
registerDefaultThingTypeAndConfigDescription();
|
||||
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type:thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID).build();
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID)
|
||||
.withConfiguration(new Configuration(Map.of("parameter", ""))).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
@@ -301,10 +308,12 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
ConfigStatusProviderThingHandlerFactory thingHandlerFactory = new ConfigStatusProviderThingHandlerFactory();
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
registerDefaultThingTypeAndConfigDescription();
|
||||
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type:thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID).build();
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID)
|
||||
.withConfiguration(new Configuration(Map.of("parameter", "ok"))).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
@@ -329,30 +338,30 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
thing.getHandler().handleConfigurationUpdate(Map.of("param", "invalid"));
|
||||
thing.getHandler().handleConfigurationUpdate(Map.of("parameter", "invalid"));
|
||||
|
||||
waitForAssert(() -> {
|
||||
Event event = eventSubscriber.getReceivedEvent();
|
||||
assertThat(event, is(notNullValue()));
|
||||
assertThat(event.getPayload(), CoreMatchers
|
||||
.containsString("\"parameterName\":\"param\",\"type\":\"ERROR\",\"message\":\"param invalid\"}"));
|
||||
assertThat(event.getPayload(), CoreMatchers.containsString(
|
||||
"\"parameterName\":\"parameter\",\"type\":\"ERROR\",\"message\":\"param invalid\"}"));
|
||||
eventSubscriber.resetReceivedEvent();
|
||||
}, 2500, DFL_SLEEP_TIME);
|
||||
|
||||
thing.getHandler().handleConfigurationUpdate(Map.of("param", "ok"));
|
||||
thing.getHandler().handleConfigurationUpdate(Map.of("parameter", "ok"));
|
||||
|
||||
waitForAssert(() -> {
|
||||
Event event = eventSubscriber.getReceivedEvent();
|
||||
assertThat(event, is(notNullValue()));
|
||||
assertThat(event.getPayload(), CoreMatchers
|
||||
.containsString("\"parameterName\":\"param\",\"type\":\"INFORMATION\",\"message\":\"param ok\"}"));
|
||||
assertThat(event.getPayload(), CoreMatchers.containsString(
|
||||
"\"parameterName\":\"parameter\",\"type\":\"INFORMATION\",\"message\":\"param ok\"}"));
|
||||
}, 2500, DFL_SLEEP_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertBaseThingHandlerNotifiesThingManagerAboutConfigurationUpdates() {
|
||||
// register ThingTypeProvider & ConfigurationDescription with 'required' parameter
|
||||
registerThingTypeProvider();
|
||||
registerDefaultThingTypeProvider();
|
||||
registerConfigDescriptionProvider(true);
|
||||
|
||||
// register thing handler factory
|
||||
@@ -396,7 +405,7 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
|
||||
static class ConfigStatusProviderThingHandler extends ConfigStatusThingHandler {
|
||||
|
||||
private static final String PARAM = "param";
|
||||
private static final String PARAM = "parameter";
|
||||
private static final ConfigStatusMessage ERROR = ConfigStatusMessage.Builder.error(PARAM)
|
||||
.withMessageKeySuffix("param.invalid").build();
|
||||
private static final ConfigStatusMessage INFO = ConfigStatusMessage.Builder.information(PARAM)
|
||||
@@ -448,7 +457,7 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
public void initialize() {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withChannel(
|
||||
ChannelBuilder.create(new ChannelUID("bindingId:type:thingId:1"), CoreItemFactory.STRING).build());
|
||||
ChannelBuilder.create(new ChannelUID(thing.getUID(), "1"), CoreItemFactory.STRING).build());
|
||||
updateThing(thingBuilder.build());
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
@@ -493,18 +502,21 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
|
||||
@Test
|
||||
public void assertThingCanBeUpdatedFromThingHandler() {
|
||||
registerThingTypeProvider();
|
||||
registerDefaultThingTypeProvider();
|
||||
YetAnotherThingHandlerFactory thingHandlerFactory = new YetAnotherThingHandlerFactory();
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
|
||||
final ThingRegistryChangeListener listener = new ThingRegistryChangeListener();
|
||||
|
||||
registerDefaultThingTypeAndConfigDescription();
|
||||
|
||||
try {
|
||||
thingRegistry.addRegistryChangeListener(listener);
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type:thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID).build();
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID)
|
||||
.withConfiguration(new Configuration(Map.of("parameter", ""))).build();
|
||||
assertThat(thing.getChannels().size(), is(0));
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
@@ -522,17 +534,20 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
|
||||
@Test
|
||||
public void assertPropertiesCanBeUpdatedFromThingHandler() {
|
||||
registerThingTypeProvider();
|
||||
registerDefaultThingTypeProvider();
|
||||
YetAnotherThingHandlerFactory thingHandlerFactory = new YetAnotherThingHandlerFactory();
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
registerDefaultThingTypeAndConfigDescription();
|
||||
|
||||
final ThingRegistryChangeListener listener = new ThingRegistryChangeListener();
|
||||
|
||||
try {
|
||||
thingRegistry.addRegistryChangeListener(listener);
|
||||
Thing thing = ThingBuilder
|
||||
.create(new ThingTypeUID("bindingId:type"), new ThingUID("bindingId:type:thingId")).build();
|
||||
.create(new ThingTypeUID(BINDING_ID, THING_TYPE_ID),
|
||||
new ThingUID(BINDING_ID, THING_TYPE_ID, "thingId"))
|
||||
.withConfiguration(new Configuration(Map.of("parameter", ""))).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
@@ -577,10 +592,12 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
|
||||
final ThingRegistryChangeListener listener = new ThingRegistryChangeListener();
|
||||
|
||||
registerDefaultThingTypeAndConfigDescription();
|
||||
|
||||
try {
|
||||
thingRegistry.addRegistryChangeListener(listener);
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type:thingId");
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
@@ -601,11 +618,11 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(true);
|
||||
registerDefaultThingTypeProvider();
|
||||
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type:thingId");
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID)
|
||||
.withConfiguration(new Configuration(Map.of("parameter", "someValue"))).build();
|
||||
|
||||
@@ -624,11 +641,11 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerDefaultThingTypeProvider();
|
||||
registerConfigDescriptionProvider(true);
|
||||
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type:thingId");
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID)
|
||||
.withConfiguration(new Configuration(Map.of("parameter", "someValue"))).build();
|
||||
|
||||
@@ -658,12 +675,12 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
|
||||
registerThingTypeAndConfigDescription();
|
||||
registerDefaultThingTypeAndConfigDescription();
|
||||
|
||||
ThingRegistry thingRegistry = getService(ThingRegistry.class);
|
||||
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID("bindingId:type");
|
||||
ThingUID thingUID = new ThingUID("bindingId:type:thingId");
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, "thingId");
|
||||
Thing thing = ThingBuilder.create(thingTypeUID, thingUID).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
@@ -694,13 +711,17 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
thingHandlerFactory.activate(componentContextMock);
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
|
||||
ThingTypeUID thingType1 = new ThingTypeUID("bindingId:type1");
|
||||
ThingTypeUID thingType2 = new ThingTypeUID("bindingId:type2");
|
||||
ThingTypeUID thingTypeUID1 = new ThingTypeUID(BINDING_ID, "type1");
|
||||
ThingTypeUID thingTypeUID2 = new ThingTypeUID(BINDING_ID, "type2");
|
||||
|
||||
Bridge bridge = BridgeBuilder.create(thingType1, new ThingUID("bindingId:type1:bridgeId")).build();
|
||||
Thing thingA = ThingBuilder.create(thingType2, new ThingUID("bindingId:type2:thingIdA"))
|
||||
ThingType thingType1 = ThingTypeBuilder.instance(thingTypeUID1, thingTypeUID1.getId()).build();
|
||||
ThingType thingType2 = ThingTypeBuilder.instance(thingTypeUID2, thingTypeUID2.getId()).build();
|
||||
registerThingTypeProvider(thingType1, thingType2);
|
||||
|
||||
Bridge bridge = BridgeBuilder.create(thingTypeUID1, new ThingUID(thingTypeUID1, "bridgeId")).build();
|
||||
Thing thingA = ThingBuilder.create(thingTypeUID2, new ThingUID(thingTypeUID2, "thingIdA"))
|
||||
.withBridge(bridge.getUID()).build();
|
||||
Thing thingB = ThingBuilder.create(thingType2, new ThingUID("bindingId:type2:thingIdB"))
|
||||
Thing thingB = ThingBuilder.create(thingTypeUID2, new ThingUID(thingTypeUID2, "thingIdB"))
|
||||
.withBridge(bridge.getUID()).build();
|
||||
|
||||
assertThat(bridge.getStatus(), is(ThingStatus.UNINITIALIZED));
|
||||
@@ -751,40 +772,35 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerThingTypeAndConfigDescription() {
|
||||
ThingType thingType = ThingTypeBuilder.instance(new ThingTypeUID(BINDING_ID, THING_TYPE_ID), "label")
|
||||
.withConfigDescriptionURI(BINDING_CONFIG_URI).build();
|
||||
private void registerDefaultThingTypeAndConfigDescription() {
|
||||
registerDefaultThingTypeProvider();
|
||||
ConfigDescription configDescription = ConfigDescriptionBuilder.create(BINDING_CONFIG_URI)
|
||||
.withParameter(ConfigDescriptionParameterBuilder
|
||||
.create("parameter", ConfigDescriptionParameter.Type.TEXT).withRequired(true).build())
|
||||
.build();
|
||||
|
||||
ThingTypeProvider thingTypeProvider = mock(ThingTypeProvider.class);
|
||||
when(thingTypeProvider.getThingType(ArgumentMatchers.any(ThingTypeUID.class),
|
||||
ArgumentMatchers.any(Locale.class))).thenReturn(thingType);
|
||||
registerService(thingTypeProvider);
|
||||
|
||||
ThingTypeRegistry thingTypeRegistry = mock(ThingTypeRegistry.class);
|
||||
when(thingTypeRegistry.getThingType(ArgumentMatchers.any(ThingTypeUID.class))).thenReturn(thingType);
|
||||
registerService(thingTypeRegistry);
|
||||
|
||||
ConfigDescriptionProvider configDescriptionProvider = mock(ConfigDescriptionProvider.class);
|
||||
when(configDescriptionProvider.getConfigDescription(ArgumentMatchers.any(URI.class),
|
||||
ArgumentMatchers.nullable(Locale.class))).thenReturn(configDescription);
|
||||
when(configDescriptionProvider.getConfigDescription(eq(BINDING_CONFIG_URI), nullable(Locale.class)))
|
||||
.thenReturn(configDescription);
|
||||
registerService(configDescriptionProvider);
|
||||
}
|
||||
|
||||
private void registerThingTypeProvider() {
|
||||
private void registerDefaultThingTypeProvider() {
|
||||
ThingType thingType = ThingTypeBuilder.instance(new ThingTypeUID(BINDING_ID, THING_TYPE_ID), "label")
|
||||
.withConfigDescriptionURI(BINDING_CONFIG_URI).build();
|
||||
registerThingTypeProvider(thingType);
|
||||
}
|
||||
|
||||
private void registerThingTypeProvider(ThingType... thingTypes) {
|
||||
ThingTypeProvider thingTypeProvider = mock(ThingTypeProvider.class);
|
||||
when(thingTypeProvider.getThingType(ArgumentMatchers.any(ThingTypeUID.class),
|
||||
ArgumentMatchers.nullable(Locale.class))).thenReturn(thingType);
|
||||
registerService(thingTypeProvider);
|
||||
|
||||
ThingTypeRegistry thingTypeRegistry = mock(ThingTypeRegistry.class);
|
||||
when(thingTypeRegistry.getThingType(ArgumentMatchers.any(ThingTypeUID.class))).thenReturn(thingType);
|
||||
|
||||
for (ThingType thingType : thingTypes) {
|
||||
when(thingTypeProvider.getThingType(eq(thingType.getUID()), nullable(Locale.class))).thenReturn(thingType);
|
||||
when(thingTypeRegistry.getThingType(eq(thingType.getUID()))).thenReturn(thingType);
|
||||
}
|
||||
|
||||
registerService(thingTypeProvider);
|
||||
registerService(thingTypeRegistry);
|
||||
}
|
||||
|
||||
@@ -796,8 +812,8 @@ public class BindingBaseClassesOSGiTest extends JavaOSGiTest {
|
||||
.build();
|
||||
|
||||
ConfigDescriptionProvider configDescriptionProvider = mock(ConfigDescriptionProvider.class);
|
||||
when(configDescriptionProvider.getConfigDescription(ArgumentMatchers.any(URI.class),
|
||||
ArgumentMatchers.nullable(Locale.class))).thenReturn(configDescription);
|
||||
when(configDescriptionProvider.getConfigDescription(ArgumentMatchers.any(URI.class), nullable(Locale.class)))
|
||||
.thenReturn(configDescription);
|
||||
registerService(configDescriptionProvider);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -437,13 +437,17 @@ public class ChangeThingTypeOSGiTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
private List<ChannelDefinition> getChannelDefinitions(ThingTypeUID thingTypeUID) throws URISyntaxException {
|
||||
URI configDescriptionUri = new URI("scheme", "channelType:" + thingTypeUID.getId(), null);
|
||||
ChannelTypeUID channelTypeUID = new ChannelTypeUID("test:" + thingTypeUID.getId());
|
||||
ChannelType channelType = ChannelTypeBuilder.state(channelTypeUID, "channelLabel", "itemType")
|
||||
.withDescription("description") //
|
||||
.withCategory("category") //
|
||||
.withConfigDescriptionURI(new URI("scheme", "channelType:" + thingTypeUID.getId(), null)).build();
|
||||
.withConfigDescriptionURI(configDescriptionUri).build();
|
||||
channelTypes.put(channelTypeUID, channelType);
|
||||
|
||||
ConfigDescription configDescription = ConfigDescriptionBuilder.create(configDescriptionUri).build();
|
||||
configDescriptions.put(configDescriptionUri, configDescription);
|
||||
|
||||
ChannelDefinition cd = new ChannelDefinitionBuilder("channel" + thingTypeUID.getId(), channelTypeUID).build();
|
||||
return List.of(cd);
|
||||
}
|
||||
|
||||
+19
@@ -39,9 +39,13 @@ import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingTypeProvider;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
|
||||
import org.openhab.core.thing.testutil.i18n.DefaultLocaleSetter;
|
||||
import org.openhab.core.thing.type.ThingType;
|
||||
import org.openhab.core.thing.type.ThingTypeBuilder;
|
||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
import org.osgi.framework.Bundle;
|
||||
@@ -88,6 +92,8 @@ public class ThingStatusInfoI18nLocalizationServiceOSGiTest extends JavaOSGiTest
|
||||
simpleThingHandlerFactory.activate(componentContext);
|
||||
registerService(simpleThingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
|
||||
registerThingType();
|
||||
|
||||
thing = ThingBuilder.create(new ThingTypeUID("aaa:bbb"), "ccc").build();
|
||||
|
||||
managedThingProvider = getService(ManagedThingProvider.class);
|
||||
@@ -330,4 +336,17 @@ public class ThingStatusInfoI18nLocalizationServiceOSGiTest extends JavaOSGiTest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerThingType() {
|
||||
ThingType thingType = ThingTypeBuilder.instance(new ThingTypeUID("aaa:bbb"), "label").build();
|
||||
|
||||
ThingTypeProvider thingTypeProvider = mock(ThingTypeProvider.class);
|
||||
ThingTypeRegistry thingTypeRegistry = mock(ThingTypeRegistry.class);
|
||||
|
||||
when(thingTypeProvider.getThingType(eq(thingType.getUID()), nullable(Locale.class))).thenReturn(thingType);
|
||||
when(thingTypeRegistry.getThingType(eq(thingType.getUID()))).thenReturn(thingType);
|
||||
|
||||
registerService(thingTypeProvider);
|
||||
registerService(thingTypeRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
+38
-6
@@ -17,12 +17,15 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -38,6 +41,8 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.core.common.registry.RegistryChangeListener;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
@@ -59,6 +64,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingTypeProvider;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.events.AbstractThingRegistryEvent;
|
||||
@@ -71,7 +77,14 @@ import org.openhab.core.thing.link.dto.ItemChannelLinkDTO;
|
||||
import org.openhab.core.thing.link.events.AbstractItemChannelLinkRegistryEvent;
|
||||
import org.openhab.core.thing.link.events.ItemChannelLinkRemovedEvent;
|
||||
import org.openhab.core.thing.type.ChannelKind;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeProvider;
|
||||
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.thing.type.ThingType;
|
||||
import org.openhab.core.thing.type.ThingTypeBuilder;
|
||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.thing.util.ThingHandlerHelper;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
@@ -85,6 +98,7 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Wouter Born - Initial contribution
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
@NonNullByDefault
|
||||
public class ChannelLinkNotifierOSGiTest extends JavaOSGiTest {
|
||||
|
||||
@@ -162,6 +176,7 @@ public class ChannelLinkNotifierOSGiTest extends JavaOSGiTest {
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
registerVolatileStorageService();
|
||||
registerThingAndChannelTypeProvider();
|
||||
|
||||
itemChannelLinkRegistry = getService(ItemChannelLinkRegistry.class);
|
||||
assertThat(itemChannelLinkRegistry, is(notNullValue()));
|
||||
@@ -184,14 +199,8 @@ public class ChannelLinkNotifierOSGiTest extends JavaOSGiTest {
|
||||
when(thingHandlerFactoryMock.supportsThingType(eq(THING_TYPE_UID))).thenReturn(true);
|
||||
registerService(thingHandlerFactoryMock);
|
||||
|
||||
when(bundleMock.getSymbolicName()).thenReturn("org.openhab.core.thing");
|
||||
when(bundleResolverMock.resolveBundle(any())).thenReturn(bundleMock);
|
||||
|
||||
ThingManagerImpl thingManager = (ThingManagerImpl) getService(ThingManager.class);
|
||||
assertThat(thingManager, is(notNullValue()));
|
||||
if (thingManager != null) {
|
||||
thingManager.setBundleResolver(bundleResolverMock);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -560,4 +569,27 @@ public class ChannelLinkNotifierOSGiTest extends JavaOSGiTest {
|
||||
assertNoChannelLinkEventsReceived(subjectThing);
|
||||
assertNoChannelLinkEventsReceived(otherThing);
|
||||
}
|
||||
|
||||
private void registerThingAndChannelTypeProvider() {
|
||||
ThingType thingType = ThingTypeBuilder.instance(THING_TYPE_UID, "label").build();
|
||||
|
||||
ThingTypeProvider thingTypeProvider = mock(ThingTypeProvider.class);
|
||||
when(thingTypeProvider.getThingType(any(ThingTypeUID.class), nullable(Locale.class))).thenReturn(thingType);
|
||||
registerService(thingTypeProvider);
|
||||
|
||||
ThingTypeRegistry thingTypeRegistry = mock(ThingTypeRegistry.class);
|
||||
when(thingTypeRegistry.getThingType(any(ThingTypeUID.class))).thenReturn(thingType);
|
||||
registerService(thingTypeRegistry);
|
||||
|
||||
ChannelType channelType = ChannelTypeBuilder.state(CHANNEL_TYPE_UID, "Number", "Number").build();
|
||||
|
||||
ChannelTypeProvider channelTypeProvider = mock(ChannelTypeProvider.class);
|
||||
when(channelTypeProvider.getChannelType(any(ChannelTypeUID.class), nullable(Locale.class)))
|
||||
.thenReturn(channelType);
|
||||
registerService(channelTypeProvider);
|
||||
|
||||
ChannelTypeRegistry channelTypeRegistry = mock(ChannelTypeRegistry.class);
|
||||
when(channelTypeRegistry.getChannelType(any(ChannelTypeUID.class))).thenReturn(channelType);
|
||||
registerService(channelTypeRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
+89
-26
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.*;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Semaphore;
|
||||
@@ -112,6 +113,8 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
CHANNEL_GROUP_ID);
|
||||
|
||||
private static final ThingTypeUID THING_TYPE_UID = new ThingTypeUID("binding:thing");
|
||||
private static final ThingTypeUID THING_WITH_BRIDGE_TYPE_UID = new ThingTypeUID("binding:thingWithBridge");
|
||||
|
||||
private static final ThingUID THING_UID = new ThingUID(THING_TYPE_UID, "thing");
|
||||
|
||||
private static final ThingTypeUID BRIDGE_TYPE_UID = new ThingTypeUID("binding:bridge");
|
||||
@@ -127,6 +130,7 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
private @NonNullByDefault({}) ThingRegistry thingRegistry;
|
||||
private @NonNullByDefault({}) ReadyService readyService;
|
||||
private @NonNullByDefault({}) Storage<Boolean> storage;
|
||||
|
||||
private @NonNullByDefault({}) ThingManager thingManager;
|
||||
|
||||
private @NonNullByDefault({}) URI configDescriptionChannel;
|
||||
@@ -137,6 +141,12 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
public void setUp() throws Exception {
|
||||
configDescriptionChannel = new URI("test:channel");
|
||||
configDescriptionThing = new URI("test:test");
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerChannelTypeProvider();
|
||||
registerChannelGroupTypeProvider();
|
||||
registerConfigDescriptions();
|
||||
|
||||
thing = ThingBuilder.create(THING_TYPE_UID, THING_UID).withChannels(List.of( //
|
||||
ChannelBuilder.create(CHANNEL_UID, CoreItemFactory.SWITCH).withLabel("Test Label")
|
||||
.withDescription("Test Description").withType(CHANNEL_TYPE_UID)
|
||||
@@ -187,8 +197,56 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializeCallsThingUpdated() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
public void testMissingBridgePreventsInitialization() {
|
||||
registerThingHandlerFactory(THING_WITH_BRIDGE_TYPE_UID, thing -> new BaseThingHandler(thing) {
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
});
|
||||
|
||||
Thing thing = ThingBuilder.create(THING_WITH_BRIDGE_TYPE_UID, THING_UID).build();
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
waitForAssert(() -> {
|
||||
assertEquals(ThingStatus.UNINITIALIZED, thing.getStatus());
|
||||
assertEquals(ThingStatusDetail.HANDLER_CONFIGURATION_PENDING, thing.getStatusInfo().getStatusDetail(),
|
||||
thing.getStatusInfo().toString());
|
||||
});
|
||||
|
||||
managedThingProvider.remove(thing.getUID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExistingBridgeAllowsInitialization() {
|
||||
registerThingHandlerFactory(THING_WITH_BRIDGE_TYPE_UID, thing -> new BaseThingHandler(thing) {
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
});
|
||||
|
||||
Thing thing = ThingBuilder.create(THING_WITH_BRIDGE_TYPE_UID, THING_UID).withBridge(BRIDGE_UID).build();
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
waitForAssert(() -> {
|
||||
assertEquals(ThingStatus.UNINITIALIZED, thing.getStatus());
|
||||
assertEquals(ThingStatusDetail.BRIDGE_UNINITIALIZED, thing.getStatusInfo().getStatusDetail());
|
||||
});
|
||||
|
||||
managedThingProvider.remove(thing.getUID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializeCallsThingUpdated() {
|
||||
AtomicReference<ThingHandlerCallback> thc = new AtomicReference<>();
|
||||
AtomicReference<Boolean> initializeRunning = new AtomicReference<>(false);
|
||||
registerThingHandlerFactory(THING_TYPE_UID, thing -> {
|
||||
@@ -325,9 +383,7 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializeOnlyIfInitializable() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
registerChannelTypeProvider();
|
||||
public void testInitializeOnlyIfInitializable() {
|
||||
registerThingHandlerFactory(THING_TYPE_UID, thing -> new BaseThingHandler(thing) {
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
@@ -563,9 +619,7 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetEnabledWithHandler() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
|
||||
public void testSetEnabledWithHandler() {
|
||||
AtomicReference<ThingHandlerCallback> thingHandlerCallback = new AtomicReference<>();
|
||||
AtomicReference<Boolean> initializeInvoked = new AtomicReference<>(false);
|
||||
AtomicReference<Boolean> disposeInvoked = new AtomicReference<>(false);
|
||||
@@ -640,8 +694,6 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
|
||||
@Test
|
||||
public void testSetEnabledWithoutHandlerFactory() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
|
||||
ThingStatusInfo thingStatusInfo = ThingStatusInfoBuilder
|
||||
.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
|
||||
thing.setStatusInfo(thingStatusInfo);
|
||||
@@ -732,9 +784,7 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisposeNotInvokedOnAlreadyDisabledThing() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
|
||||
public void testDisposeNotInvokedOnAlreadyDisabledThing() {
|
||||
AtomicReference<ThingHandlerCallback> thingHandlerCallback = new AtomicReference<>();
|
||||
AtomicReference<Boolean> initializeInvoked = new AtomicReference<>(false);
|
||||
AtomicReference<Boolean> disposeInvoked = new AtomicReference<>(false);
|
||||
@@ -809,9 +859,7 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateThing() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
|
||||
public void testUpdateThing() {
|
||||
AtomicReference<ThingHandlerCallback> thingHandlerCallback = new AtomicReference<>();
|
||||
AtomicReference<Boolean> initializeInvoked = new AtomicReference<>(false);
|
||||
AtomicReference<Boolean> disposeInvoked = new AtomicReference<>(false);
|
||||
@@ -897,9 +945,7 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStorageEntryRetainedOnThingRemoval() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
|
||||
public void testStorageEntryRetainedOnThingRemoval() {
|
||||
AtomicReference<ThingHandlerCallback> thingHandlerCallback = new AtomicReference<>();
|
||||
AtomicReference<Boolean> initializeInvoked = new AtomicReference<>(false);
|
||||
AtomicReference<Boolean> disposeInvoked = new AtomicReference<>(false);
|
||||
@@ -1002,28 +1048,37 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
registerService(mockThingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
}
|
||||
|
||||
private void registerThingTypeProvider() throws Exception {
|
||||
private void registerThingTypeProvider() {
|
||||
ThingType thingType = ThingTypeBuilder.instance(THING_TYPE_UID, "label")
|
||||
.withConfigDescriptionURI(configDescriptionThing)
|
||||
.withChannelDefinitions(List.of(new ChannelDefinitionBuilder(CHANNEL_ID, CHANNEL_TYPE_UID).build()))
|
||||
.build();
|
||||
ThingType thingTypeWithBridge = ThingTypeBuilder.instance(THING_WITH_BRIDGE_TYPE_UID, "label")
|
||||
.withConfigDescriptionURI(configDescriptionThing)
|
||||
.withSupportedBridgeTypeUIDs(List.of(BRIDGE_TYPE_UID.getId()))
|
||||
.withChannelDefinitions(List.of(new ChannelDefinitionBuilder(CHANNEL_ID, CHANNEL_TYPE_UID).build()))
|
||||
.build();
|
||||
ThingType bridgeType = ThingTypeBuilder.instance(BRIDGE_TYPE_UID, "label").buildBridge();
|
||||
|
||||
ThingTypeProvider mockThingTypeProvider = mock(ThingTypeProvider.class);
|
||||
when(mockThingTypeProvider.getThingType(eq(THING_TYPE_UID), any())).thenReturn(thingType);
|
||||
when(mockThingTypeProvider.getThingType(eq(THING_WITH_BRIDGE_TYPE_UID), any())).thenReturn(thingTypeWithBridge);
|
||||
when(mockThingTypeProvider.getThingType(eq(BRIDGE_TYPE_UID), any())).thenReturn(bridgeType);
|
||||
|
||||
registerService(mockThingTypeProvider);
|
||||
}
|
||||
|
||||
private void registerChannelTypeProvider() throws Exception {
|
||||
private void registerChannelTypeProvider() {
|
||||
ChannelType channelType = ChannelTypeBuilder.state(CHANNEL_TYPE_UID, "Test Label", CoreItemFactory.SWITCH)
|
||||
.withDescription("Test Description").withCategory("Test Category").withTag("Test Tag")
|
||||
.withConfigDescriptionURI(new URI("test:channel")).build();
|
||||
.withConfigDescriptionURI(URI.create("test:channel")).build();
|
||||
|
||||
ChannelTypeProvider mockChannelTypeProvider = mock(ChannelTypeProvider.class);
|
||||
when(mockChannelTypeProvider.getChannelType(eq(CHANNEL_TYPE_UID), any())).thenReturn(channelType);
|
||||
registerService(mockChannelTypeProvider);
|
||||
}
|
||||
|
||||
private void registerChannelGroupTypeProvider() throws Exception {
|
||||
private void registerChannelGroupTypeProvider() {
|
||||
ChannelGroupType channelGroupType = ChannelGroupTypeBuilder.instance(CHANNEL_GROUP_TYPE_UID, "Test Group Label")
|
||||
.withDescription("Test Group Description").withCategory("Test Group Category")
|
||||
.withChannelDefinitions(List.of(new ChannelDefinitionBuilder(CHANNEL_ID, CHANNEL_TYPE_UID).build(),
|
||||
@@ -1064,9 +1119,6 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
};
|
||||
|
||||
private AtomicReference<ThingHandlerCallback> initializeThingHandlerCallback() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
registerChannelTypeProvider();
|
||||
registerChannelGroupTypeProvider();
|
||||
AtomicReference<ThingHandlerCallback> thc = new AtomicReference<>();
|
||||
ThingHandlerFactory thingHandlerFactory = new BaseThingHandlerFactory() {
|
||||
@Override
|
||||
@@ -1093,4 +1145,15 @@ public class ThingManagerOSGiJavaTest extends JavaOSGiTest {
|
||||
});
|
||||
return thc;
|
||||
}
|
||||
|
||||
private void registerConfigDescriptions() {
|
||||
ConfigDescriptionProvider configDescriptionProvider = mock(ConfigDescriptionProvider.class);
|
||||
|
||||
when(configDescriptionProvider.getConfigDescription(eq(configDescriptionThing), nullable(Locale.class)))
|
||||
.thenReturn(ConfigDescriptionBuilder.create(configDescriptionThing).build());
|
||||
when(configDescriptionProvider.getConfigDescription(eq(configDescriptionChannel), nullable(Locale.class)))
|
||||
.thenReturn(ConfigDescriptionBuilder.create(configDescriptionChannel).build());
|
||||
|
||||
registerService(configDescriptionProvider);
|
||||
}
|
||||
}
|
||||
|
||||
+69
-82
@@ -58,8 +58,8 @@ import org.openhab.core.library.items.StringItem;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.service.ReadyMarker;
|
||||
import org.openhab.core.service.ReadyMarkerUtils;
|
||||
import org.openhab.core.service.ReadyService;
|
||||
import org.openhab.core.service.StartLevelService;
|
||||
import org.openhab.core.test.java.JavaOSGiTest;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
@@ -100,9 +100,6 @@ import org.openhab.core.thing.type.ThingTypeBuilder;
|
||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.service.cm.ConfigurationAdmin;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
|
||||
@@ -169,27 +166,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
readyService = getService(ReadyService.class);
|
||||
assertNotNull(readyService);
|
||||
|
||||
waitForAssert(() -> {
|
||||
try {
|
||||
assertThat(
|
||||
bundleContext
|
||||
.getServiceReferences(ReadyMarker.class,
|
||||
"(" + ThingManagerImpl.XML_THING_TYPE + "="
|
||||
+ bundleContext.getBundle().getSymbolicName() + ")"),
|
||||
is(notNullValue()));
|
||||
} catch (InvalidSyntaxException e) {
|
||||
fail("Failed to get service reference: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
Bundle bundle = mock(Bundle.class);
|
||||
when(bundle.getSymbolicName()).thenReturn("org.openhab.core.thing");
|
||||
|
||||
BundleResolver bundleResolver = mock(BundleResolver.class);
|
||||
when(bundleResolver.resolveBundle(any())).thenReturn(bundle);
|
||||
|
||||
ThingManagerImpl thingManager = (ThingManagerImpl) getService(ThingTypeMigrationService.class);
|
||||
thingManager.setBundleResolver(bundleResolver);
|
||||
assertNotNull(thingManager);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -199,6 +177,33 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
when(componentContext.getProperties()).thenReturn(new Hashtable<>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thingManagerHonorsMissingPrerequisite() {
|
||||
// set ready marker, otherwise check job is not running
|
||||
ThingManagerImpl thingManager = (ThingManagerImpl) getService(ThingManager.class);
|
||||
thingManager.onReadyMarkerAdded(new ReadyMarker(StartLevelService.STARTLEVEL_MARKER_TYPE,
|
||||
Integer.toString(StartLevelService.STARTLEVEL_MODEL)));
|
||||
|
||||
ThingHandler thingHandler = mock(ThingHandler.class);
|
||||
when(thingHandler.getThing()).thenReturn(thing);
|
||||
|
||||
ThingHandlerFactory thingHandlerFactory = mock(ThingHandlerFactory.class);
|
||||
when(thingHandlerFactory.supportsThingType(any(ThingTypeUID.class))).thenReturn(true);
|
||||
when(thingHandlerFactory.registerHandler(any(Thing.class))).thenReturn(thingHandler);
|
||||
|
||||
registerService(thingHandlerFactory);
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
assertThat(thing.getStatus(), is(ThingStatus.UNINITIALIZED));
|
||||
assertThat(thing.getStatusInfo().getStatusDetail(), is(ThingStatusDetail.NOT_YET_READY));
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.INITIALIZING)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("null")
|
||||
public void thingManagerChangesTheThingType() {
|
||||
@@ -231,6 +236,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerChangesTheThingTypeCorrectlyEvenIfInitializeTakesLongAndCalledFromThere() {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
ThingTypeUID newThingTypeUID = new ThingTypeUID("binding:type2");
|
||||
|
||||
@@ -317,6 +323,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerWaitsWithThingUpdatedUntilInitializeReturned() {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
Thing thing2 = ThingBuilder.create(THING_TYPE_UID, THING_UID)
|
||||
.withChannels(List.of(ChannelBuilder.create(CHANNEL_UID, CoreItemFactory.SWITCH).build())).build();
|
||||
@@ -379,6 +386,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
when(thingHandlerFactory.registerHandler(any(Thing.class))).thenReturn(thingHandler);
|
||||
|
||||
registerService(thingHandlerFactory);
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
@@ -395,6 +404,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
when(thingHandlerFactory.registerHandler(any(Thing.class))).thenReturn(thingHandler);
|
||||
|
||||
registerService(thingHandlerFactory);
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
managedThingProvider.remove(thing.getUID());
|
||||
@@ -442,6 +453,9 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
|
||||
assertThat(thing.getStatusInfo(), is(uninitializedNone));
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
// add thing - provokes handler registration & initialization
|
||||
managedThingProvider.add(thing);
|
||||
waitForAssert(() -> verify(thingHandlerFactory, times(1)).registerHandler(thing));
|
||||
@@ -521,6 +535,9 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
|
||||
assertThat(testThing.getStatusInfo(), is(uninitializedNone));
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(testThing);
|
||||
final ThingStatusInfo uninitializedError = ThingStatusInfoBuilder
|
||||
.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.HANDLER_INITIALIZING_ERROR)
|
||||
@@ -684,6 +701,9 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
ThingRegistry thingRegistry = getService(ThingRegistry.class);
|
||||
assertThat(thingRegistry, not(nullValue()));
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
// add thing - no thing initialization, because bridge is not available
|
||||
thingRegistry.add(thing);
|
||||
waitForAssert(() -> assertThat(thingState.initCalled, is(false)));
|
||||
@@ -767,6 +787,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerDoesNotDelegateUpdateEventsToItsSource() {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
class ThingHandlerState {
|
||||
boolean handleCommandWasCalled;
|
||||
@@ -829,6 +850,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerHandlesStateUpdatesCorrectly() {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
class ThingHandlerState {
|
||||
boolean thingUpdatedWasCalled;
|
||||
@@ -931,6 +953,9 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
ThingHandlerCallback callback;
|
||||
}
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
final ThingHandlerState state = new ThingHandlerState();
|
||||
|
||||
ThingHandler thingHandler = mock(ThingHandler.class);
|
||||
@@ -1000,6 +1025,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
final ThingHandlerState state = new ThingHandlerState();
|
||||
|
||||
ThingHandler thingHandler = mock(ThingHandler.class);
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
@@ -1048,6 +1075,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerHandlesThingStatusUpdatesUninitializedAndInitializingCorrectly() {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
ThingHandler thingHandler = mock(ThingHandler.class);
|
||||
when(thingHandler.getThing()).thenReturn(thing);
|
||||
@@ -1078,6 +1106,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerHandlesThingStatusUpdatesRemovingAndInitializingCorrectly() {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
ThingHandler thingHandler = mock(ThingHandler.class);
|
||||
when(thingHandler.getThing()).thenReturn(thing);
|
||||
@@ -1111,6 +1140,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
when(thingHandlerFactory.registerHandler(any(Thing.class))).thenThrow(new RuntimeException(exceptionMessage));
|
||||
|
||||
registerService(thingHandlerFactory);
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
@@ -1124,6 +1155,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@SuppressWarnings({ "null", "unchecked" })
|
||||
public void thingManagerHandlesThingUpdatesCorrectly() {
|
||||
String itemName = "name";
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
managedItemChannelLinkProvider.add(new ItemChannelLink(itemName, CHANNEL_UID));
|
||||
@@ -1196,6 +1229,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerPostsThingStatusEventsIfTheStatusOfAThingIsUpdated() {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
class ThingHandlerState {
|
||||
@Nullable
|
||||
@@ -1283,6 +1317,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@Test
|
||||
public void thingManagerPostsThingStatusChangedEventsIfTheStatusOfAThingIsChanged() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
class ThingHandlerState {
|
||||
@Nullable
|
||||
@@ -1355,6 +1390,7 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
@SuppressWarnings("null")
|
||||
public void thingManagerPostsLocalizedThingStatusInfoAndThingStatusInfoChangedEvents() throws Exception {
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
class ThingHandlerState {
|
||||
@Nullable
|
||||
@@ -1573,64 +1609,6 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("null")
|
||||
public void thingManagerWaitsWithInitializeUntilBundleProcessingIsFinished() throws Exception {
|
||||
Thing thing = ThingBuilder.create(THING_TYPE_UID, THING_UID).build();
|
||||
|
||||
class ThingHandlerState {
|
||||
@SuppressWarnings("unused")
|
||||
@Nullable
|
||||
ThingHandlerCallback callback;
|
||||
}
|
||||
final ThingHandlerState state = new ThingHandlerState();
|
||||
|
||||
ThingHandler thingHandler = mock(ThingHandler.class);
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public @Nullable Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
state.callback = (ThingHandlerCallback) invocation.getArgument(0);
|
||||
return null;
|
||||
}
|
||||
}).when(thingHandler).setCallback(any(ThingHandlerCallback.class));
|
||||
when(thingHandler.getThing()).thenReturn(thing);
|
||||
|
||||
ThingHandlerFactory thingHandlerFactory = mock(ThingHandlerFactory.class);
|
||||
when(thingHandlerFactory.supportsThingType(any(ThingTypeUID.class))).thenReturn(true);
|
||||
when(thingHandlerFactory.registerHandler(any(Thing.class))).thenReturn(thingHandler);
|
||||
|
||||
registerService(thingHandlerFactory);
|
||||
|
||||
final ReadyMarker marker = new ReadyMarker(ThingManagerImpl.XML_THING_TYPE,
|
||||
ReadyMarkerUtils.getIdentifier(FrameworkUtil.getBundle(this.getClass())));
|
||||
waitForAssert(() -> {
|
||||
// wait for the XML processing to be finished, then remove the ready marker again
|
||||
assertThat(readyService.isReady(marker), is(true));
|
||||
readyService.unmarkReady(marker);
|
||||
});
|
||||
|
||||
ThingStatusInfo uninitializedNone = ThingStatusInfoBuilder
|
||||
.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
|
||||
assertThat(thing.getStatusInfo(), is(uninitializedNone));
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
// just wait a little to make sure really nothing happens
|
||||
Thread.sleep(1000);
|
||||
verify(thingHandler, never()).initialize();
|
||||
assertThat(thing.getStatusInfo(), is(uninitializedNone));
|
||||
|
||||
readyService.markReady(marker);
|
||||
|
||||
// ThingHandler.initialize() called, thing status is INITIALIZING.NONE
|
||||
ThingStatusInfo initializingNone = ThingStatusInfoBuilder
|
||||
.create(ThingStatus.INITIALIZING, ThingStatusDetail.NONE).build();
|
||||
waitForAssert(() -> {
|
||||
verify(thingHandler, times(1)).initialize();
|
||||
assertThat(thing.getStatusInfo(), is(initializingNone));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("null")
|
||||
public void thingManagerCallsBridgeStatusChangedOnThingHandlerCorrectly() {
|
||||
@@ -1719,6 +1697,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
}).when(thingHandlerFactory).registerHandler(any(Thing.class));
|
||||
|
||||
registerService(thingHandlerFactory);
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(bridge);
|
||||
managedThingProvider.add(thing);
|
||||
@@ -1859,6 +1839,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
}
|
||||
}).when(thingHandlerFactory).registerHandler(any(Thing.class));
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
registerService(thingHandlerFactory);
|
||||
|
||||
managedThingProvider.add(bridge);
|
||||
@@ -1985,6 +1967,8 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
}
|
||||
}).when(thingHandlerFactory).registerHandler(any(Thing.class));
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
registerService(thingHandlerFactory);
|
||||
|
||||
managedThingProvider.add(bridge);
|
||||
@@ -2016,6 +2000,9 @@ public class ThingManagerOSGiTest extends JavaOSGiTest {
|
||||
}
|
||||
final ThingHandlerState state = new ThingHandlerState();
|
||||
|
||||
registerThingTypeProvider();
|
||||
registerConfigDescriptionProvider(false);
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
ThingHandler thingHandler = mock(ThingHandler.class);
|
||||
|
||||
+22
@@ -16,8 +16,13 @@ import static java.util.Map.entry;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -44,10 +49,14 @@ import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingTypeProvider;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.events.ThingAddedEvent;
|
||||
import org.openhab.core.thing.events.ThingRemovedEvent;
|
||||
import org.openhab.core.thing.events.ThingUpdatedEvent;
|
||||
import org.openhab.core.thing.type.ThingType;
|
||||
import org.openhab.core.thing.type.ThingTypeBuilder;
|
||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
@@ -76,6 +85,7 @@ public class ThingRegistryOSGiTest extends JavaOSGiTest {
|
||||
public void setUp() {
|
||||
registerVolatileStorageService();
|
||||
managedThingProvider = getService(ManagedThingProvider.class);
|
||||
registerThingTypeProvider();
|
||||
unregisterCurrentThingHandlerFactory();
|
||||
}
|
||||
|
||||
@@ -246,4 +256,16 @@ public class ThingRegistryOSGiTest extends JavaOSGiTest {
|
||||
thingHandlerFactoryServiceReg = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerThingTypeProvider() {
|
||||
ThingType thingType = ThingTypeBuilder.instance(THING_TYPE_UID, "label").build();
|
||||
|
||||
ThingTypeProvider thingTypeProvider = mock(ThingTypeProvider.class);
|
||||
when(thingTypeProvider.getThingType(any(ThingTypeUID.class), nullable(Locale.class))).thenReturn(thingType);
|
||||
registerService(thingTypeProvider);
|
||||
|
||||
ThingTypeRegistry thingTypeRegistry = mock(ThingTypeRegistry.class);
|
||||
when(thingTypeRegistry.getThingType(any(ThingTypeUID.class))).thenReturn(thingType);
|
||||
registerService(thingTypeRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
+384
@@ -0,0 +1,384 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.thing.internal.update;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.openhab.core.thing.internal.ThingManagerImpl.PROPERTY_THING_TYPE_VERSION;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.service.ReadyService;
|
||||
import org.openhab.core.test.SyntheticBundleInstaller;
|
||||
import org.openhab.core.test.java.JavaOSGiTest;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ManagedThingProvider;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingTypeProvider;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeProvider;
|
||||
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.thing.type.ThingType;
|
||||
import org.openhab.core.thing.type.ThingTypeBuilder;
|
||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.Constants;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Tests for {@link ThingUpdateInstructionReader} and {@link ThingUpdateInstruction} implementations.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
@NonNullByDefault
|
||||
public class ThingUpdateOSGiTest extends JavaOSGiTest {
|
||||
|
||||
private static final String TEST_BUNDLE_NAME = "thingUpdateTest.bundle";
|
||||
private static final String BINDING_ID = "testBinding";
|
||||
private static final ThingTypeUID ADD_CHANNEL_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "testThingTypeAdd");
|
||||
private static final ThingTypeUID UPDATE_CHANNEL_THING_TYPE_UID = new ThingTypeUID(BINDING_ID,
|
||||
"testThingTypeUpdate");
|
||||
private static final ThingTypeUID REMOVE_CHANNEL_THING_TYPE_UID = new ThingTypeUID(BINDING_ID,
|
||||
"testThingTypeRemove");
|
||||
private static final ThingTypeUID MULTIPLE_CHANNEL_THING_TYPE_UID = new ThingTypeUID(BINDING_ID,
|
||||
"testThingTypeMultiple");
|
||||
|
||||
private static final String[] ADDED_TAGS = { "Tag1", "Tag2" };
|
||||
|
||||
private static final String THING_ID = "thing";
|
||||
|
||||
private @NonNullByDefault({}) Bundle testBundle;
|
||||
private @NonNullByDefault({}) BundleResolver bundleResolver;
|
||||
private @NonNullByDefault({}) ReadyService readyService;
|
||||
private @NonNullByDefault({}) ThingRegistry thingRegistry;
|
||||
private @NonNullByDefault({}) ManagedThingProvider managedThingProvider;
|
||||
private @NonNullByDefault({}) TestThingHandlerFactory thingHandlerFactory;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach() throws Exception {
|
||||
Hashtable<String, Object> properties = new Hashtable<>();
|
||||
properties.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
|
||||
bundleResolver = new BundleResolverImpl();
|
||||
registerService(bundleResolver, BundleResolver.class.getName(), properties);
|
||||
|
||||
registerVolatileStorageService();
|
||||
|
||||
testBundle = SyntheticBundleInstaller.install(bundleContext, TEST_BUNDLE_NAME, "*.xml");
|
||||
assertThat(testBundle, is(notNullValue()));
|
||||
|
||||
readyService = getService(ReadyService.class);
|
||||
assertThat(readyService, is(notNullValue()));
|
||||
|
||||
thingRegistry = getService(ThingRegistry.class);
|
||||
assertThat(thingRegistry, is(notNullValue()));
|
||||
|
||||
managedThingProvider = getService(ManagedThingProvider.class);
|
||||
assertThat(managedThingProvider, is(notNullValue()));
|
||||
|
||||
thingHandlerFactory = new TestThingHandlerFactory();
|
||||
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() throws Exception {
|
||||
testBundle.uninstall();
|
||||
managedThingProvider.getAll().forEach(t -> managedThingProvider.remove(t.getUID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleChannelAddition() {
|
||||
registerThingType(ADD_CHANNEL_THING_TYPE_UID);
|
||||
|
||||
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, "testChannelTypeId");
|
||||
registerChannelTypes(channelTypeUID);
|
||||
|
||||
ThingUID thingUID = new ThingUID(ADD_CHANNEL_THING_TYPE_UID, THING_ID);
|
||||
Thing thing = ThingBuilder.create(ADD_CHANNEL_THING_TYPE_UID, thingUID).build();
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
Thing updatedThing = assertThing(thing, 1);
|
||||
|
||||
assertThat(updatedThing.getChannels(), hasSize(3));
|
||||
|
||||
Channel channel1 = updatedThing.getChannel("testChannel1");
|
||||
assertChannel(channel1, channelTypeUID, null, null);
|
||||
|
||||
Channel channel2 = updatedThing.getChannel("testChannel2");
|
||||
assertChannel(channel2, channelTypeUID, "Test Label", null);
|
||||
assertThat(channel2.getDefaultTags(), containsInAnyOrder(ADDED_TAGS));
|
||||
|
||||
Channel channel3 = updatedThing.getChannel("testChannel3");
|
||||
assertChannel(channel3, channelTypeUID, "Test Label", "Test Description");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleChannelUpdate() {
|
||||
registerThingType(UPDATE_CHANNEL_THING_TYPE_UID);
|
||||
|
||||
ChannelTypeUID channelTypeOldUID = new ChannelTypeUID(BINDING_ID, "testChannelOldTypeId");
|
||||
ChannelTypeUID channelTypeNewUID = new ChannelTypeUID(BINDING_ID, "testChannelNewTypeId");
|
||||
registerChannelTypes(channelTypeOldUID, channelTypeNewUID);
|
||||
|
||||
ThingUID thingUID = new ThingUID(UPDATE_CHANNEL_THING_TYPE_UID, THING_ID);
|
||||
ChannelUID channelUID1 = new ChannelUID(thingUID, "testChannel1");
|
||||
ChannelUID channelUID2 = new ChannelUID(thingUID, "testChannel2");
|
||||
Configuration channelConfig = new Configuration(Map.of("foo", "bar"));
|
||||
|
||||
Channel origChannel1 = ChannelBuilder.create(channelUID1).withType(channelTypeOldUID)
|
||||
.withConfiguration(channelConfig).build();
|
||||
Channel origChannel2 = ChannelBuilder.create(channelUID2).withType(channelTypeOldUID)
|
||||
.withConfiguration(channelConfig).build();
|
||||
|
||||
Thing thing = ThingBuilder.create(UPDATE_CHANNEL_THING_TYPE_UID, thingUID)
|
||||
.withChannels(origChannel1, origChannel2).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
Thing updatedThing = assertThing(thing, 1);
|
||||
assertThat(updatedThing.getChannels(), hasSize(2));
|
||||
|
||||
Channel channel1 = updatedThing.getChannel(channelUID1);
|
||||
assertChannel(channel1, channelTypeNewUID, "New Test Label", null);
|
||||
assertThat(channel1.getConfiguration(), is(channelConfig));
|
||||
|
||||
Channel channel2 = updatedThing.getChannel(channelUID2);
|
||||
assertChannel(channel2, channelTypeNewUID, null, null);
|
||||
assertThat(channel2.getConfiguration().getProperties(), is(anEmptyMap()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleChannelRemoval() {
|
||||
registerThingType(REMOVE_CHANNEL_THING_TYPE_UID);
|
||||
|
||||
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, "testChannelTypeId");
|
||||
registerChannelTypes(channelTypeUID);
|
||||
|
||||
ThingUID thingUID = new ThingUID(REMOVE_CHANNEL_THING_TYPE_UID, THING_ID);
|
||||
ChannelUID channelUID = new ChannelUID(thingUID, "testChannel");
|
||||
|
||||
Thing thing = ThingBuilder.create(REMOVE_CHANNEL_THING_TYPE_UID, thingUID)
|
||||
.withChannel(ChannelBuilder.create(channelUID).withType(channelTypeUID).build()).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
Thing updatedThing = assertThing(thing, 1);
|
||||
assertThat(updatedThing.getChannels(), hasSize(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleChannelUpdates() {
|
||||
registerThingType(MULTIPLE_CHANNEL_THING_TYPE_UID);
|
||||
|
||||
ChannelTypeUID channelTypeOldUID = new ChannelTypeUID(BINDING_ID, "testChannelOldTypeId");
|
||||
ChannelTypeUID channelTypeNewUID = new ChannelTypeUID(BINDING_ID, "testChannelNewTypeId");
|
||||
registerChannelTypes(channelTypeOldUID, channelTypeNewUID);
|
||||
|
||||
ThingUID thingUID = new ThingUID(MULTIPLE_CHANNEL_THING_TYPE_UID, THING_ID);
|
||||
ChannelUID channelUID0 = new ChannelUID(thingUID, "testChannel0");
|
||||
ChannelUID channelUID1 = new ChannelUID(thingUID, "testChannel1");
|
||||
|
||||
Thing thing = ThingBuilder.create(MULTIPLE_CHANNEL_THING_TYPE_UID, thingUID)
|
||||
.withChannel(ChannelBuilder.create(channelUID0).withType(channelTypeOldUID).build())
|
||||
.withChannel(ChannelBuilder.create(channelUID1).withType(channelTypeOldUID).build()).build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
Thing updatedThing = assertThing(thing, 3);
|
||||
assertThat(updatedThing.getChannels(), hasSize(2));
|
||||
|
||||
Channel channel1 = updatedThing.getChannel("testChannel1");
|
||||
assertChannel(channel1, channelTypeNewUID, "Test Label", null);
|
||||
|
||||
Channel channel2 = updatedThing.getChannel("testChannel2");
|
||||
assertChannel(channel2, channelTypeOldUID, "TestLabel", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyMatchingInstructionsUpdate() {
|
||||
registerThingType(MULTIPLE_CHANNEL_THING_TYPE_UID);
|
||||
|
||||
ChannelTypeUID channelTypeOldUID = new ChannelTypeUID(BINDING_ID, "testChannelOldTypeId");
|
||||
registerChannelTypes(channelTypeOldUID);
|
||||
|
||||
ThingUID thingUID = new ThingUID(MULTIPLE_CHANNEL_THING_TYPE_UID, THING_ID);
|
||||
ChannelUID channelUID0 = new ChannelUID(thingUID, "testChannel0");
|
||||
ChannelUID channelUID1 = new ChannelUID(thingUID, "testChannel1");
|
||||
|
||||
Thing thing = ThingBuilder.create(MULTIPLE_CHANNEL_THING_TYPE_UID, thingUID)
|
||||
.withChannel(ChannelBuilder.create(channelUID0).withType(channelTypeOldUID).build())
|
||||
.withChannel(ChannelBuilder.create(channelUID1).withType(channelTypeOldUID).build())
|
||||
.withProperty(PROPERTY_THING_TYPE_VERSION, "2").build();
|
||||
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
Thing updatedThing = assertThing(thing, 3);
|
||||
assertThat(updatedThing.getChannels(), hasSize(1));
|
||||
|
||||
Channel channel1 = updatedThing.getChannel("testChannel1");
|
||||
assertChannel(channel1, channelTypeOldUID, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotModifiedIfHigherVersion() {
|
||||
registerThingType(ADD_CHANNEL_THING_TYPE_UID);
|
||||
|
||||
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, "testChannelTypeId");
|
||||
registerChannelTypes(channelTypeUID);
|
||||
|
||||
ThingUID thingUID = new ThingUID(ADD_CHANNEL_THING_TYPE_UID, THING_ID);
|
||||
Thing thing = ThingBuilder.create(ADD_CHANNEL_THING_TYPE_UID, thingUID)
|
||||
.withProperty(PROPERTY_THING_TYPE_VERSION, "1").build();
|
||||
managedThingProvider.add(thing);
|
||||
|
||||
waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
|
||||
assertThat(thingRegistry.get(thingUID), is(sameInstance(thing)));
|
||||
assertThat(thing.getChannels(), is(emptyCollectionOf(Channel.class)));
|
||||
}
|
||||
|
||||
private Thing assertThing(Thing oldThing, int expectedNewThingTypeVersion) {
|
||||
ThingUID thingUID = oldThing.getUID();
|
||||
|
||||
waitForAssert(() -> {
|
||||
@Nullable
|
||||
Thing updatedThing = thingRegistry.get(thingUID);
|
||||
assertThat(updatedThing, is(not(sameInstance(oldThing))));
|
||||
});
|
||||
|
||||
@Nullable
|
||||
Thing updatedThing = thingRegistry.get(thingUID);
|
||||
assertThat(updatedThing.getStatus(), is(ThingStatus.ONLINE));
|
||||
|
||||
// check thing type version is upgraded
|
||||
String thingTypeVersion = updatedThing.getProperties().get(PROPERTY_THING_TYPE_VERSION);
|
||||
assertThat(thingTypeVersion, is(Integer.toString(expectedNewThingTypeVersion)));
|
||||
|
||||
return updatedThing;
|
||||
}
|
||||
|
||||
private void assertChannel(@Nullable Channel channel, ChannelTypeUID channelTypeUID, @Nullable String label,
|
||||
@Nullable String description) {
|
||||
assertThat(channel, is(notNullValue()));
|
||||
assertThat(channel.getChannelTypeUID(), is(channelTypeUID));
|
||||
if (label != null) {
|
||||
assertThat(channel.getLabel(), is(label));
|
||||
} else {
|
||||
assertThat(channel.getLabel(), is(nullValue()));
|
||||
}
|
||||
if (description != null) {
|
||||
assertThat(channel.getDescription(), is(description));
|
||||
} else {
|
||||
assertThat(channel.getDescription(), is(nullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
private void registerThingType(ThingTypeUID thingTypeUID) {
|
||||
ThingType thingType = ThingTypeBuilder.instance(thingTypeUID, "label").build();
|
||||
|
||||
ThingTypeProvider thingTypeProvider = mock(ThingTypeProvider.class);
|
||||
when(thingTypeProvider.getThingType(eq(thingTypeUID), nullable(Locale.class))).thenReturn(thingType);
|
||||
registerService(thingTypeProvider);
|
||||
|
||||
ThingTypeRegistry thingTypeRegistry = mock(ThingTypeRegistry.class);
|
||||
when(thingTypeRegistry.getThingType(eq(thingTypeUID))).thenReturn(thingType);
|
||||
registerService(thingTypeRegistry);
|
||||
}
|
||||
|
||||
private void registerChannelTypes(ChannelTypeUID... channelTypeUIDs) {
|
||||
ChannelTypeProvider channelTypeProvider = mock(ChannelTypeProvider.class);
|
||||
ChannelTypeRegistry channelTypeRegistry = mock(ChannelTypeRegistry.class);
|
||||
|
||||
for (ChannelTypeUID channelTypeUID : channelTypeUIDs) {
|
||||
ChannelType channelType = ChannelTypeBuilder.state(channelTypeUID, "label", "Number").build();
|
||||
when(channelTypeProvider.getChannelType(eq(channelTypeUID), nullable(Locale.class)))
|
||||
.thenReturn(channelType);
|
||||
when(channelTypeRegistry.getChannelType(eq(channelTypeUID))).thenReturn(channelType);
|
||||
}
|
||||
|
||||
registerService(channelTypeProvider);
|
||||
registerService(channelTypeRegistry);
|
||||
}
|
||||
|
||||
class TestThingHandlerFactory extends BaseThingHandlerFactory {
|
||||
Logger logger = LoggerFactory.getLogger(TestThingHandlerFactory.class);
|
||||
|
||||
@Override
|
||||
public void activate(final ComponentContext ctx) {
|
||||
super.activate(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
return new BaseThingHandler(thing) {
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class BundleResolverImpl implements BundleResolver {
|
||||
@Override
|
||||
public Bundle resolveBundle(@NonNullByDefault({}) Class<?> clazz) {
|
||||
// return the test bundle if the class is TestThingHandlerFactory
|
||||
if (clazz != null && clazz.equals(TestThingHandlerFactory.class)) {
|
||||
return testBundle;
|
||||
} else {
|
||||
return FrameworkUtil.getBundle(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
|
||||
|
||||
<thing-type uid="testBinding:testThingTypeMultiple">
|
||||
<instruction-set targetVersion="1">
|
||||
<update-channel id="testChannel1">
|
||||
<type>testBinding:testChannelNewTypeId</type>
|
||||
<label>Test Label</label>
|
||||
</update-channel>
|
||||
</instruction-set>
|
||||
<instruction-set targetVersion="2">
|
||||
<add-channel id="testChannel2">
|
||||
<type>testBinding:testChannelOldTypeId</type>
|
||||
<label>TestLabel</label>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
<instruction-set targetVersion="3">
|
||||
<remove-channel id="testChannel0"/>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
</update:update-descriptions>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
|
||||
|
||||
<thing-type uid="testBinding:testThingTypeAdd">
|
||||
<instruction-set targetVersion="1">
|
||||
<add-channel id="testChannel1">
|
||||
<type>testBinding:testChannelTypeId</type>
|
||||
</add-channel>
|
||||
<add-channel id="testChannel2">
|
||||
<type>testBinding:testChannelTypeId</type>
|
||||
<label>Test Label</label>
|
||||
<tags>
|
||||
<tag>Tag1</tag>
|
||||
<tag>Tag2</tag>
|
||||
</tags>
|
||||
</add-channel>
|
||||
<add-channel id="testChannel3">
|
||||
<type>testBinding:testChannelTypeId</type>
|
||||
<label>Test Label</label>
|
||||
<description>Test Description</description>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
<thing-type uid="testBinding:testThingTypeRemove">
|
||||
<instruction-set targetVersion="1">
|
||||
<remove-channel id="testChannel"/>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
<thing-type uid="testBinding:testThingTypeUpdate">
|
||||
<instruction-set targetVersion="1">
|
||||
<update-channel id="testChannel1">
|
||||
<type>testBinding:testChannelNewTypeId</type>
|
||||
<label>New Test Label</label>
|
||||
</update-channel>
|
||||
<update-channel id="testChannel2" preserveConfiguration="false">
|
||||
<type>testBinding:testChannelNewTypeId</type>
|
||||
</update-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
</update:update-descriptions>
|
||||
Reference in New Issue
Block a user