[boschshc] Add unit tests (#14426)

Signed-off-by: David Pace <dev@davidpace.de>
This commit is contained in:
David Pace 2023-02-20 08:56:29 +01:00 committed by GitHub
parent 5bb3f834d4
commit 8306210a13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 2130 additions and 150 deletions

View File

@ -28,7 +28,7 @@ import org.openhab.core.thing.ThingTypeUID;
@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");

View File

@ -46,6 +46,7 @@ import org.openhab.core.thing.ThingStatusDetail;
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;
@ -95,8 +96,10 @@ public class BridgeHandler extends BaseBridgeHandler {
@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);
@ -190,8 +193,10 @@ public class BridgeHandler extends BaseBridgeHandler {
* 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 {
@ -482,7 +487,7 @@ public class BridgeHandler extends BaseBridgeHandler {
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));
}
});

View File

@ -12,13 +12,21 @@
*/
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;
@ -35,8 +43,20 @@ import com.google.gson.JsonParser;
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"
@ -44,15 +64,13 @@ public abstract class AbstractBatteryPoweredDeviceHandlerTest<T extends Abstract
+ " \"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"
@ -60,15 +78,13 @@ public abstract class AbstractBatteryPoweredDeviceHandlerTest<T extends Abstract
+ " \"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"
@ -76,15 +92,13 @@ public abstract class AbstractBatteryPoweredDeviceHandlerTest<T extends Abstract
+ " \"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\" }");
@ -97,7 +111,7 @@ public abstract class AbstractBatteryPoweredDeviceHandlerTest<T extends Abstract
}
@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"
@ -105,9 +119,21 @@ public abstract class AbstractBatteryPoweredDeviceHandlerTest<T extends Abstract
+ " \"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);
}
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.boschshc.internal.devices;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.config.core.Configuration;
/**
@ -21,8 +22,9 @@ 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() {

View File

@ -15,14 +15,20 @@ 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;
@ -38,32 +44,33 @@ import org.openhab.core.thing.binding.ThingHandlerCallback;
*
* @param <T> type of the handler to be tested
*/
@NonNullByDefault
@ExtendWith(MockitoExtension.class)
public abstract class AbstractSHCHandlerTest<T extends BoschSHCHandler> {
public abstract class AbstractBoschSHCHandlerTest<T extends BoschSHCHandler> {
private T fixture;
@Mock
private Thing thing;
private @Mock @NonNullByDefault({}) Thing thing;
@Mock
private Bridge bridge;
private @Mock @NonNullByDefault({}) Bridge bridge;
@Mock
private BridgeHandler bridgeHandler;
protected @Mock @NonNullByDefault({}) BridgeHandler bridgeHandler;
@Mock
private ThingHandlerCallback callback;
private @Mock @NonNullByDefault({}) ThingHandlerCallback callback;
protected AbstractBoschSHCHandlerTest() {
this.fixture = createFixture();
}
@BeforeEach
public void 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);
when(thing.getConfiguration()).thenReturn(getConfiguration());
lenient().when(thing.getConfiguration()).thenReturn(getConfiguration());
fixture.initialize();
}
@ -80,6 +87,10 @@ public abstract class AbstractSHCHandlerTest<T extends BoschSHCHandler> {
protected abstract ThingTypeUID getThingTypeUID();
protected ChannelUID getChannelUID(String channelID) {
return new ChannelUID(getThingUID(), channelID);
}
protected Configuration getConfiguration() {
return new Configuration();
}
@ -88,11 +99,11 @@ public abstract class AbstractSHCHandlerTest<T extends BoschSHCHandler> {
return thing;
}
public BridgeHandler getBridgeHandler() {
protected BridgeHandler getBridgeHandler() {
return bridgeHandler;
}
public ThingHandlerCallback getCallback() {
protected ThingHandlerCallback getCallback() {
return callback;
}

View File

@ -13,7 +13,7 @@
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;
@ -22,16 +22,19 @@ import java.util.concurrent.TimeoutException;
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;
@ -43,30 +46,42 @@ 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();
@ -74,36 +89,54 @@ public abstract class AbstractPowerSwitchHandlerTest<T extends AbstractPowerSwit
}
@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));
}
}

View File

@ -14,8 +14,7 @@ package org.openhab.binding.boschshc.internal.devices;
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;
@ -28,9 +27,14 @@ import org.openhab.binding.boschshc.internal.devices.smokedetector.SmokeDetector
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;
@ -51,7 +55,6 @@ public abstract class AbstractSmokeDetectorHandlerTest<T extends AbstractSmokeDe
@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()));
@ -83,9 +86,8 @@ public abstract class AbstractSmokeDetectorHandlerTest<T extends AbstractSmokeDe
}
@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"),
@ -95,7 +97,20 @@ public abstract class AbstractSmokeDetectorHandlerTest<T extends AbstractSmokeDe
}
@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(
@ -104,7 +119,7 @@ public abstract class AbstractSmokeDetectorHandlerTest<T extends AbstractSmokeDe
}
@Test
public void testUpdateChannel_SmokeDetectorCheckServiceState_Requests() {
public void testUpdateChannelSmokeDetectorCheckServiceStateRequests() {
JsonElement jsonObject = JsonParser
.parseString("{\"@type\":\"smokeDetectorCheckState\",\"value\":SMOKE_TEST_REQUESTED}");
getFixture().processUpdate("SmokeDetectorCheck", jsonObject);

View File

@ -0,0 +1,68 @@
/**
* 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);
}
}

View File

@ -13,17 +13,31 @@
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}.
@ -33,8 +47,7 @@ import org.openhab.binding.boschshc.internal.exceptions.PairingFailedException;
@NonNullByDefault
class BoschHttpClientTest {
@Nullable
private BoschHttpClient httpClient;
private @NonNullByDefault({}) BoschHttpClient httpClient;
@BeforeAll
static void beforeAll() {
@ -91,6 +104,53 @@ class BoschHttpClientTest {
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());
@ -104,16 +164,103 @@ class BoschHttpClientTest {
@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());
}
}

View File

@ -0,0 +1,35 @@
/**
* 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);
}
}

View File

@ -12,45 +12,101 @@
*/
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;
@Nullable
private BoschHttpClient httpClient;
private @NonNullByDefault({}) 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;
}
@ -69,4 +125,265 @@ class BridgeHandlerTest {
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();
}
}

