use of org.openhab.core.thing.ThingStatusInfo in project openhab-core by openhab.
the class ThingManagerOSGiTest method thingManagerHandlesThingHandlerLifecycleCorrectly.
@Test
public void thingManagerHandlesThingHandlerLifecycleCorrectly() {
class ThingHandlerState {
@Nullable
ThingHandlerCallback callback = null;
}
final ThingHandlerState state = new ThingHandlerState();
ThingHandler thingHandler = mock(ThingHandler.class);
doAnswer(new Answer<Void>() {
@Override
@Nullable
public Void answer(InvocationOnMock invocation) throws Throwable {
state.callback = (ThingHandlerCallback) invocation.getArgument(0);
return null;
}
}).when(thingHandler).setCallback(any(ThingHandlerCallback.class));
doAnswer(new Answer<Void>() {
@Override
@Nullable
public Void answer(InvocationOnMock invocation) throws Throwable {
state.callback.statusUpdated(thing, ThingStatusInfoBuilder.create(ThingStatus.ONLINE).build());
return null;
}
}).when(thingHandler).initialize();
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 ThingStatusInfo uninitializedNone = ThingStatusInfoBuilder.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
assertThat(thing.getStatusInfo(), is(uninitializedNone));
// add thing - provokes handler registration & initialization
managedThingProvider.add(thing);
waitForAssert(() -> verify(thingHandlerFactory, times(1)).registerHandler(thing));
waitForAssert(() -> verify(thingHandler, times(1)).initialize());
final ThingStatusInfo onlineNone = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
waitForAssert(() -> assertThat(thing.getStatusInfo(), is(onlineNone)));
// remove handler factory - provokes handler deregistration & disposal
unregisterService(thingHandlerFactory);
waitForAssert(() -> verify(thingHandlerFactory, times(1)).unregisterHandler(thing));
waitForAssert(() -> verify(thingHandler, times(1)).dispose());
final ThingStatusInfo uninitializedHandlerMissing = ThingStatusInfoBuilder.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.HANDLER_MISSING_ERROR).build();
waitForAssert(() -> assertThat(thing.getStatusInfo(), is(uninitializedHandlerMissing)));
// add handler factory - provokes handler registration & initialization
registerService(thingHandlerFactory);
waitForAssert(() -> verify(thingHandlerFactory, times(2)).registerHandler(thing));
waitForAssert(() -> verify(thingHandler, times(2)).initialize());
waitForAssert(() -> assertThat(thing.getStatusInfo(), is(onlineNone)));
// remove thing - provokes handler deregistration & disposal
managedThingProvider.remove(thing.getUID());
waitForAssert(() -> verify(thingHandlerFactory, times(2)).unregisterHandler(thing));
waitForAssert(() -> verify(thingHandler, times(2)).dispose());
waitForAssert(() -> assertThat(thing.getStatusInfo(), is(uninitializedHandlerMissing)));
}
use of org.openhab.core.thing.ThingStatusInfo in project openhab-core by openhab.
the class ThingManagerOSGiJavaTest method testStorageEntryRetainedOnThingRemoval.
@Test
public void testStorageEntryRetainedOnThingRemoval() throws Exception {
registerThingTypeProvider();
AtomicReference<ThingHandlerCallback> thingHandlerCallback = new AtomicReference<>();
AtomicReference<Boolean> initializeInvoked = new AtomicReference<>(false);
AtomicReference<Boolean> disposeInvoked = new AtomicReference<>(false);
registerThingHandlerFactory(THING_TYPE_UID, thing -> {
ThingHandler mockHandler = mock(ThingHandler.class);
doAnswer(a -> {
thingHandlerCallback.set((ThingHandlerCallback) a.getArguments()[0]);
return null;
}).when(mockHandler).setCallback(ArgumentMatchers.isA(ThingHandlerCallback.class));
doAnswer(a -> {
initializeInvoked.set(true);
// call thingUpdated() from within initialize()
thingHandlerCallback.get().thingUpdated(thing);
// hang on a little to provoke a potential dead-lock
Thread.sleep(1000);
ThingStatusInfo thingStatusInfo = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
thing.setStatusInfo(thingStatusInfo);
return null;
}).when(mockHandler).initialize();
doAnswer(a -> {
disposeInvoked.set(true);
return null;
}).when(mockHandler).dispose();
when(mockHandler.getThing()).thenReturn(thing);
return mockHandler;
});
ThingStatusInfo thingStatusInfo = ThingStatusInfoBuilder.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
thing.setStatusInfo(thingStatusInfo);
new Thread((Runnable) () -> managedThingProvider.add(thing)).start();
waitForAssert(() -> {
assertThat(initializeInvoked.get(), is(true));
assertThat(thing.getStatus(), is(ThingStatus.INITIALIZING));
});
initializeInvoked.set(false);
thingManager.setEnabled(THING_UID, false);
waitForAssert(() -> {
assertThat(storage.containsKey(THING_UID.getAsString()), is(true));
assertThat(disposeInvoked.get(), is(true));
assertThat(thing.getStatus(), is(ThingStatus.UNINITIALIZED));
assertThat(thing.getStatusInfo().getStatusDetail(), is(ThingStatusDetail.DISABLED));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
disposeInvoked.set(false);
new Thread((Runnable) () -> managedThingProvider.remove(thing.getUID())).start();
waitForAssert(() -> {
assertThat(thingRegistry.get(thing.getUID()), is(equalTo(null)));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
assertThat(storage.containsKey(THING_UID.getAsString()), is(true));
}
use of org.openhab.core.thing.ThingStatusInfo in project openhab-core by openhab.
the class ThingManagerOSGiJavaTest method testUpdateThing.
@Test
public void testUpdateThing() throws Exception {
registerThingTypeProvider();
AtomicReference<ThingHandlerCallback> thingHandlerCallback = new AtomicReference<>();
AtomicReference<Boolean> initializeInvoked = new AtomicReference<>(false);
AtomicReference<Boolean> disposeInvoked = new AtomicReference<>(false);
AtomicReference<Boolean> updatedInvoked = new AtomicReference<>(false);
registerThingHandlerFactory(THING_TYPE_UID, thing -> {
ThingHandler mockHandler = mock(ThingHandler.class);
doAnswer(a -> {
thingHandlerCallback.set((ThingHandlerCallback) a.getArguments()[0]);
return null;
}).when(mockHandler).setCallback(ArgumentMatchers.isA(ThingHandlerCallback.class));
doAnswer(a -> {
initializeInvoked.set(true);
// call thingUpdated() from within initialize()
thingHandlerCallback.get().thingUpdated(thing);
// hang on a little to provoke a potential dead-lock
Thread.sleep(1000);
ThingStatusInfo thingStatusInfo = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
thing.setStatusInfo(thingStatusInfo);
return null;
}).when(mockHandler).initialize();
doAnswer(a -> {
disposeInvoked.set(true);
return null;
}).when(mockHandler).dispose();
doAnswer(a -> {
updatedInvoked.set(true);
return null;
}).when(mockHandler).thingUpdated(any());
when(mockHandler.getThing()).thenReturn(thing);
return mockHandler;
});
ThingStatusInfo thingStatusInfo = ThingStatusInfoBuilder.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
thing.setStatusInfo(thingStatusInfo);
new Thread((Runnable) () -> managedThingProvider.add(thing)).start();
waitForAssert(() -> {
assertThat(thing.getStatus(), is(ThingStatus.INITIALIZING));
});
waitForAssert(() -> {
assertThat(initializeInvoked.get(), is(true));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
new Thread((Runnable) () -> managedThingProvider.update(thing)).start();
waitForAssert(() -> {
assertThat(updatedInvoked.get(), is(true));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
updatedInvoked.set(false);
thingManager.setEnabled(THING_UID, false);
waitForAssert(() -> {
assertThat(storage.containsKey(THING_UID.getAsString()), is(true));
assertThat(disposeInvoked.get(), is(true));
assertThat(thing.getStatus(), is(ThingStatus.UNINITIALIZED));
assertThat(thing.getStatusInfo().getStatusDetail(), is(ThingStatusDetail.DISABLED));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
disposeInvoked.set(false);
new Thread((Runnable) () -> managedThingProvider.update(thing)).start();
waitForAssert(() -> {
assertThat(updatedInvoked.get(), is(false));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
}
use of org.openhab.core.thing.ThingStatusInfo in project openhab-core by openhab.
the class ThingManagerOSGiJavaTest method testDisposeNotInvokedOnAlreadyDisabledThing.
@Test
public void testDisposeNotInvokedOnAlreadyDisabledThing() throws Exception {
registerThingTypeProvider();
AtomicReference<ThingHandlerCallback> thingHandlerCallback = new AtomicReference<>();
AtomicReference<Boolean> initializeInvoked = new AtomicReference<>(false);
AtomicReference<Boolean> disposeInvoked = new AtomicReference<>(false);
registerThingHandlerFactory(THING_TYPE_UID, thing -> {
ThingHandler mockHandler = mock(ThingHandler.class);
doAnswer(a -> {
thingHandlerCallback.set((ThingHandlerCallback) a.getArguments()[0]);
return null;
}).when(mockHandler).setCallback(ArgumentMatchers.isA(ThingHandlerCallback.class));
doAnswer(a -> {
initializeInvoked.set(true);
// call thingUpdated() from within initialize()
thingHandlerCallback.get().thingUpdated(thing);
// hang on a little to provoke a potential dead-lock
Thread.sleep(1000);
ThingStatusInfo thingStatusInfo = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
thing.setStatusInfo(thingStatusInfo);
return null;
}).when(mockHandler).initialize();
doAnswer(a -> {
disposeInvoked.set(true);
return null;
}).when(mockHandler).dispose();
when(mockHandler.getThing()).thenReturn(thing);
return mockHandler;
});
ThingStatusInfo thingStatusInfo = ThingStatusInfoBuilder.create(ThingStatus.UNINITIALIZED, ThingStatusDetail.NONE).build();
thing.setStatusInfo(thingStatusInfo);
new Thread((Runnable) () -> managedThingProvider.add(thing)).start();
waitForAssert(() -> {
assertThat(thing.getStatus(), is(ThingStatus.INITIALIZING));
});
// ensure it didn't run into a dead-lock which gets resolved by the SafeCaller.
waitForAssert(() -> {
assertThat(initializeInvoked.get(), is(true));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
thingManager.setEnabled(THING_UID, false);
waitForAssert(() -> {
assertThat(storage.containsKey(THING_UID.getAsString()), is(true));
assertThat(disposeInvoked.get(), is(true));
assertThat(thing.getStatus(), is(ThingStatus.UNINITIALIZED));
assertThat(thing.getStatusInfo().getStatusDetail(), is(ThingStatusDetail.DISABLED));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
disposeInvoked.set(false);
thingManager.setEnabled(THING_UID, false);
waitForAssert(() -> {
assertThat(storage.containsKey(THING_UID.getAsString()), is(true));
assertThat(disposeInvoked.get(), is(false));
assertThat(thing.getStatus(), is(ThingStatus.UNINITIALIZED));
assertThat(thing.getStatusInfo().getStatusDetail(), is(ThingStatusDetail.DISABLED));
}, SafeCaller.DEFAULT_TIMEOUT - 100, 50);
}
use of org.openhab.core.thing.ThingStatusInfo in project openhab-core by openhab.
the class ThingManagerOSGiTest method thingManagerCallsBridgeStatusChangedOnThingHandlerCorrectly.
@Test
@SuppressWarnings("null")
public void thingManagerCallsBridgeStatusChangedOnThingHandlerCorrectly() {
class BridgeHandlerState {
@Nullable
ThingHandlerCallback callback;
}
final BridgeHandlerState bridgeState = new BridgeHandlerState();
Bridge bridge = BridgeBuilder.create(new ThingTypeUID("binding:test"), new ThingUID("binding:test:someBridgeUID-1")).build();
BridgeHandler bridgeHandler = mock(BridgeHandler.class);
doAnswer(new Answer<Void>() {
@Override
@Nullable
public Void answer(InvocationOnMock invocation) throws Throwable {
bridgeState.callback = (ThingHandlerCallback) invocation.getArgument(0);
return null;
}
}).when(bridgeHandler).setCallback(any(ThingHandlerCallback.class));
doAnswer(new Answer<Void>() {
@Override
@Nullable
public Void answer(InvocationOnMock invocation) throws Throwable {
bridgeState.callback.statusUpdated(bridge, ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build());
return null;
}
}).when(bridgeHandler).initialize();
when(bridgeHandler.getThing()).thenReturn(bridge);
doAnswer(new Answer<Void>() {
@Override
@Nullable
public Void answer(InvocationOnMock invocation) throws Throwable {
bridgeState.callback.statusUpdated(bridge, ThingStatusInfoBuilder.create(ThingStatus.REMOVED, ThingStatusDetail.NONE).build());
return null;
}
}).when(bridgeHandler).handleRemoval();
class ThingHandlerState {
@Nullable
ThingHandlerCallback callback;
}
final ThingHandlerState thingState = new ThingHandlerState();
Thing thing = ThingBuilder.create(new ThingTypeUID("binding:type"), new ThingUID("binding:type:thingUID-1")).withBridge(bridge.getUID()).build();
ThingHandler thingHandler = mock(ThingHandler.class);
doAnswer(new Answer<Void>() {
@Override
@Nullable
public Void answer(InvocationOnMock invocation) throws Throwable {
thingState.callback = (ThingHandlerCallback) invocation.getArgument(0);
return null;
}
}).when(thingHandler).setCallback(any(ThingHandlerCallback.class));
doAnswer(new Answer<Void>() {
@Override
@Nullable
public Void answer(InvocationOnMock invocation) throws Throwable {
thingState.callback.statusUpdated(thing, ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build());
return null;
}
}).when(thingHandler).initialize();
when(thingHandler.getThing()).thenReturn(thing);
ThingHandlerFactory thingHandlerFactory = mock(ThingHandlerFactory.class);
when(thingHandlerFactory.supportsThingType(any(ThingTypeUID.class))).thenReturn(true);
doAnswer(new Answer<ThingHandler>() {
@Override
@Nullable
public ThingHandler answer(InvocationOnMock invocation) throws Throwable {
Thing thing = (Thing) invocation.getArgument(0);
if (thing instanceof Bridge) {
return bridgeHandler;
} else if (thing instanceof Thing) {
return thingHandler;
}
return null;
}
}).when(thingHandlerFactory).registerHandler(any(Thing.class));
registerService(thingHandlerFactory);
managedThingProvider.add(bridge);
managedThingProvider.add(thing);
waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
// initial bridge initialization is not reported as status change
waitForAssert(() -> verify(thingHandler, never()).bridgeStatusChanged(any(ThingStatusInfo.class)));
// the same status is also not reported, because it's not a change
ThingStatusInfo onlineNone = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
bridgeState.callback.statusUpdated(bridge, onlineNone);
waitForAssert(() -> verify(thingHandler, never()).bridgeStatusChanged(any(ThingStatusInfo.class)));
// report a change to OFFLINE
ThingStatusInfo offlineNone = ThingStatusInfoBuilder.create(ThingStatus.OFFLINE, ThingStatusDetail.NONE).build();
bridgeState.callback.statusUpdated(bridge, offlineNone);
waitForAssert(() -> verify(thingHandler, times(1)).bridgeStatusChanged(any(ThingStatusInfo.class)));
// report a change to ONLINE
bridgeState.callback.statusUpdated(bridge, onlineNone);
waitForAssert(() -> verify(thingHandler, times(2)).bridgeStatusChanged(any(ThingStatusInfo.class)));
ThingRegistry thingRegistry = getService(ThingRegistry.class);
thingRegistry.remove(bridge.getUID());
waitForAssert(() -> {
assertThat(bridge.getStatus(), is(equalTo(ThingStatus.UNINITIALIZED)));
waitForAssert(() -> verify(thingHandler, times(2)).bridgeStatusChanged(any(ThingStatusInfo.class)));
});
}
Aggregations