@NonNullByDefault
public class BoschSHCBindingConstants {
- private static final String BINDING_ID = "boschshc";
+ public static final String BINDING_ID = "boschshc";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_SHC = new ThingTypeUID(BINDING_ID, "shc");
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
+import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
public void initialize() {
- logger.debug("Initialize {} Version {}", FrameworkUtil.getBundle(getClass()).getSymbolicName(),
- FrameworkUtil.getBundle(getClass()).getVersion());
+ Bundle bundle = FrameworkUtil.getBundle(getClass());
+ if (bundle != null) {
+ logger.debug("Initialize {} Version {}", bundle.getSymbolicName(), bundle.getVersion());
+ }
// Read configuration
BridgeConfiguration config = getConfigAs(BridgeConfiguration.class);
* to check if access if possible
* pairs this Bosch SHC Bridge with the SHC if necessary
* and starts the first log poll.
+ * <p>
+ * This method is package-protected to enable unit testing.
*/
- private void initialAccess(BoschHttpClient httpClient) {
+ /* package */ void initialAccess(BoschHttpClient httpClient) {
logger.debug("Initializing Bosch SHC Bridge: {} - HTTP client is: {}", this, httpClient);
try {
deviceId, errorResponse.statusCode, errorResponse.errorCode));
}
} else {
- return new BoschSHCException(String.format("Request for info for device %s failed with status code %d",
+ return new BoschSHCException(String.format("Request for info of device %s failed with status code %d",
deviceId, statusCode));
}
});
*/
package org.openhab.binding.boschshc.internal.devices;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceServiceData;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.types.RefreshType;
import org.openhab.core.types.UnDefType;
import com.google.gson.JsonElement;
public abstract class AbstractBatteryPoweredDeviceHandlerTest<T extends AbstractBatteryPoweredDeviceHandler>
extends AbstractBoschSHCDeviceHandlerTest<T> {
+ @BeforeEach
+ @Override
+ public void beforeEach() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ super.beforeEach();
+
+ DeviceServiceData deviceServiceData = new DeviceServiceData();
+ deviceServiceData.path = "/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel";
+ deviceServiceData.id = "BatteryLevel";
+ deviceServiceData.deviceId = "hdm:ZigBee:000d6f0004b93361";
+ lenient().when(bridgeHandler.getServiceData(anyString(), anyString())).thenReturn(deviceServiceData);
+ }
+
@Test
- public void testProcessUpdate_BatteryLevel_LowBattery() {
+ public void testProcessUpdateBatteryLevelLowBattery() {
JsonElement deviceServiceData = JsonParser.parseString("{ \n" + " \"@type\":\"DeviceServiceData\",\n"
+ " \"path\":\"/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel\",\n"
+ " \"id\":\"BatteryLevel\",\n" + " \"deviceId\":\"hdm:ZigBee:000d6f0004b93361\",\n"
+ " \"type\":\"LOW_BATTERY\",\n" + " \"category\":\"WARNING\"\n" + " }\n"
+ " ]\n" + " }\n" + "}");
getFixture().processUpdate("BatteryLevel", deviceServiceData);
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
new DecimalType(10));
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.ON);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.ON);
}
@Test
- public void testProcessUpdate_BatteryLevel_CriticalLow() {
+ public void testProcessUpdateBatteryLevelCriticalLow() {
JsonElement deviceServiceData = JsonParser.parseString("{ \n" + " \"@type\":\"DeviceServiceData\",\n"
+ " \"path\":\"/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel\",\n"
+ " \"id\":\"BatteryLevel\",\n" + " \"deviceId\":\"hdm:ZigBee:000d6f0004b93361\",\n"
+ " \"type\":\"CRITICAL_LOW\",\n" + " \"category\":\"WARNING\"\n"
+ " }\n" + " ]\n" + " }\n" + "}");
getFixture().processUpdate("BatteryLevel", deviceServiceData);
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
new DecimalType(1));
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.ON);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.ON);
}
@Test
- public void testProcessUpdate_BatteryLevel_CriticallyLowBattery() {
+ public void testProcessUpdateBatteryLevelCriticallyLowBattery() {
JsonElement deviceServiceData = JsonParser.parseString("{ \n" + " \"@type\":\"DeviceServiceData\",\n"
+ " \"path\":\"/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel\",\n"
+ " \"id\":\"BatteryLevel\",\n" + " \"deviceId\":\"hdm:ZigBee:000d6f0004b93361\",\n"
+ " \"type\":\"CRITICALLY_LOW_BATTERY\",\n" + " \"category\":\"WARNING\"\n"
+ " }\n" + " ]\n" + " }\n" + "}");
getFixture().processUpdate("BatteryLevel", deviceServiceData);
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
new DecimalType(1));
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.ON);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.ON);
}
@Test
- public void testProcessUpdate_BatteryLevel_OK() {
+ public void testProcessUpdateBatteryLevelOK() {
JsonElement deviceServiceData = JsonParser.parseString("{ \n" + " \"@type\":\"DeviceServiceData\",\n"
+ " \"path\":\"/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel\",\n"
+ " \"id\":\"BatteryLevel\",\n" + " \"deviceId\":\"hdm:ZigBee:000d6f0004b93361\" }");
}
@Test
- public void testProcessUpdate_BatteryLevel_NotAvailable() {
+ public void testProcessUpdateBatteryLevelNotAvailable() {
JsonElement deviceServiceData = JsonParser.parseString("{ \n" + " \"@type\":\"DeviceServiceData\",\n"
+ " \"path\":\"/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel\",\n"
+ " \"id\":\"BatteryLevel\",\n" + " \"deviceId\":\"hdm:ZigBee:000d6f0004b93361\",\n"
+ " \"type\":\"NOT_AVAILABLE\",\n" + " \"category\":\"WARNING\"\n"
+ " }\n" + " ]\n" + " }\n" + "}");
getFixture().processUpdate("BatteryLevel", deviceServiceData);
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL), UnDefType.UNDEF);
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.OFF);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
+ UnDefType.UNDEF);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.OFF);
+ }
+
+ @Test
+ public void testHandleCommandRefreshBatteryLevelChannel() {
+ getFixture().handleCommand(getChannelUID(BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL), RefreshType.REFRESH);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_BATTERY_LEVEL),
+ new DecimalType(100));
+ }
+
+ @Test
+ public void testHandleCommandRefreshLowBatteryChannel() {
+ getFixture().handleCommand(getChannelUID(BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), RefreshType.REFRESH);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_LOW_BATTERY), OnOffType.OFF);
}
}
*/
package org.openhab.binding.boschshc.internal.devices;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.config.core.Configuration;
/**
*
* @param <T> type of the device handler to be tested
*/
+@NonNullByDefault
public abstract class AbstractBoschSHCDeviceHandlerTest<T extends BoschSHCDeviceHandler>
- extends AbstractSHCHandlerTest<T> {
+ extends AbstractBoschSHCHandlerTest<T> {
@Override
protected Configuration getConfiguration() {
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices;
+
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+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.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.core.config.core.Configuration;
+import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingStatusInfo;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.ThingHandlerCallback;
+
+/**
+ * Abstract unit test implementation for all types of handlers.
+ *
+ * @author David Pace - Initial contribution
+ *
+ * @param <T> type of the handler to be tested
+ */
+@NonNullByDefault
+@ExtendWith(MockitoExtension.class)
+public abstract class AbstractBoschSHCHandlerTest<T extends BoschSHCHandler> {
+
+ private T fixture;
+
+ private @Mock @NonNullByDefault({}) Thing thing;
+
+ private @Mock @NonNullByDefault({}) Bridge bridge;
+
+ protected @Mock @NonNullByDefault({}) BridgeHandler bridgeHandler;
+
+ private @Mock @NonNullByDefault({}) ThingHandlerCallback callback;
+
+ protected AbstractBoschSHCHandlerTest() {
+ this.fixture = createFixture();
+ }
+
+ @BeforeEach
+ void beforeEach() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ fixture = createFixture();
+ lenient().when(thing.getUID()).thenReturn(getThingUID());
+ when(thing.getBridgeUID()).thenReturn(new ThingUID("boschshc", "shc", "myBridgeUID"));
+ when(callback.getBridge(any())).thenReturn(bridge);
+ fixture.setCallback(callback);
+ when(bridge.getHandler()).thenReturn(bridgeHandler);
+ lenient().when(thing.getConfiguration()).thenReturn(getConfiguration());
+
+ fixture.initialize();
+ }
+
+ protected abstract T createFixture();
+
+ protected T getFixture() {
+ return fixture;
+ }
+
+ protected ThingUID getThingUID() {
+ return new ThingUID(getThingTypeUID(), "abcdef");
+ }
+
+ protected abstract ThingTypeUID getThingTypeUID();
+
+ protected ChannelUID getChannelUID(String channelID) {
+ return new ChannelUID(getThingUID(), channelID);
+ }
+
+ protected Configuration getConfiguration() {
+ return new Configuration();
+ }
+
+ protected Thing getThing() {
+ return thing;
+ }
+
+ protected BridgeHandler getBridgeHandler() {
+ return bridgeHandler;
+ }
+
+ protected ThingHandlerCallback getCallback() {
+ return callback;
+ }
+
+ @Test
+ public void testInitialize() {
+ ThingStatusInfo expectedStatusInfo = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
+ verify(callback).statusUpdated(same(thing), eq(expectedStatusInfo));
+ }
+}
package org.openhab.binding.boschshc.internal.devices;
import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.util.concurrent.ExecutionException;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.powermeter.dto.PowerMeterServiceState;
import org.openhab.binding.boschshc.internal.services.powerswitch.PowerSwitchState;
import org.openhab.binding.boschshc.internal.services.powerswitch.dto.PowerSwitchServiceState;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
-import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.ThingUID;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.types.RefreshType;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
*
* @param <T> type of the handler to be tested
*/
+@NonNullByDefault
public abstract class AbstractPowerSwitchHandlerTest<T extends AbstractPowerSwitchHandler>
extends AbstractBoschSHCDeviceHandlerTest<T> {
- @Captor
- private ArgumentCaptor<PowerSwitchServiceState> serviceStateCaptor;
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<PowerSwitchServiceState> serviceStateCaptor;
- @Captor
- private ArgumentCaptor<QuantityType<Power>> powerCaptor;
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<QuantityType<Power>> powerCaptor;
- @Captor
- private ArgumentCaptor<QuantityType<Energy>> energyCaptor;
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<QuantityType<Energy>> energyCaptor;
+
+ @BeforeEach
+ @Override
+ public void beforeEach() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ super.beforeEach();
+
+ PowerSwitchServiceState powerSwitchServiceState = new PowerSwitchServiceState();
+ powerSwitchServiceState.switchState = PowerSwitchState.ON;
+ lenient().when(bridgeHandler.getState(anyString(), eq("PowerSwitch"), same(PowerSwitchServiceState.class)))
+ .thenReturn(powerSwitchServiceState);
+
+ PowerMeterServiceState powerMeterServiceState = new PowerMeterServiceState();
+ powerMeterServiceState.powerConsumption = 12.34d;
+ powerMeterServiceState.energyConsumption = 56.78d;
+ lenient().when(bridgeHandler.getState(anyString(), eq("PowerMeter"), same(PowerMeterServiceState.class)))
+ .thenReturn(powerMeterServiceState);
+ }
@Test
- public void testHandleCommand()
+ public void testHandleCommandPowerSwitchChannel()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
-
- getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_SWITCH),
- OnOffType.ON);
+ getFixture().handleCommand(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.ON);
verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("PowerSwitch"), serviceStateCaptor.capture());
PowerSwitchServiceState state = serviceStateCaptor.getValue();
assertSame(PowerSwitchState.ON, state.switchState);
- getFixture().handleCommand(new ChannelUID(new ThingUID(getThingTypeUID(), "abcdef"),
- BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.OFF);
+ getFixture().handleCommand(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.OFF);
verify(getBridgeHandler(), times(2)).putState(eq(getDeviceID()), eq("PowerSwitch"),
serviceStateCaptor.capture());
state = serviceStateCaptor.getValue();
}
@Test
- public void testUpdateChannel_PowerSwitchState() {
+ public void testUpdateChannelPowerSwitchState() {
JsonElement jsonObject = JsonParser
.parseString("{\n" + " \"@type\": \"powerSwitchState\",\n" + " \"switchState\": \"ON\"\n" + "}");
getFixture().processUpdate("PowerSwitch", jsonObject);
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.ON);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.ON);
jsonObject = JsonParser
.parseString("{\n" + " \"@type\": \"powerSwitchState\",\n" + " \"switchState\": \"OFF\"\n" + "}");
getFixture().processUpdate("PowerSwitch", jsonObject);
- verify(getCallback()).stateUpdated(
- new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.OFF);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.OFF);
}
@Test
- public void testUpdateChannel_PowerMeterServiceState() {
+ public void testUpdateChannelPowerMeterServiceState() {
JsonElement jsonObject = JsonParser.parseString("{\n" + " \"@type\": \"powerMeterState\",\n"
+ " \"powerConsumption\": \"23\",\n" + " \"energyConsumption\": 42\n" + "}");
getFixture().processUpdate("PowerMeter", jsonObject);
- verify(getCallback()).stateUpdated(
- eq(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_CONSUMPTION)),
+ verify(getCallback()).stateUpdated(eq(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_CONSUMPTION)),
powerCaptor.capture());
QuantityType<Power> powerValue = powerCaptor.getValue();
assertEquals(23, powerValue.intValue());
- verify(getCallback()).stateUpdated(
- eq(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ENERGY_CONSUMPTION)),
+ verify(getCallback()).stateUpdated(eq(getChannelUID(BoschSHCBindingConstants.CHANNEL_ENERGY_CONSUMPTION)),
energyCaptor.capture());
QuantityType<Energy> energyValue = energyCaptor.getValue();
assertEquals(42, energyValue.intValue());
}
+
+ @Test
+ public void testHandleCommandRefreshPowerSwitchChannel() {
+ getFixture().handleCommand(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), RefreshType.REFRESH);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.ON);
+ }
+
+ @Test
+ public void testHandleCommandRefreshPowerConsumptionChannel() {
+ getFixture().handleCommand(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_CONSUMPTION),
+ RefreshType.REFRESH);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_POWER_CONSUMPTION),
+ new QuantityType<Power>(12.34d, Units.WATT));
+ }
+
+ @Test
+ public void testHandleCommandRefreshEnergyConsumptionChannel() {
+ getFixture().handleCommand(getChannelUID(BoschSHCBindingConstants.CHANNEL_ENERGY_CONSUMPTION),
+ RefreshType.REFRESH);
+ verify(getCallback()).stateUpdated(getChannelUID(BoschSHCBindingConstants.CHANNEL_ENERGY_CONSUMPTION),
+ new QuantityType<Energy>(56.78d, Units.WATT_HOUR));
+ }
}
+++ /dev/null
-/**
- * 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.binding.boschshc.internal.devices;
-
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-import org.junit.jupiter.api.BeforeEach;
-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.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
-import org.openhab.core.config.core.Configuration;
-import org.openhab.core.thing.Bridge;
-import org.openhab.core.thing.Thing;
-import org.openhab.core.thing.ThingStatus;
-import org.openhab.core.thing.ThingStatusDetail;
-import org.openhab.core.thing.ThingStatusInfo;
-import org.openhab.core.thing.ThingTypeUID;
-import org.openhab.core.thing.ThingUID;
-import org.openhab.core.thing.binding.ThingHandlerCallback;
-
-/**
- * Abstract unit test implementation for all types of handlers.
- *
- * @author David Pace - Initial contribution
- *
- * @param <T> type of the handler to be tested
- */
-@ExtendWith(MockitoExtension.class)
-public abstract class AbstractSHCHandlerTest<T extends BoschSHCHandler> {
-
- private T fixture;
-
- @Mock
- private Thing thing;
-
- @Mock
- private Bridge bridge;
-
- @Mock
- private BridgeHandler bridgeHandler;
-
- @Mock
- private ThingHandlerCallback callback;
-
- @BeforeEach
- public void beforeEach() {
- fixture = createFixture();
- lenient().when(thing.getUID()).thenReturn(getThingUID());
- when(thing.getBridgeUID()).thenReturn(new ThingUID("boschshc", "shc", "myBridgeUID"));
- when(callback.getBridge(any())).thenReturn(bridge);
- fixture.setCallback(callback);
- when(bridge.getHandler()).thenReturn(bridgeHandler);
- when(thing.getConfiguration()).thenReturn(getConfiguration());
-
- fixture.initialize();
- }
-
- protected abstract T createFixture();
-
- protected T getFixture() {
- return fixture;
- }
-
- protected ThingUID getThingUID() {
- return new ThingUID(getThingTypeUID(), "abcdef");
- }
-
- protected abstract ThingTypeUID getThingTypeUID();
-
- protected Configuration getConfiguration() {
- return new Configuration();
- }
-
- protected Thing getThing() {
- return thing;
- }
-
- public BridgeHandler getBridgeHandler() {
- return bridgeHandler;
- }
-
- public ThingHandlerCallback getCallback() {
- return callback;
- }
-
- @Test
- public void testInitialize() {
- ThingStatusInfo expectedStatusInfo = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
- verify(callback).statusUpdated(same(thing), eq(expectedStatusInfo));
- }
-}
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.binding.boschshc.internal.services.smokedetectorcheck.SmokeDetectorCheckState;
import org.openhab.binding.boschshc.internal.services.smokedetectorcheck.dto.SmokeDetectorCheckServiceState;
+import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PlayPauseType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingStatusInfo;
+import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
@Test
public void testHandleCommand()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
-
// valid commands with valid thing & channel
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
new StringType(SmokeDetectorCheckState.SMOKE_TEST_REQUESTED.toString()));
}
@Test
- public void testHandleCommand_PlayPauseType()
+ public void testHandleCommandPlayPauseType()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
-
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
PlayPauseType.PLAY);
verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"),
}
@Test
- public void testUpdateChannel_SmokeDetectorCheckServiceState_none() {
+ public void testHandleCommandUnknownCommand()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+ OnOffType.ON);
+ ThingStatusInfo expectedThingStatusInfo = ThingStatusInfoBuilder
+ .create(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR)
+ .withDescription(
+ "Error when service SmokeDetectorCheck should handle command org.openhab.core.library.types.OnOffType: SmokeDetectorCheck: Can not handle command org.openhab.core.library.types.OnOffType")
+ .build();
+ verify(getCallback()).statusUpdated(getThing(), expectedThingStatusInfo);
+ }
+
+ @Test
+ public void testUpdateChannelSmokeDetectorCheckServiceStateNone() {
JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"smokeDetectorCheckState\",\"value\":NONE}");
getFixture().processUpdate("SmokeDetectorCheck", jsonObject);
verify(getCallback()).stateUpdated(
}
@Test
- public void testUpdateChannel_SmokeDetectorCheckServiceState_Requests() {
+ public void testUpdateChannelSmokeDetectorCheckServiceStateRequests() {
JsonElement jsonObject = JsonParser
.parseString("{\"@type\":\"smokeDetectorCheckState\",\"value\":SMOKE_TEST_REQUESTED}");
getFixture().processUpdate("SmokeDetectorCheck", jsonObject);
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.boschshc.internal.devices.plug.PlugHandler;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * Unit tests for {@link BoschSHCHandlerFactory}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class BoschSHCHandlerFactoryTest {
+
+ private @NonNullByDefault({}) BoschSHCHandlerFactory fixture;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ fixture = new BoschSHCHandlerFactory();
+ }
+
+ @Test
+ public void testSupportsThingType() {
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_SHC));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_INWALL_SWITCH));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_TWINGUARD));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_WINDOW_CONTACT));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_MOTION_DETECTOR));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_SHUTTER_CONTROL));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_THERMOSTAT));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_CLIMATE_CONTROL));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_WALL_THERMOSTAT));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_CAMERA_360));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_CAMERA_EYES));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_INTRUSION_DETECTION_SYSTEM));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_SMART_PLUG_COMPACT));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_SMART_BULB));
+ assertTrue(fixture.supportsThingType(BoschSHCBindingConstants.THING_TYPE_SMOKE_DETECTOR));
+
+ assertFalse(fixture.supportsThingType(new ThingTypeUID(BoschSHCBindingConstants.BINDING_ID, "foo")));
+ }
+
+ @Test
+ public void testCreateHandler() {
+ Thing thing = mock(Thing.class);
+ when(thing.getThingTypeUID()).thenReturn(BoschSHCBindingConstants.THING_TYPE_SMART_PLUG_COMPACT);
+ assertTrue(fixture.createHandler(thing) instanceof PlugHandler);
+ }
+}
package org.openhab.binding.boschshc.internal.devices.bridge;
import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.platform.commons.support.HierarchyTraversalMode;
+import org.junit.platform.commons.support.ReflectionSupport;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
import org.openhab.binding.boschshc.internal.devices.bridge.dto.SubscribeResult;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.binding.boschshc.internal.exceptions.PairingFailedException;
+import org.openhab.binding.boschshc.internal.services.binaryswitch.dto.BinarySwitchServiceState;
+import org.slf4j.Logger;
/**
* Tests cases for {@link BoschHttpClient}.
@NonNullByDefault
class BoschHttpClientTest {
- @Nullable
- private BoschHttpClient httpClient;
+ private @NonNullByDefault({}) BoschHttpClient httpClient;
@BeforeAll
static void beforeAll() {
assertFalse(httpClient.isOnline());
}
+ @Test
+ void isOnlineErrorResponse() throws InterruptedException, IllegalArgumentException, IllegalAccessException,
+ TimeoutException, ExecutionException {
+ BoschHttpClient mockedHttpClient = mock(BoschHttpClient.class);
+ when(mockedHttpClient.isOnline()).thenCallRealMethod();
+ when(mockedHttpClient.getPublicInformationUrl()).thenCallRealMethod();
+
+ // mock a logger using reflection to avoid NPEs during logger calls
+ Logger mockedLogger = mock(Logger.class);
+ List<Field> fields = ReflectionSupport.findFields(BoschHttpClient.class,
+ f -> f.getName().equalsIgnoreCase("logger"), HierarchyTraversalMode.TOP_DOWN);
+ Field field = fields.iterator().next();
+ field.setAccessible(true);
+ field.set(mockedHttpClient, mockedLogger);
+
+ Request request = mock(Request.class);
+ when(mockedHttpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(500);
+ assertFalse(mockedHttpClient.isOnline());
+ }
+
+ @Test
+ void isOnlineMockedResponse() throws InterruptedException, TimeoutException, ExecutionException,
+ IllegalArgumentException, IllegalAccessException {
+ BoschHttpClient mockedHttpClient = mock(BoschHttpClient.class);
+ when(mockedHttpClient.isOnline()).thenCallRealMethod();
+ when(mockedHttpClient.getPublicInformationUrl()).thenCallRealMethod();
+
+ // mock a logger using reflection to avoid NPEs during logger calls
+ Logger mockedLogger = mock(Logger.class);
+ List<Field> fields = ReflectionSupport.findFields(BoschHttpClient.class,
+ f -> f.getName().equalsIgnoreCase("logger"), HierarchyTraversalMode.TOP_DOWN);
+ Field field = fields.iterator().next();
+ field.setAccessible(true);
+ field.set(mockedHttpClient, mockedLogger);
+
+ Request request = mock(Request.class);
+ when(mockedHttpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(200);
+ when(response.getContentAsString()).thenReturn("response");
+ assertTrue(mockedHttpClient.isOnline());
+ }
+
@Test
void doPairing() throws InterruptedException {
assertFalse(httpClient.doPairing());
@Test
void createRequestWithObject() {
- Request request = httpClient.createRequest("https://127.0.0.1", HttpMethod.GET, "someData");
+ BinarySwitchServiceState binarySwitchState = new BinarySwitchServiceState();
+ binarySwitchState.on = true;
+ Request request = httpClient.createRequest("https://127.0.0.1", HttpMethod.GET, binarySwitchState);
assertNotNull(request);
+ assertEquals("{\"on\":true,\"stateType\":\"binarySwitchState\",\"@type\":\"binarySwitchState\"}",
+ StandardCharsets.UTF_8.decode(request.getContent().iterator().next()).toString());
}
@Test
- void sendRequest() {
- Request request = httpClient.createRequest("https://127.0.0.1", HttpMethod.GET);
- // Null pointer exception is expected, because localhost will not answer request
- assertThrows(NullPointerException.class, () -> {
- httpClient.sendRequest(request, SubscribeResult.class, SubscribeResult::isValid, null);
- });
+ void sendRequest() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ Request request = mock(Request.class);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(200);
+ when(response.getContentAsString()).thenReturn("{\"jsonrpc\": \"2.0\", \"result\": \"test result\"}");
+
+ SubscribeResult subscribeResult = httpClient.sendRequest(request, SubscribeResult.class,
+ SubscribeResult::isValid, null);
+ assertEquals("2.0", subscribeResult.getJsonrpc());
+ assertEquals("test result", subscribeResult.getResult());
+ }
+
+ @Test
+ void sendRequestResponseError()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ Request request = mock(Request.class);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(500);
+ ExecutionException e = assertThrows(ExecutionException.class,
+ () -> httpClient.sendRequest(request, SubscribeResult.class, SubscribeResult::isValid, null));
+ assertEquals("Request failed with status code 500", e.getMessage());
+ }
+
+ @Test
+ void sendRequestResponseErrorWithErrorHandler()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ Request request = mock(Request.class);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(500);
+ when(response.getContentAsString()).thenReturn(
+ "{\"@type\": \"JsonRestExceptionResponseEntity\", \"errorCode\": \"500\", \"statusCode\": \"500\"}");
+
+ BoschSHCException e = assertThrows(BoschSHCException.class, () -> httpClient.sendRequest(request, Device.class,
+ Device::isValid, (Integer statusCode, String content) -> {
+ return new BoschSHCException("test exception");
+ }));
+ assertEquals("test exception", e.getMessage());
+ }
+
+ @Test
+ void sendRequestEmptyResponse()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ Request request = mock(Request.class);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(200);
+ ExecutionException e = assertThrows(ExecutionException.class,
+ () -> httpClient.sendRequest(request, SubscribeResult.class, SubscribeResult::isValid, null));
+ assertEquals(
+ "Received no content in response, expected type org.openhab.binding.boschshc.internal.devices.bridge.dto.SubscribeResult",
+ e.getMessage());
+ }
+
+ @Test
+ void sendRequestInvalidResponse()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ Request request = mock(Request.class);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(200);
+ when(response.getContentAsString()).thenReturn(
+ "{\"@type\": \"JsonRestExceptionResponseEntity\", \"errorCode\": \"500\", \"statusCode\": \"500\"}");
+ ExecutionException e = assertThrows(ExecutionException.class,
+ () -> httpClient.sendRequest(request, SubscribeResult.class, sr -> {
+ return false;
+ }, null));
+ String actualMessage = e.getMessage();
+ assertTrue(actualMessage.contains(
+ "Received invalid content for type org.openhab.binding.boschshc.internal.devices.bridge.dto.SubscribeResult:"));
+ }
+
+ @Test
+ void sendRequestInvalidSyntaxInResponse()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ Request request = mock(Request.class);
+ ContentResponse response = mock(ContentResponse.class);
+ when(request.send()).thenReturn(response);
+ when(response.getStatus()).thenReturn(200);
+ when(response.getContentAsString()).thenReturn("{\"@type\": \"JsonRestExceptionResponseEntity}");
+ ExecutionException e = assertThrows(ExecutionException.class,
+ () -> httpClient.sendRequest(request, SubscribeResult.class, sr -> {
+ return false;
+ }, null));
+ assertEquals(
+ "Received invalid content in response, expected type org.openhab.binding.boschshc.internal.devices.bridge.dto.SubscribeResult: com.google.gson.stream.MalformedJsonException: Unterminated string at line 1 column 44 path $.@type",
+ e.getMessage());
}
}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.bridge;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link BridgeConfiguration}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class BridgeConfigurationTest {
+
+ @Test
+ void testConstructor() {
+ BridgeConfiguration fixture = new BridgeConfiguration();
+ assertEquals("", fixture.ipAddress);
+ assertEquals("", fixture.password);
+ }
+}
*/
package org.openhab.binding.boschshc.internal.devices.bridge;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.same;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
+import java.util.function.BiFunction;
import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpMethod;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceServiceData;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceTest;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.Faults;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.SubscribeResult;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.binaryswitch.dto.BinarySwitchServiceState;
import org.openhab.binding.boschshc.internal.services.intrusion.actions.arm.dto.ArmActionRequest;
+import org.openhab.binding.boschshc.internal.services.intrusion.dto.AlarmState;
+import org.openhab.binding.boschshc.internal.services.intrusion.dto.ArmingState;
+import org.openhab.binding.boschshc.internal.services.intrusion.dto.IntrusionDetectionSystemState;
+import org.openhab.binding.boschshc.internal.services.shuttercontact.ShutterContactState;
+import org.openhab.binding.boschshc.internal.services.shuttercontact.dto.ShutterContactServiceState;
+import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.binding.ThingHandlerCallback;
+import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
/**
* Unit tests for the {@link BridgeHandler}.
- *
+ *
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
class BridgeHandlerTest {
- @Nullable
- private BridgeHandler fixture;
+ private @NonNullByDefault({}) BridgeHandler fixture;
+
+ private @NonNullByDefault({}) BoschHttpClient httpClient;
- @Nullable
- private BoschHttpClient httpClient;
+ private @NonNullByDefault({}) ThingHandlerCallback thingHandlerCallback;
+
+ @BeforeAll
+ static void beforeAll() throws IOException {
+ Path mavenTargetFolder = Paths.get("target");
+ assertTrue(Files.exists(mavenTargetFolder), "Maven target folder does not exist.");
+ System.setProperty("openhab.userdata", mavenTargetFolder.toFile().getAbsolutePath());
+ Path etc = mavenTargetFolder.resolve("etc");
+ if (!Files.exists(etc)) {
+ Files.createDirectory(etc);
+ }
+ }
@BeforeEach
- void beforeEach() {
+ void beforeEach() throws Exception {
Bridge bridge = mock(Bridge.class);
fixture = new BridgeHandler(bridge);
+
+ thingHandlerCallback = mock(ThingHandlerCallback.class);
+ fixture.setCallback(thingHandlerCallback);
+
+ Configuration bridgeConfiguration = new Configuration();
+ Map<String, Object> properties = new HashMap<>();
+ properties.put("ipAddress", "localhost");
+ properties.put("password", "test");
+ bridgeConfiguration.setProperties(properties);
+
+ Thing thing = mock(Bridge.class);
+ when(thing.getConfiguration()).thenReturn(bridgeConfiguration);
+ // this calls initialize() as well
+ fixture.thingUpdated(thing);
+
+ // shut down the real HTTP client
+ if (fixture.httpClient != null) {
+ fixture.httpClient.stop();
+ }
+
+ // use a mocked HTTP client
httpClient = mock(BoschHttpClient.class);
fixture.httpClient = httpClient;
}
verify(httpClient).createRequest(eq(url), same(HttpMethod.POST), same(request));
verify(mockRequest).send();
}
+
+ @Test
+ void initialAccessHttpClientOffline() {
+ fixture.initialAccess(httpClient);
+ }
+
+ @Test
+ void initialAccessHttpClientOnline() throws InterruptedException {
+ when(httpClient.isOnline()).thenReturn(true);
+ fixture.initialAccess(httpClient);
+ }
+
+ @Test
+ void initialAccessAccessPossible()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.isOnline()).thenReturn(true);
+ when(httpClient.isAccessPossible()).thenReturn(true);
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+
+ // mock a request and response to obtain rooms
+ Request roomsRequest = mock(Request.class);
+ ContentResponse roomsResponse = mock(ContentResponse.class);
+ when(roomsResponse.getStatus()).thenReturn(200);
+ when(roomsResponse.getContentAsString()).thenReturn(
+ "[{\"@type\":\"room\",\"id\":\"hz_1\",\"iconId\":\"icon_room_bedroom\",\"name\":\"Bedroom\"}]");
+ when(roomsRequest.send()).thenReturn(roomsResponse);
+ when(httpClient.createRequest(contains("/rooms"), same(HttpMethod.GET))).thenReturn(roomsRequest);
+
+ // mock a request and response to obtain devices
+ Request devicesRequest = mock(Request.class);
+ ContentResponse devicesResponse = mock(ContentResponse.class);
+ when(devicesResponse.getStatus()).thenReturn(200);
+ when(devicesResponse.getContentAsString()).thenReturn("[{\"@type\":\"device\",\r\n"
+ + " \"rootDeviceId\":\"64-da-a0-02-14-9b\",\r\n"
+ + " \"id\":\"hdm:HomeMaticIP:3014F711A00004953859F31B\",\r\n"
+ + " \"deviceServiceIds\":[\"PowerMeter\",\"PowerSwitch\",\"PowerSwitchProgram\",\"Routing\"],\r\n"
+ + " \"manufacturer\":\"BOSCH\",\r\n" + " \"roomId\":\"hz_3\",\r\n" + " \"deviceModel\":\"PSM\",\r\n"
+ + " \"serial\":\"3014F711A00004953859F31B\",\r\n" + " \"profile\":\"GENERIC\",\r\n"
+ + " \"name\":\"Coffee Machine\",\r\n" + " \"status\":\"AVAILABLE\",\r\n" + " \"childDeviceIds\":[]\r\n"
+ + " }]");
+ when(devicesRequest.send()).thenReturn(devicesResponse);
+ when(httpClient.createRequest(contains("/devices"), same(HttpMethod.GET))).thenReturn(devicesRequest);
+
+ SubscribeResult subscribeResult = new SubscribeResult();
+ when(httpClient.sendRequest(any(), same(SubscribeResult.class), any(), any())).thenReturn(subscribeResult);
+
+ Request longPollRequest = mock(Request.class);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.POST),
+ argThat((JsonRpcRequest r) -> r.method.equals("RE/longPoll")))).thenReturn(longPollRequest);
+
+ fixture.initialAccess(httpClient);
+ verify(thingHandlerCallback).statusUpdated(any(),
+ eq(ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build()));
+ }
+
+ @Test
+ void getState() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.getContentAsString()).thenReturn("{\r\n" + " \"@type\": \"systemState\",\r\n"
+ + " \"systemAvailability\": {\r\n" + " \"@type\": \"systemAvailabilityState\",\r\n"
+ + " \"available\": true,\r\n" + " \"deleted\": false\r\n" + " },\r\n"
+ + " \"armingState\": {\r\n" + " \"@type\": \"armingState\",\r\n"
+ + " \"state\": \"SYSTEM_DISARMED\",\r\n" + " \"deleted\": false\r\n" + " },\r\n"
+ + " \"alarmState\": {\r\n" + " \"@type\": \"alarmState\",\r\n"
+ + " \"value\": \"ALARM_OFF\",\r\n" + " \"incidents\": [],\r\n"
+ + " \"deleted\": false\r\n" + " },\r\n" + " \"activeConfigurationProfile\": {\r\n"
+ + " \"@type\": \"activeConfigurationProfile\",\r\n" + " \"deleted\": false\r\n"
+ + " },\r\n" + " \"securityGapState\": {\r\n" + " \"@type\": \"securityGapState\",\r\n"
+ + " \"securityGaps\": [],\r\n" + " \"deleted\": false\r\n" + " },\r\n"
+ + " \"deleted\": false\r\n" + " }");
+ when(request.send()).thenReturn(response);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+
+ IntrusionDetectionSystemState state = fixture.getState("intrusion/states/system",
+ IntrusionDetectionSystemState.class);
+ assertNotNull(state);
+ assertTrue(state.systemAvailability.available);
+ assertSame(AlarmState.ALARM_OFF, state.alarmState.value);
+ assertSame(ArmingState.SYSTEM_DISARMED, state.armingState.state);
+ }
+
+ @Test
+ void getDeviceState() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getServiceStateUrl(anyString(), anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.getContentAsString())
+ .thenReturn("{\n" + " \"@type\": \"shutterContactState\",\n" + " \"value\": \"OPEN\"\n" + " }");
+ when(request.send()).thenReturn(response);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+
+ ShutterContactServiceState state = fixture.getState("hdm:HomeMaticIP:3014D711A000009D545DEB39D",
+ "ShutterContact", ShutterContactServiceState.class);
+ assertNotNull(state);
+ assertSame(ShutterContactState.OPEN, state.value);
+ }
+
+ @Test
+ void getDeviceInfo() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(response.getStatus()).thenReturn(200);
+ when(request.send()).thenReturn(response);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+ when(httpClient.sendRequest(same(request), same(Device.class), any(), any()))
+ .thenReturn(DeviceTest.createTestDevice());
+
+ String deviceId = "hdm:HomeMaticIP:3014F711A00004953859F31B";
+ Device device = fixture.getDeviceInfo(deviceId);
+ assertEquals(deviceId, device.id);
+ }
+
+ @Test
+ void getDeviceInfoErrorCases()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(response.getStatus()).thenReturn(200);
+ when(request.send()).thenReturn(response);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+
+ @SuppressWarnings("unchecked")
+ ArgumentCaptor<BiFunction<Integer, String, BoschSHCException>> errorResponseHandlerCaptor = ArgumentCaptor
+ .forClass(BiFunction.class);
+
+ when(httpClient.sendRequest(same(request), same(Device.class), any(), errorResponseHandlerCaptor.capture()))
+ .thenReturn(DeviceTest.createTestDevice());
+
+ String deviceId = "hdm:HomeMaticIP:3014F711A00004953859F31B";
+ fixture.getDeviceInfo(deviceId);
+
+ BiFunction<Integer, String, BoschSHCException> errorResponseHandler = errorResponseHandlerCaptor.getValue();
+ Exception e = errorResponseHandler.apply(500,
+ "{\"@type\":\"JsonRestExceptionResponseEntity\",\"errorCode\": \"testErrorCode\",\"statusCode\": 500}");
+ assertEquals(
+ "Request for info of device hdm:HomeMaticIP:3014F711A00004953859F31B failed with status code 500 and error code testErrorCode",
+ e.getMessage());
+
+ e = errorResponseHandler.apply(404,
+ "{\"@type\":\"JsonRestExceptionResponseEntity\",\"errorCode\": \"ENTITY_NOT_FOUND\",\"statusCode\": 404}");
+ assertNotNull(e);
+
+ e = errorResponseHandler.apply(500, "");
+ assertEquals("Request for info of device hdm:HomeMaticIP:3014F711A00004953859F31B failed with status code 500",
+ e.getMessage());
+ }
+
+ @Test
+ void getServiceData() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getServiceUrl(anyString(), anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.getContentAsString()).thenReturn("{ \n" + " \"@type\":\"DeviceServiceData\",\n"
+ + " \"path\":\"/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel\",\n"
+ + " \"id\":\"BatteryLevel\",\n" + " \"deviceId\":\"hdm:ZigBee:000d6f0004b93361\",\n"
+ + " \"faults\":{ \n" + " \"entries\":[\n" + " {\n"
+ + " \"type\":\"LOW_BATTERY\",\n" + " \"category\":\"WARNING\"\n" + " }\n"
+ + " ]\n" + " }\n" + "}");
+ when(request.send()).thenReturn(response);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+
+ DeviceServiceData serviceData = fixture.getServiceData("hdm:ZigBee:000d6f0004b93361", "BatteryLevel");
+ assertNotNull(serviceData);
+ Faults faults = serviceData.faults;
+ assertNotNull(faults);
+ assertEquals("LOW_BATTERY", faults.entries.get(0).type);
+ }
+
+ @Test
+ void getServiceDataError() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getServiceUrl(anyString(), anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(response.getStatus()).thenReturn(500);
+ when(response.getContentAsString()).thenReturn(
+ "{\"@type\":\"JsonRestExceptionResponseEntity\",\"errorCode\": \"testErrorCode\",\"statusCode\": 500}");
+ when(request.send()).thenReturn(response);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+ when(httpClient.sendRequest(same(request), same(Device.class), any(), any()))
+ .thenReturn(DeviceTest.createTestDevice());
+
+ BoschSHCException e = assertThrows(BoschSHCException.class,
+ () -> fixture.getServiceData("hdm:ZigBee:000d6f0004b93361", "BatteryLevel"));
+ assertEquals(
+ "State request with URL https://null:8444/smarthome/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel failed with status code 500 and error code testErrorCode",
+ e.getMessage());
+ }
+
+ @Test
+ void getServiceDataErrorNoRestExceptionResponse()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getServiceUrl(anyString(), anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+ when(response.getStatus()).thenReturn(500);
+ when(response.getContentAsString()).thenReturn("");
+ when(request.send()).thenReturn(response);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.GET))).thenReturn(request);
+
+ BoschSHCException e = assertThrows(BoschSHCException.class,
+ () -> fixture.getServiceData("hdm:ZigBee:000d6f0004b93361", "BatteryLevel"));
+ assertEquals(
+ "State request with URL https://null:8444/smarthome/devices/hdm:ZigBee:000d6f0004b93361/services/BatteryLevel failed with status code 500",
+ e.getMessage());
+ }
+
+ @Test
+ void putState() throws InterruptedException, TimeoutException, ExecutionException {
+ when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getServiceStateUrl(anyString(), anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(request.header(anyString(), anyString())).thenReturn(request);
+ ContentResponse response = mock(ContentResponse.class);
+
+ when(httpClient.createRequest(anyString(), same(HttpMethod.PUT), any(BinarySwitchServiceState.class)))
+ .thenReturn(request);
+ when(request.send()).thenReturn(response);
+
+ BinarySwitchServiceState binarySwitchState = new BinarySwitchServiceState();
+ binarySwitchState.on = true;
+ fixture.putState("hdm:ZigBee:f0d1b80000f2a3e9", "BinarySwitch", binarySwitchState);
+ }
+
+ @AfterEach
+ void afterEach() throws Exception {
+ fixture.dispose();
+ }
}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.bridge;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link JsonRpcRequest}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class JsonRpcRequestTest {
+
+ private @NonNullByDefault({}) JsonRpcRequest fixture;
+
+ @BeforeEach
+ protected void setUp() throws Exception {
+ fixture = new JsonRpcRequest("2.0", "RE/longPoll", new String[] { "subscriptionId", "20" });
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals("2.0", fixture.getJsonrpc());
+ assertEquals("RE/longPoll", fixture.getMethod());
+ assertArrayEquals(new String[] { "subscriptionId", "20" }, fixture.getParams());
+ }
+
+ @Test
+ public void testNoArgConstructor() {
+ fixture = new JsonRpcRequest();
+ assertEquals("", fixture.getJsonrpc());
+ assertEquals("", fixture.getMethod());
+ assertArrayEquals(new String[0], fixture.getParams());
+ }
+
+ @Test
+ public void testSetJsonrpc() {
+ fixture.setJsonrpc("test");
+ assertEquals("test", fixture.getJsonrpc());
+ }
+
+ @Test
+ public void testSetMethod() {
+ fixture.setMethod("RE/subscribe");
+ assertEquals("RE/subscribe", fixture.getMethod());
+ }
+
+ @Test
+ public void testSetParams() {
+ fixture.setParams(new String[] { "com/bosch/sh/remote/*", null });
+ assertArrayEquals(new String[] { "com/bosch/sh/remote/*", null }, fixture.getParams());
+ }
+}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.bridge;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.api.Response.CompleteListener;
+import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.client.util.BufferingResponseListener;
+import org.eclipse.jetty.http.HttpMethod;
+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.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceServiceData;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.LongPollResult;
+import org.openhab.binding.boschshc.internal.devices.bridge.dto.SubscribeResult;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.exceptions.LongPollingFailedException;
+
+import com.google.gson.JsonObject;
+
+/**
+ * Unit tests for {@link LongPolling}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+@ExtendWith(MockitoExtension.class)
+public class LongPollingTest {
+
+ /**
+ * A dummy implementation of {@link ScheduledFuture}.
+ * <p>
+ * This is required because we can not return <code>null</code> in the executor service test implementation (see
+ * below).
+ *
+ * @author David Pace - Initial contribution
+ *
+ * @param <T> The result type returned by this Future
+ */
+ private static class NullScheduledFuture<T> implements ScheduledFuture<T> {
+
+ @Override
+ public long getDelay(@Nullable TimeUnit unit) {
+ return 0;
+ }
+
+ @Override
+ public int compareTo(@Nullable Delayed o) {
+ return 0;
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return false;
+ }
+
+ @Override
+ public T get() throws InterruptedException, ExecutionException {
+ return null;
+ }
+
+ @Override
+ public T get(long timeout, @Nullable TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return null;
+ }
+ }
+
+ /**
+ * Executor service implementation that runs all runnables in the same thread in order to enable deterministic
+ * testing.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+ private static class SameThreadExecutorService extends AbstractExecutorService implements ScheduledExecutorService {
+
+ private volatile boolean terminated;
+
+ @Override
+ public void shutdown() {
+ terminated = true;
+ }
+
+ @NonNullByDefault({})
+ @Override
+ public List<Runnable> shutdownNow() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return terminated;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return terminated;
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, @Nullable TimeUnit unit) throws InterruptedException {
+ shutdown();
+ return terminated;
+ }
+
+ @Override
+ public void execute(@Nullable Runnable command) {
+ if (command != null) {
+ // execute in the same thread in unit tests
+ command.run();
+ }
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(@Nullable Runnable command, long delay, @Nullable TimeUnit unit) {
+ // not used in this tests
+ return new NullScheduledFuture<Object>();
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(@Nullable Callable<V> callable, long delay, @Nullable TimeUnit unit) {
+ return new NullScheduledFuture<V>();
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(@Nullable Runnable command, long initialDelay, long period,
+ @Nullable TimeUnit unit) {
+ if (command != null) {
+ command.run();
+ }
+ return new NullScheduledFuture<Object>();
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(@Nullable Runnable command, long initialDelay, long delay,
+ @Nullable TimeUnit unit) {
+ if (command != null) {
+ command.run();
+ }
+ return new NullScheduledFuture<Object>();
+ }
+ }
+
+ private @NonNullByDefault({}) LongPolling fixture;
+
+ private @NonNullByDefault({}) BoschHttpClient httpClient;
+
+ private @Mock @NonNullByDefault({}) Consumer<@NonNull LongPollResult> longPollHandler;
+
+ private @Mock @NonNullByDefault({}) Consumer<@NonNull Throwable> failureHandler;
+
+ @BeforeEach
+ void beforeEach() {
+ fixture = new LongPolling(new SameThreadExecutorService(), longPollHandler, failureHandler);
+ httpClient = mock(BoschHttpClient.class);
+ }
+
+ @Test
+ void start() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ // when(httpClient.getBoschSmartHomeUrl(anyString())).thenCallRealMethod();
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+
+ Request subscribeRequest = mock(Request.class);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.POST),
+ argThat((JsonRpcRequest r) -> r.method.equals("RE/subscribe")))).thenReturn(subscribeRequest);
+ SubscribeResult subscribeResult = new SubscribeResult();
+ when(httpClient.sendRequest(any(), same(SubscribeResult.class), any(), any())).thenReturn(subscribeResult);
+
+ Request longPollRequest = mock(Request.class);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.POST),
+ argThat((JsonRpcRequest r) -> r.method.equals("RE/longPoll")))).thenReturn(longPollRequest);
+
+ fixture.start(httpClient);
+
+ ArgumentCaptor<CompleteListener> completeListener = ArgumentCaptor.forClass(CompleteListener.class);
+ verify(longPollRequest).send(completeListener.capture());
+
+ BufferingResponseListener bufferingResponseListener = (BufferingResponseListener) completeListener.getValue();
+
+ String longPollResultJSON = "{\"result\":[{\"path\":\"/devices/hdm:HomeMaticIP:3014F711A0001916D859A8A9/services/PowerSwitch\",\"@type\":\"DeviceServiceData\",\"id\":\"PowerSwitch\",\"state\":{\"@type\":\"powerSwitchState\",\"switchState\":\"ON\"},\"deviceId\":\"hdm:HomeMaticIP:3014F711A0001916D859A8A9\"}],\"jsonrpc\":\"2.0\"}\n";
+ Response response = mock(Response.class);
+ bufferingResponseListener.onContent(response,
+ ByteBuffer.wrap(longPollResultJSON.getBytes(StandardCharsets.UTF_8)));
+
+ Result result = mock(Result.class);
+ bufferingResponseListener.onComplete(result);
+
+ ArgumentCaptor<LongPollResult> longPollResultCaptor = ArgumentCaptor.forClass(LongPollResult.class);
+ verify(longPollHandler).accept(longPollResultCaptor.capture());
+ LongPollResult longPollResult = longPollResultCaptor.getValue();
+ assertEquals(1, longPollResult.result.size());
+ DeviceServiceData longPollResultItem = longPollResult.result.get(0);
+ assertEquals("hdm:HomeMaticIP:3014F711A0001916D859A8A9", longPollResultItem.deviceId);
+ assertEquals("/devices/hdm:HomeMaticIP:3014F711A0001916D859A8A9/services/PowerSwitch", longPollResultItem.path);
+ assertEquals("PowerSwitch", longPollResultItem.id);
+ JsonObject stateObject = (JsonObject) longPollResultItem.state;
+ assertNotNull(stateObject);
+ assertEquals("ON", stateObject.get("switchState").getAsString());
+ }
+
+ @Test
+ void startSubscriptionFailure()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.sendRequest(any(), same(SubscribeResult.class), any(), any()))
+ .thenThrow(new ExecutionException("Subscription failed.", null));
+
+ LongPollingFailedException e = assertThrows(LongPollingFailedException.class, () -> fixture.start(httpClient));
+ assertTrue(e.getMessage().contains("Subscription failed."));
+ }
+
+ @Test
+ void startLongPollFailure() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+
+ Request request = mock(Request.class);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.POST), any(JsonRpcRequest.class)))
+ .thenReturn(request);
+ SubscribeResult subscribeResult = new SubscribeResult();
+ when(httpClient.sendRequest(any(), same(SubscribeResult.class), any(), any())).thenReturn(subscribeResult);
+
+ Request longPollRequest = mock(Request.class);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.POST),
+ argThat((JsonRpcRequest r) -> r.method.equals("RE/longPoll")))).thenReturn(longPollRequest);
+
+ fixture.start(httpClient);
+
+ ArgumentCaptor<CompleteListener> completeListener = ArgumentCaptor.forClass(CompleteListener.class);
+ verify(longPollRequest).send(completeListener.capture());
+
+ BufferingResponseListener bufferingResponseListener = (BufferingResponseListener) completeListener.getValue();
+
+ Result result = mock(Result.class);
+ ExecutionException exception = new ExecutionException("test exception", null);
+ when(result.getFailure()).thenReturn(exception);
+ bufferingResponseListener.onComplete(result);
+
+ ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class);
+ verify(failureHandler).accept(throwableCaptor.capture());
+ Throwable t = throwableCaptor.getValue();
+ assertEquals("Unexpected exception during long polling request", t.getMessage());
+ assertSame(exception, t.getCause());
+ }
+
+ @Test
+ void startSubscriptionInvalid()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ when(httpClient.getBoschShcUrl(anyString())).thenCallRealMethod();
+
+ Request subscribeRequest = mock(Request.class);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.POST),
+ argThat((JsonRpcRequest r) -> r.method.equals("RE/subscribe")))).thenReturn(subscribeRequest);
+ SubscribeResult subscribeResult = new SubscribeResult();
+ when(httpClient.sendRequest(any(), same(SubscribeResult.class), any(), any())).thenReturn(subscribeResult);
+
+ Request longPollRequest = mock(Request.class);
+ when(httpClient.createRequest(anyString(), same(HttpMethod.POST),
+ argThat((JsonRpcRequest r) -> r.method.equals("RE/longPoll")))).thenReturn(longPollRequest);
+
+ fixture.start(httpClient);
+
+ ArgumentCaptor<CompleteListener> completeListener = ArgumentCaptor.forClass(CompleteListener.class);
+ verify(longPollRequest).send(completeListener.capture());
+
+ BufferingResponseListener bufferingResponseListener = (BufferingResponseListener) completeListener.getValue();
+
+ String longPollResultJSON = "{\"jsonrpc\":\"2.0\",\"error\": {\"code\":-32001,\"message\":\"No subscription with id: e8fei62b0-0\"}}\n";
+ Response response = mock(Response.class);
+ bufferingResponseListener.onContent(response,
+ ByteBuffer.wrap(longPollResultJSON.getBytes(StandardCharsets.UTF_8)));
+
+ Result result = mock(Result.class);
+ bufferingResponseListener.onComplete(result);
+ }
+
+ @AfterEach
+ void afterEach() {
+ fixture.stop();
+ }
+}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.bridge.dto;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link DeviceServiceData}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+public class DeviceServiceDataTest {
+
+ private DeviceServiceData fixture;
+
+ @BeforeEach
+ void beforeEach() {
+ fixture = new DeviceServiceData();
+ fixture.deviceId = "64-da-a0-02-14-9b";
+ }
+
+ @Test
+ public void testToString() {
+ assertEquals("64-da-a0-02-14-9b state: DeviceServiceData", fixture.toString());
+ }
+}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.bridge.dto;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link Device}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class DeviceTest {
+
+ public static Device createTestDevice() {
+ Device device = new Device();
+ device.type = "device";
+ device.rootDeviceId = "64-da-a0-02-14-9b";
+ device.id = "hdm:HomeMaticIP:3014F711A00004953859F31B";
+ device.deviceServiceIds = Collections
+ .unmodifiableList(List.of("PowerMeter", "PowerSwitch", "PowerSwitchProgram", "Routing"));
+ device.manufacturer = "BOSCH";
+ device.roomId = "hz_3";
+ device.deviceModel = "PSM";
+ device.serial = "3014F711A00004953859F31B";
+ device.profile = "GENERIC";
+ device.name = "Coffee Machine";
+ device.status = "AVAILABLE";
+ return device;
+ }
+
+ private @NonNullByDefault({}) Device fixture;
+
+ @BeforeEach
+ void beforeEach() {
+ fixture = createTestDevice();
+ }
+
+ @Test
+ void testIsValid() {
+ assertTrue(Device.isValid(fixture));
+ }
+
+ @Test
+ public void testToString() {
+ assertEquals(
+ "Type device; RootDeviceId: 64-da-a0-02-14-9b; Id: hdm:HomeMaticIP:3014F711A00004953859F31B; Device Service Ids: PowerMeter, PowerSwitch, PowerSwitchProgram, Routing; Manufacturer: BOSCH; Room Id: hz_3; Device Model: PSM; Serial: 3014F711A00004953859F31B; Profile: GENERIC; Name: Coffee Machine; Status: AVAILABLE; Child Device Ids: null ",
+ fixture.toString());
+ }
+}
*/
package org.openhab.binding.boschshc.internal.devices.bridge.dto;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
private final Gson gson = new Gson();
@Test
- public void noResultsForErrorResult() {
+ void noResultsForErrorResult() {
LongPollResult longPollResult = gson.fromJson(
"{\"jsonrpc\":\"2.0\", \"error\": { \"code\":-32001, \"message\":\"No subscription with id: e8fei62b0-0\" } }",
LongPollResult.class);
- assertNotEquals(null, longPollResult);
- if (longPollResult != null) {
- assertEquals(null, longPollResult.result);
- }
+ assertNotNull(longPollResult);
+ assertEquals(null, longPollResult.result);
}
}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.camera;
+
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.openhab.binding.boschshc.internal.devices.AbstractBoschSHCDeviceHandlerTest;
+import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.cameranotification.CameraNotificationState;
+import org.openhab.binding.boschshc.internal.services.cameranotification.dto.CameraNotificationServiceState;
+import org.openhab.binding.boschshc.internal.services.privacymode.PrivacyModeState;
+import org.openhab.binding.boschshc.internal.services.privacymode.dto.PrivacyModeServiceState;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingTypeUID;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+/**
+ * Unit tests for {@link CameraHandler}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class CameraHandlerTest extends AbstractBoschSHCDeviceHandlerTest<CameraHandler> {
+
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<PrivacyModeServiceState> privacyModeServiceStateCaptor;
+
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<CameraNotificationServiceState> cameraNotificationServiceStateCaptor;
+
+ @Override
+ protected CameraHandler createFixture() {
+ return new CameraHandler(getThing());
+ }
+
+ @Override
+ protected ThingTypeUID getThingTypeUID() {
+ return BoschSHCBindingConstants.THING_TYPE_CAMERA_360;
+ }
+
+ @Override
+ protected String getDeviceID() {
+ return "8e28ce2d-e7bf-3e3d-8e3a-a78de61b493e";
+ }
+
+ @Test
+ public void testHandleCommandPrivacyMode()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_PRIVACY_MODE),
+ OnOffType.ON);
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("PrivacyMode"),
+ privacyModeServiceStateCaptor.capture());
+ PrivacyModeServiceState state = privacyModeServiceStateCaptor.getValue();
+ assertSame(PrivacyModeState.ENABLED, state.value);
+
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_PRIVACY_MODE),
+ OnOffType.OFF);
+ verify(getBridgeHandler(), times(2)).putState(eq(getDeviceID()), eq("PrivacyMode"),
+ privacyModeServiceStateCaptor.capture());
+ state = privacyModeServiceStateCaptor.getValue();
+ assertSame(PrivacyModeState.DISABLED, state.value);
+ }
+
+ @Test
+ public void testHandleCommandCameraNotification()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CAMERA_NOTIFICATION),
+ OnOffType.ON);
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("CameraNotification"),
+ cameraNotificationServiceStateCaptor.capture());
+ CameraNotificationServiceState state = cameraNotificationServiceStateCaptor.getValue();
+ assertSame(CameraNotificationState.ENABLED, state.value);
+
+ getFixture().handleCommand(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CAMERA_NOTIFICATION),
+ OnOffType.OFF);
+ verify(getBridgeHandler(), times(2)).putState(eq(getDeviceID()), eq("CameraNotification"),
+ cameraNotificationServiceStateCaptor.capture());
+ state = cameraNotificationServiceStateCaptor.getValue();
+ assertSame(CameraNotificationState.DISABLED, state.value);
+ }
+
+ @Test
+ public void testUpdateChannelsPrivacyModeState() {
+ JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"privacyModeState\",\"value\":\"ENABLED\"}");
+ getFixture().processUpdate("PrivacyMode", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_PRIVACY_MODE), OnOffType.ON);
+
+ jsonObject = JsonParser.parseString("{\"@type\":\"privacyModeState\",\"value\":\"DISABLED\"}");
+ getFixture().processUpdate("PrivacyMode", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_PRIVACY_MODE), OnOffType.OFF);
+ }
+
+ @Test
+ public void testUpdateChannelsCameraNotificationState() {
+ JsonElement jsonObject = JsonParser
+ .parseString("{\"@type\":\"cameraNotificationState\",\"value\":\"ENABLED\"}");
+ getFixture().processUpdate("CameraNotification", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CAMERA_NOTIFICATION),
+ OnOffType.ON);
+
+ jsonObject = JsonParser.parseString("{\"@type\":\"cameraNotificationState\",\"value\":\"DISABLED\"}");
+ getFixture().processUpdate("CameraNotification", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CAMERA_NOTIFICATION),
+ OnOffType.OFF);
+ }
+}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.climatecontrol;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import javax.measure.quantity.Temperature;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.openhab.binding.boschshc.internal.devices.AbstractBoschSHCDeviceHandlerTest;
+import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.roomclimatecontrol.dto.RoomClimateControlServiceState;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingTypeUID;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+/**
+ * Unit tests for {@link ClimateControlHandler}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class ClimateControlHandlerTest extends AbstractBoschSHCDeviceHandlerTest<ClimateControlHandler> {
+
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<RoomClimateControlServiceState> roomClimateControlServiceStateCaptor;
+
+ @Override
+ protected String getDeviceID() {
+ return "hdm:ZigBee:abcd6fc012ad25b1";
+ }
+
+ @Override
+ protected ClimateControlHandler createFixture() {
+ return new ClimateControlHandler(getThing());
+ }
+
+ @Override
+ protected ThingTypeUID getThingTypeUID() {
+ return BoschSHCBindingConstants.THING_TYPE_CLIMATE_CONTROL;
+ }
+
+ @Test
+ public void testHandleCommandRoomClimateControlService()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ QuantityType<Temperature> temperature = new QuantityType<>(21.5, SIUnits.CELSIUS);
+ getFixture().handleCommand(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SETPOINT_TEMPERATURE),
+ temperature);
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("RoomClimateControl"),
+ roomClimateControlServiceStateCaptor.capture());
+ RoomClimateControlServiceState state = roomClimateControlServiceStateCaptor.getValue();
+ assertEquals(temperature, state.getSetpointTemperatureState());
+ }
+
+ @Test
+ public void testUpdateChannelsTemperatureLevelService() {
+ JsonElement jsonObject = JsonParser.parseString(
+ "{\n" + " \"@type\": \"temperatureLevelState\",\n" + " \"temperature\": 21.5\n" + " }");
+ getFixture().processUpdate("TemperatureLevel", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE),
+ new QuantityType<Temperature>(21.5, SIUnits.CELSIUS));
+ }
+
+ @Test
+ public void testUpdateChannelsRoomClimateControlService() {
+ JsonElement jsonObject = JsonParser.parseString(
+ "{\n" + " \"@type\": \"climateControlState\",\n" + " \"setpointTemperature\": 21.5\n" + " }");
+ getFixture().processUpdate("RoomClimateControl", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SETPOINT_TEMPERATURE),
+ new QuantityType<Temperature>(21.5, SIUnits.CELSIUS));
+ }
+}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.intrusion;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.openhab.binding.boschshc.internal.devices.AbstractBoschSHCHandlerTest;
+import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.binding.boschshc.internal.services.intrusion.actions.arm.dto.ArmActionRequest;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingTypeUID;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+/**
+ * Unit test for {@link IntrusionDetectionHandler}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class IntrusionDetectionHandlerTest extends AbstractBoschSHCHandlerTest<IntrusionDetectionHandler> {
+
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<ArmActionRequest> armActionRequestCaptor;
+
+ @Override
+ protected IntrusionDetectionHandler createFixture() {
+ return new IntrusionDetectionHandler(getThing());
+ }
+
+ @Override
+ protected ThingTypeUID getThingTypeUID() {
+ return BoschSHCBindingConstants.THING_TYPE_INTRUSION_DETECTION_SYSTEM;
+ }
+
+ @Test
+ public void testHandleCommandArmAction() throws InterruptedException, TimeoutException, ExecutionException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ARM_ACTION),
+ new StringType("0"));
+ verify(getBridgeHandler()).postAction(eq("intrusion/actions/arm"), armActionRequestCaptor.capture());
+ ArmActionRequest armRequest = armActionRequestCaptor.getValue();
+ assertEquals("0", armRequest.profileId);
+ }
+
+ @Test
+ public void testHandleCommandDisarmAction() throws InterruptedException, TimeoutException, ExecutionException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_DISARM_ACTION),
+ OnOffType.ON);
+ verify(getBridgeHandler()).postAction("intrusion/actions/disarm");
+ }
+
+ @Test
+ public void testHandleCommandMuteAction() throws InterruptedException, TimeoutException, ExecutionException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_MUTE_ACTION),
+ OnOffType.ON);
+ verify(getBridgeHandler()).postAction("intrusion/actions/mute");
+ }
+
+ @Test
+ public void testUpdateChannelsIntrusionDetectionSystemState() {
+ JsonElement jsonObject = JsonParser.parseString("{\n" + " \"@type\": \"systemState\",\n"
+ + " \"systemAvailability\": {\n" + " \"@type\": \"systemAvailabilityState\",\n"
+ + " \"available\": true,\n" + " \"deleted\": false\n" + " },\n"
+ + " \"armingState\": {\n" + " \"@type\": \"armingState\",\n"
+ + " \"state\": \"SYSTEM_DISARMED\",\n" + " \"deleted\": false\n" + " },\n"
+ + " \"alarmState\": {\n" + " \"@type\": \"alarmState\",\n"
+ + " \"value\": \"ALARM_OFF\",\n" + " \"incidents\": [],\n"
+ + " \"deleted\": false\n" + " },\n" + " \"activeConfigurationProfile\": {\n"
+ + " \"@type\": \"activeConfigurationProfile\",\n" + " \"deleted\": false\n"
+ + " },\n" + " \"securityGapState\": {\n" + " \"@type\": \"securityGapState\",\n"
+ + " \"securityGaps\": [],\n" + " \"deleted\": false\n" + " },\n"
+ + " \"deleted\": false\n" + " }\n");
+ getFixture().processUpdate(BoschSHCBindingConstants.SERVICE_INTRUSION_DETECTION, jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SYSTEM_AVAILABILITY),
+ OnOffType.ON);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ARMING_STATE),
+ new StringType("SYSTEM_DISARMED"));
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ALARM_STATE),
+ new StringType("ALARM_OFF"));
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ACTIVE_CONFIGURATION_PROFILE),
+ new StringType(null));
+ }
+
+ @Test
+ public void testUpdateChannelsIntrusionDetectionControlState() {
+ JsonElement jsonObject = JsonParser.parseString("{\n" + " \"@type\": \"intrusionDetectionControlState\",\n"
+ + " \"activeProfile\": \"0\",\n" + " \"alarmActivationDelayTime\": 30,\n" + " \"actuators\": [\n"
+ + " {\n" + " \"readonly\": false,\n" + " \"active\": true,\n"
+ + " \"id\": \"intrusion:video\"\n" + " },\n" + " {\n" + " \"readonly\": false,\n"
+ + " \"active\": false,\n" + " \"id\": \"intrusion:siren\"\n" + " }\n" + " ],\n"
+ + " \"remainingTimeUntilArmed\": 29559,\n" + " \"armActivationDelayTime\": 30,\n"
+ + " \"triggers\": [\n" + " {\n" + " \"readonly\": false,\n" + " \"active\": true,\n"
+ + " \"id\": \"hdm:ZigBee:000d6f0012f02378\"\n" + " }\n" + " ],\n"
+ + " \"value\": \"SYSTEM_ARMING\"\n" + " }");
+ getFixture().processUpdate("IntrusionDetectionControl", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ARMING_STATE),
+ new StringType("SYSTEM_ARMING"));
+ }
+
+ @Test
+ public void testUpdateChannelsSurveillanceAlarmState() {
+ JsonElement jsonObject = JsonParser.parseString("{\n" + " \"@type\": \"surveillanceAlarmState\",\n"
+ + " \"incidents\": [\n" + " {\n" + " \"triggerName\": \"Motion Detector\",\n"
+ + " \"locationId\": \"hz_5\",\n" + " \"location\": \"Living Room\",\n"
+ + " \"id\": \"hdm:ZigBee:000d6f0012f02342\",\n" + " \"time\": 1652615755336,\n"
+ + " \"type\": \"INTRUSION\"\n" + " }\n" + " ],\n" + " \"value\": \"ALARM_ON\"\n" + " }");
+ getFixture().processUpdate("SurveillanceAlarm", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ALARM_STATE),
+ new StringType("ALARM_ON"));
+ }
+}
*/
package org.openhab.binding.boschshc.internal.devices.motiondetector;
+import static org.mockito.Mockito.verify;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingTypeUID;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
/**
* Unit Tests for {@link MotionDetectorHandler}.
*
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_MOTION_DETECTOR;
}
+
+ @Test
+ public void testUpdateChannelsLatestMotionService() {
+ JsonElement jsonObject = JsonParser.parseString("{\n" + " \"@type\": \"latestMotionState\",\n"
+ + " \"latestMotionDetected\": \"2020-04-03T19:02:19.054Z\"\n" + " }");
+ getFixture().processUpdate("LatestMotion", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LATEST_MOTION),
+ new DateTimeType("2020-04-03T19:02:19.054Z"));
+ }
}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.devices.shuttercontrol;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.openhab.binding.boschshc.internal.devices.AbstractBoschSHCDeviceHandlerTest;
+import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.shuttercontrol.OperationState;
+import org.openhab.binding.boschshc.internal.services.shuttercontrol.dto.ShutterControlServiceState;
+import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.StopMoveType;
+import org.openhab.core.library.types.UpDownType;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingTypeUID;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+/**
+ * Unit tests for {@link ShutterControlHandler}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class ShutterControlHandlerTest extends AbstractBoschSHCDeviceHandlerTest<ShutterControlHandler> {
+
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<ShutterControlServiceState> shutterControlServiceStateCaptor;
+
+ @Override
+ protected String getDeviceID() {
+ return "hdm:ZigBee:abcd6fc012ad25b1";
+ }
+
+ @Override
+ protected ShutterControlHandler createFixture() {
+ return new ShutterControlHandler(getThing());
+ }
+
+ @Override
+ protected ThingTypeUID getThingTypeUID() {
+ return BoschSHCBindingConstants.THING_TYPE_SHUTTER_CONTROL;
+ }
+
+ @Test
+ public void testHandleCommandUpDownType()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LEVEL),
+ UpDownType.UP);
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("ShutterControl"),
+ shutterControlServiceStateCaptor.capture());
+ ShutterControlServiceState state = shutterControlServiceStateCaptor.getValue();
+ assertEquals(1d, state.level);
+
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LEVEL),
+ UpDownType.DOWN);
+ verify(getBridgeHandler(), times(2)).putState(eq(getDeviceID()), eq("ShutterControl"),
+ shutterControlServiceStateCaptor.capture());
+ state = shutterControlServiceStateCaptor.getValue();
+ assertEquals(0d, state.level);
+ }
+
+ @Test
+ public void testHandleCommandStopMoveType()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LEVEL),
+ StopMoveType.STOP);
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("ShutterControl"),
+ shutterControlServiceStateCaptor.capture());
+ ShutterControlServiceState state = shutterControlServiceStateCaptor.getValue();
+ assertEquals(OperationState.STOPPED, state.operationState);
+ }
+
+ @Test
+ public void testHandleCommandPercentType()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LEVEL),
+ new PercentType(42));
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("ShutterControl"),
+ shutterControlServiceStateCaptor.capture());
+ ShutterControlServiceState state = shutterControlServiceStateCaptor.getValue();
+ assertEquals(0.58d, state.level);
+ }
+
+ @Test
+ public void testUpdateChannelsShutterControlService() {
+ JsonElement jsonObject = JsonParser
+ .parseString("{\n" + " \"@type\": \"shutterControlState\",\n" + " \"level\": 0.58\n" + " }");
+ getFixture().processUpdate("ShutterControl", jsonObject);
+ verify(getCallback()).stateUpdated(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_LEVEL),
+ new PercentType(42));
+ }
+}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
* @author David Pace - Initial contribution
*
*/
+@NonNullByDefault
public class SmartBulbHandlerTest extends AbstractBoschSHCDeviceHandlerTest<SmartBulbHandler> {
- @Captor
- private ArgumentCaptor<BinarySwitchServiceState> binarySwitchServiceStateCaptor;
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<BinarySwitchServiceState> binarySwitchServiceStateCaptor;
- @Captor
- private ArgumentCaptor<MultiLevelSwitchServiceState> multiLevelSwitchServiceStateCaptor;
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<MultiLevelSwitchServiceState> multiLevelSwitchServiceStateCaptor;
- @Captor
- private ArgumentCaptor<HSBColorActuatorServiceState> hsbColorActuatorServiceStateCaptor;
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<HSBColorActuatorServiceState> hsbColorActuatorServiceStateCaptor;
@Override
protected SmartBulbHandler createFixture() {
}
@Test
- public void testHandleCommand_BinarySwitch()
+ public void testHandleCommandBinarySwitch()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
-
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_SWITCH),
OnOffType.ON);
verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("BinarySwitch"),
}
@Test
- public void testHandleCommand_MultiLevelSwitch()
+ public void testHandleCommandMultiLevelSwitch()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
-
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_BRIGHTNESS),
new PercentType(42));
verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("MultiLevelSwitch"),
}
@Test
- public void testHandleCommand_HSBColorActuator()
+ public void testHandleCommandHSBColorActuator()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
-
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_COLOR),
HSBType.BLUE);
verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("HSBColorActuator"),
}
@Test
- public void testUpdateChannel_BinarySwitchState() {
+ public void testUpdateChannelBinarySwitchState() {
JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"binarySwitchState\",\"on\":true}");
getFixture().processUpdate("BinarySwitch", jsonObject);
verify(getCallback()).stateUpdated(
}
@Test
- public void testUpdateChannel_MultiLevelSwitchState() {
+ public void testUpdateChannelMultiLevelSwitchState() {
JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"multiLevelSwitchState\",\"level\":16}");
getFixture().processUpdate("MultiLevelSwitch", jsonObject);
verify(getCallback()).stateUpdated(
}
@Test
- public void testUpdateChannel_HSBColorActuatorState() {
+ public void testUpdateChannelHSBColorActuatorState() {
JsonElement jsonObject = JsonParser.parseString("{\"colorTemperatureRange\": {\n" + " \"minCt\": 153,\n"
+ " \"maxCt\": 526\n" + " },\n" + " \"@type\": \"colorState\",\n"
+ " \"gamut\": \"LEDVANCE_GAMUT_A\",\n" + " \"rgb\": -12427}");
*/
package org.openhab.binding.boschshc.internal.devices.thermostat;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import javax.measure.quantity.Temperature;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.childlock.dto.ChildLockServiceState;
+import org.openhab.binding.boschshc.internal.services.childlock.dto.ChildLockState;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
/**
* Unit Tests for {@link ThermostatHandler}.
@NonNullByDefault
public class ThermostatHandlerTest extends AbstractBatteryPoweredDeviceHandlerTest<ThermostatHandler> {
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<ChildLockServiceState> childLockServiceStateCaptor;
+
@Override
protected ThermostatHandler createFixture() {
return new ThermostatHandler(getThing());
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_THERMOSTAT;
}
+
+ @Test
+ public void testHandleCommand()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_LOCK),
+ OnOffType.ON);
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("Thermostat"), childLockServiceStateCaptor.capture());
+ ChildLockServiceState state = childLockServiceStateCaptor.getValue();
+ assertSame(ChildLockState.ON, state.childLock);
+ }
+
+ @Test
+ public void testHandleCommandUnknownCommand() {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_LOCK),
+ new DecimalType(42));
+ ThingStatusInfo expectedThingStatusInfo = ThingStatusInfoBuilder
+ .create(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR)
+ .withDescription(
+ "Error when service Thermostat should handle command org.openhab.core.library.types.DecimalType: Thermostat: Can not handle command org.openhab.core.library.types.DecimalType")
+ .build();
+ verify(getCallback()).statusUpdated(getThing(), expectedThingStatusInfo);
+ }
+
+ @Test
+ public void testUpdateChannelsTemperatureLevelService() {
+ JsonElement jsonObject = JsonParser.parseString(
+ "{\n" + " \"@type\": \"temperatureLevelState\",\n" + " \"temperature\": 21.5\n" + " }");
+ getFixture().processUpdate("TemperatureLevel", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE),
+ new QuantityType<Temperature>(21.5, SIUnits.CELSIUS));
+ }
+
+ @Test
+ public void testUpdateChannelsValveTappetService() {
+ JsonElement jsonObject = JsonParser
+ .parseString("{\n" + " \"@type\": \"valveTappetState\",\n" + " \"position\": 42\n" + " }");
+ getFixture().processUpdate("ValveTappet", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_VALVE_TAPPET_POSITION),
+ new DecimalType(42));
+ }
+
+ @Test
+ public void testUpdateChannelsChildLockService() {
+ JsonElement jsonObject = JsonParser
+ .parseString("{\n" + " \"@type\": \"childLockState\",\n" + " \"childLock\": \"ON\"\n" + " }");
+ getFixture().processUpdate("Thermostat", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_LOCK), OnOffType.ON);
+ }
}
*/
package org.openhab.binding.boschshc.internal.devices.twinguard;
+import static org.mockito.Mockito.verify;
+
+import javax.measure.quantity.Dimensionless;
+import javax.measure.quantity.Temperature;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingTypeUID;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
/**
* Unit Tests for {@link TwinguardHandler}.
*
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_TWINGUARD;
}
+
+ @Test
+ public void testUpdateChannelsAirQualityLevelService() {
+ JsonElement jsonObject = JsonParser.parseString(
+ "{\"temperatureRating\":\"GOOD\",\"humidityRating\":\"MEDIUM\",\"purity\":620,\"@type\":\"airQualityLevelState\",\n"
+ + " \"purityRating\":\"GOOD\",\"temperature\":23.77,\"description\":\"LITTLE_DRY\",\"humidity\":32.69,\"combinedRating\":\"MEDIUM\"}");
+ getFixture().processUpdate("AirQualityLevel", jsonObject);
+
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE),
+ new QuantityType<Temperature>(23.77, SIUnits.CELSIUS));
+
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_RATING),
+ new StringType("GOOD"));
+
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_HUMIDITY),
+ new QuantityType<Dimensionless>(32.69, Units.PERCENT));
+
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_HUMIDITY_RATING),
+ new StringType("MEDIUM"));
+
+ verify(getCallback()).stateUpdated(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_PURITY),
+ new QuantityType<Dimensionless>(620, Units.PARTS_PER_MILLION));
+
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_PURITY_RATING),
+ new StringType("GOOD"));
+
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_AIR_DESCRIPTION),
+ new StringType("LITTLE_DRY"));
+
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_COMBINED_RATING),
+ new StringType("MEDIUM"));
+ }
}
*/
package org.openhab.binding.boschshc.internal.devices.wallthermostat;
+import static org.mockito.Mockito.verify;
+
+import javax.measure.quantity.Dimensionless;
+import javax.measure.quantity.Temperature;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingTypeUID;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
/**
* Unit Tests for {@link WallThermostatHandler}.
*
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_WALL_THERMOSTAT;
}
+
+ @Test
+ public void testUpdateChannelsTemperatureLevelService() {
+ JsonElement jsonObject = JsonParser.parseString(
+ "{\n" + " \"@type\": \"temperatureLevelState\",\n" + " \"temperature\": 21.5\n" + " }");
+ getFixture().processUpdate("TemperatureLevel", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE),
+ new QuantityType<Temperature>(21.5, SIUnits.CELSIUS));
+ }
+
+ @Test
+ public void testUpdateChannelsHumidityLevelService() {
+ JsonElement jsonObject = JsonParser
+ .parseString("{\n" + " \"@type\": \"humidityLevelState\",\n" + " \"humidity\": 42.5\n" + " }");
+ getFixture().processUpdate("HumidityLevel", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_HUMIDITY),
+ new QuantityType<Dimensionless>(42.5, Units.PERCENT));
+ }
}
*/
package org.openhab.binding.boschshc.internal.devices.windowcontact;
+import static org.mockito.Mockito.verify;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.core.library.types.OpenClosedType;
+import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingTypeUID;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
/**
* Unit Tests for {@link WindowContactHandler}.
*
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_WINDOW_CONTACT;
}
+
+ @Test
+ public void testUpdateChannelsShutterContactService() {
+ JsonElement jsonObject = JsonParser
+ .parseString("{\n" + " \"@type\": \"shutterContactState\",\n" + " \"value\": \"OPEN\"\n" + " }");
+ getFixture().processUpdate("ShutterContact", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CONTACT), OpenClosedType.OPEN);
+
+ jsonObject = JsonParser
+ .parseString("{\n" + " \"@type\": \"shutterContactState\",\n" + " \"value\": \"CLOSED\"\n" + " }");
+ getFixture().processUpdate("ShutterContact", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CONTACT), OpenClosedType.CLOSED);
+ }
}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.exceptions;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link LongPollingFailedException}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class LongPollingFailedExceptionTest {
+
+ @Test
+ public void testConstructor() {
+ RuntimeException testException = new RuntimeException("test exception");
+ LongPollingFailedException longPollingFailedException = new LongPollingFailedException("message",
+ testException);
+ assertEquals("message", longPollingFailedException.getMessage());
+ assertSame(testException, longPollingFailedException.getCause());
+ }
+}
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.exceptions;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link PairingFailedException}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class PairingFailedExceptionTest {
+
+ @Test
+ public void testConstructor() {
+ PairingFailedException fixture = new PairingFailedException();
+ assertNotNull(fixture);
+ assertNull(fixture.getMessage());
+ assertNull(fixture.getCause());
+ }
+
+ @Test
+ public void testConstructorWithMessage() {
+ PairingFailedException fixture = new PairingFailedException("message");
+ assertNotNull(fixture);
+ assertEquals("message", fixture.getMessage());
+ assertNull(fixture.getCause());
+ }
+
+ @Test
+ public void testConstructorWithMessageAndCause() {
+ RuntimeException testException = new RuntimeException("test exception");
+ PairingFailedException fixture = new PairingFailedException("message", testException);
+ assertNotNull(fixture);
+ assertEquals("message", fixture.getMessage());
+ assertSame(testException, fixture.getCause());
+ }
+}
import java.util.ArrayList;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceServiceData;
import org.openhab.binding.boschshc.internal.devices.bridge.dto.Fault;
* @author David Pace - Initial contribution
*
*/
+@NonNullByDefault
class BatteryLevelTest {
@Test
*/
package org.openhab.binding.boschshc.internal.services.dto;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
private final Gson gson = new Gson();
@Test
- public void fromJson_nullStateForDifferentType() {
+ public void fromJsonNullStateForDifferentType() {
var state = BoschSHCServiceState.fromJson(gson.fromJson("{\"@type\":\"differentState\"}", JsonObject.class),
TestState.class);
assertEquals(null, state);
}
@Test
- public void fromJson_stateObjectForValidJson() {
+ public void fromJsonStateObjectForValidJson() {
var state = BoschSHCServiceState.fromJson(gson.fromJson("{\"@type\":\"testState\"}", JsonObject.class),
TestState.class);
assertNotEquals(null, state);
* This checks for a bug we had where the expected type stayed the same for different state classes
*/
@Test
- public void fromJson_stateObjectForValidJsonAfterOtherState() {
+ public void fromJsonStateObjectForValidJsonAfterOtherState() {
BoschSHCServiceState.fromJson(gson.fromJson("{\"@type\":\"testState\"}", JsonObject.class), TestState.class);
var state2 = BoschSHCServiceState.fromJson(gson.fromJson("{\"@type\":\"testState2\"}", JsonObject.class),
TestState2.class);
--- /dev/null
+/**
+ * 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.binding.boschshc.internal.services.dto;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link JsonRestExceptionResponse}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class JsonRestExceptionResponseTest {
+
+ private @NonNullByDefault({}) JsonRestExceptionResponse fixture;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ fixture = new JsonRestExceptionResponse();
+ }
+
+ @Test
+ public void testIsValid() {
+ assertFalse(JsonRestExceptionResponse.isValid(null));
+ assertTrue(JsonRestExceptionResponse.isValid(fixture));
+ fixture.errorCode = null;
+ assertFalse(JsonRestExceptionResponse.isValid(fixture));
+ fixture.statusCode = null;
+ assertFalse(JsonRestExceptionResponse.isValid(fixture));
+ fixture.errorCode = "";
+ assertFalse(JsonRestExceptionResponse.isValid(fixture));
+ }
+}
*/
package org.openhab.binding.boschshc.internal.services.intrusion;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
/**
* Unit tests for {@link IntrusionDetectionControlStateService}.
- *
+ *
* @author David Pace - Initial contribution
*
*/
+@NonNullByDefault
@ExtendWith(MockitoExtension.class)
class IntrusionDetectionControlStateServiceTest {
- private IntrusionDetectionControlStateService fixture;
+ private @NonNullByDefault({}) IntrusionDetectionControlStateService fixture;
- @Mock
- private BridgeHandler bridgeHandler;
+ private @Mock @NonNullByDefault({}) BridgeHandler bridgeHandler;
- @Mock
- private Consumer<IntrusionDetectionControlState> consumer;
+ private @Mock @NonNullByDefault({}) Consumer<IntrusionDetectionControlState> consumer;
- @Mock
- private IntrusionDetectionControlState testState;
+ private @Mock @NonNullByDefault({}) IntrusionDetectionControlState testState;
@BeforeEach
void beforeEach() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
package org.openhab.binding.boschshc.internal.services.intrusion;
import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
/**
* Unit tests for {@link IntrusionDetectionSystemStateService}.
- *
+ *
* @author David Pace - Initial contribution
*
*/
+@NonNullByDefault
@ExtendWith(MockitoExtension.class)
class IntrusionDetectionSystemStateServiceTest {
- private IntrusionDetectionSystemStateService fixture;
+ private @NonNullByDefault({}) IntrusionDetectionSystemStateService fixture;
- @Mock
- private BridgeHandler bridgeHandler;
+ private @Mock @NonNullByDefault({}) BridgeHandler bridgeHandler;
- @Mock
- private Consumer<IntrusionDetectionSystemState> consumer;
+ private @Mock @NonNullByDefault({}) Consumer<IntrusionDetectionSystemState> consumer;
- @Mock
- private IntrusionDetectionSystemState testState;
+ private @Mock @NonNullByDefault({}) IntrusionDetectionSystemState testState;
@BeforeEach
void beforeEach() {