View File

@ -0,0 +1,69 @@
/**
* 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());
}
}

View File

@ -0,0 +1,327 @@
/**
* 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();
}
}

View File

@ -0,0 +1,40 @@
/**
* 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());
}
}

View File

@ -0,0 +1,68 @@
/**
* 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());
}
}

View File

@ -12,8 +12,7 @@
*/
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;
@ -30,13 +29,11 @@ public class LongPollResultTest {
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);
}
}

View File

@ -0,0 +1,134 @@
/**
* 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);
}
}

View File

@ -0,0 +1,98 @@
/**
* 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));
}
}

View File

@ -0,0 +1,139 @@
/**
* 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"));
}
}

View File

@ -12,11 +12,19 @@
*/
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}.
*
@ -40,4 +48,14 @@ public class MotionDetectorHandlerTest extends AbstractBatteryPoweredDeviceHandl
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"));
}
}

View File

@ -0,0 +1,114 @@
/**
* 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));
}
}

View File

@ -19,6 +19,7 @@ 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;
@ -44,16 +45,14 @@ import com.google.gson.JsonParser;
* @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() {
@ -71,9 +70,8 @@ public class SmartBulbHandlerTest extends AbstractBoschSHCDeviceHandlerTest<Smar
}
@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"),
@ -90,9 +88,8 @@ public class SmartBulbHandlerTest extends AbstractBoschSHCDeviceHandlerTest<Smar
}
@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"),
@ -102,9 +99,8 @@ public class SmartBulbHandlerTest extends AbstractBoschSHCDeviceHandlerTest<Smar
}
@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"),
@ -114,7 +110,7 @@ public class SmartBulbHandlerTest extends AbstractBoschSHCDeviceHandlerTest<Smar
}
@Test
public void testUpdateChannel_BinarySwitchState() {
public void testUpdateChannelBinarySwitchState() {
JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"binarySwitchState\",\"on\":true}");
getFixture().processUpdate("BinarySwitch", jsonObject);
verify(getCallback()).stateUpdated(
@ -127,7 +123,7 @@ public class SmartBulbHandlerTest extends AbstractBoschSHCDeviceHandlerTest<Smar
}
@Test
public void testUpdateChannel_MultiLevelSwitchState() {
public void testUpdateChannelMultiLevelSwitchState() {
JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"multiLevelSwitchState\",\"level\":16}");
getFixture().processUpdate("MultiLevelSwitch", jsonObject);
verify(getCallback()).stateUpdated(
@ -135,7 +131,7 @@ public class SmartBulbHandlerTest extends AbstractBoschSHCDeviceHandlerTest<Smar
}
@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}");

View File

@ -12,10 +12,37 @@
*/
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}.
@ -26,6 +53,8 @@ import org.openhab.core.thing.ThingTypeUID;
@NonNullByDefault
public class ThermostatHandlerTest extends AbstractBatteryPoweredDeviceHandlerTest<ThermostatHandler> {
private @Captor @NonNullByDefault({}) ArgumentCaptor<ChildLockServiceState> childLockServiceStateCaptor;
@Override
protected ThermostatHandler createFixture() {
return new ThermostatHandler(getThing());
@ -40,4 +69,55 @@ public class ThermostatHandlerTest extends AbstractBatteryPoweredDeviceHandlerTe
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);
}
}

View File

@ -12,11 +12,25 @@
*/
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}.
*
@ -40,4 +54,43 @@ public class TwinguardHandlerTest extends AbstractSmokeDetectorHandlerTest<Twing
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"));
}
}

View File

@ -12,11 +12,24 @@
*/
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}.
*
@ -40,4 +53,24 @@ public class WallThermostatHandlerTest extends AbstractBatteryPoweredDeviceHandl
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));
}
}

View File

@ -12,11 +12,19 @@
*/
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}.
*
@ -40,4 +48,19 @@ public class WindowContactHandlerTest extends AbstractBatteryPoweredDeviceHandle
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);
}
}

View File

@ -0,0 +1,37 @@
/**
* 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());
}
}

View File

@ -0,0 +1,53 @@
/**
* 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());
}
}

View File

@ -16,6 +16,7 @@ import static org.junit.jupiter.api.Assertions.*;
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;
@ -30,6 +31,7 @@ import org.openhab.core.types.UnDefType;
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
class BatteryLevelTest {
@Test

View File

@ -12,8 +12,7 @@
*/
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;
@ -53,14 +52,14 @@ public class BoschSHCServiceStateTest {
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);
@ -70,7 +69,7 @@ public class BoschSHCServiceStateTest {
* 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);

View File

@ -0,0 +1,48 @@
/**
* 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));
}
}

View File

@ -12,17 +12,15 @@
*/
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;
@ -38,23 +36,21 @@ import com.google.gson.JsonParser;
/**
* 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 {

View File

@ -13,15 +13,14 @@
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;
@ -34,23 +33,21 @@ import org.openhab.binding.boschshc.internal.services.intrusion.dto.IntrusionDet
/**
* 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() {