2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.boschshc.internal.devices.relay;
15 import static org.hamcrest.CoreMatchers.notNullValue;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.hamcrest.Matchers.is;
18 import static org.mockito.ArgumentMatchers.any;
19 import static org.mockito.ArgumentMatchers.eq;
20 import static org.mockito.Mockito.times;
21 import static org.mockito.Mockito.verify;
23 import java.time.Instant;
24 import java.util.List;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.TimeoutException;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.junit.jupiter.api.Test;
31 import org.mockito.ArgumentCaptor;
32 import org.mockito.Captor;
33 import org.openhab.binding.boschshc.internal.devices.AbstractPowerSwitchHandlerTest;
34 import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
35 import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
36 import org.openhab.binding.boschshc.internal.services.childprotection.dto.ChildProtectionServiceState;
37 import org.openhab.binding.boschshc.internal.services.impulseswitch.ImpulseSwitchService;
38 import org.openhab.binding.boschshc.internal.services.impulseswitch.dto.ImpulseSwitchServiceState;
39 import org.openhab.core.library.types.DateTimeType;
40 import org.openhab.core.library.types.DecimalType;
41 import org.openhab.core.library.types.OnOffType;
42 import org.openhab.core.thing.ChannelUID;
43 import org.openhab.core.thing.ThingTypeUID;
44 import org.openhab.core.types.UnDefType;
46 import com.google.gson.JsonElement;
47 import com.google.gson.JsonParser;
50 * Unit tests for {@link RelayHandler}.
52 * @author David Pace - Initial contributions
56 class RelayHandlerTest extends AbstractPowerSwitchHandlerTest<RelayHandler> {
58 private @Captor @NonNullByDefault({}) ArgumentCaptor<ChildProtectionServiceState> childProtectionServiceStateCaptor;
60 private @Captor @NonNullByDefault({}) ArgumentCaptor<ImpulseSwitchServiceState> impulseSwitchServiceStateCaptor;
63 protected RelayHandler createFixture() {
64 return new RelayHandler(getThing());
68 protected ThingTypeUID getThingTypeUID() {
69 return BoschSHCBindingConstants.THING_TYPE_RELAY;
73 protected String getDeviceID() {
74 return "hdm:ZigBee:30XXXXXXXXXXXXXX";
78 void testUpdateChannelsCommunicationQualityService() {
81 "@type": "communicationQualityState",
85 JsonElement jsonObject = JsonParser.parseString(json);
87 getFixture().processUpdate("CommunicationQuality", jsonObject);
88 verify(getCallback()).stateUpdated(
89 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SIGNAL_STRENGTH),
94 "@type": "communicationQualityState",
98 jsonObject = JsonParser.parseString(json);
100 getFixture().processUpdate("CommunicationQuality", jsonObject);
101 verify(getCallback()).stateUpdated(
102 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SIGNAL_STRENGTH),
107 void testUpdateChannelsChildProtectionService() {
110 "@type": "ChildProtectionState",
111 "childLockActive": true
114 JsonElement jsonObject = JsonParser.parseString(json);
116 getFixture().processUpdate("ChildProtection", jsonObject);
117 verify(getCallback()).stateUpdated(
118 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_PROTECTION), OnOffType.ON);
122 void testUpdateChannelsImpulseSwitchService()
123 throws BoschSHCException, InterruptedException, TimeoutException, ExecutionException {
124 configureImpulseSwitchMode();
127 "@type": "ImpulseSwitchState",
128 "impulseState": true,
129 "impulseLength": 100,
130 "instantOfLastImpulse": "2024-04-14T15:52:31.677366Z"
133 JsonElement jsonObject = JsonParser.parseString(json);
135 getFixture().processUpdate("ImpulseSwitch", jsonObject);
136 verify(getCallback()).stateUpdated(
137 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_IMPULSE_SWITCH), OnOffType.ON);
138 verify(getCallback(), times(2)).stateUpdated(
139 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_IMPULSE_LENGTH),
140 new DecimalType(100));
141 verify(getCallback(), times(2)).stateUpdated(
142 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_INSTANT_OF_LAST_IMPULSE),
143 new DateTimeType("2024-04-14T15:52:31.677366Z"));
147 void testUpdateChannelsImpulseSwitchServiceNoInstantOfLastImpulse()
148 throws BoschSHCException, InterruptedException, TimeoutException, ExecutionException {
149 configureImpulseSwitchMode();
152 "@type": "ImpulseSwitchState",
153 "impulseState": true,
157 JsonElement jsonObject = JsonParser.parseString(json);
159 getFixture().processUpdate("ImpulseSwitch", jsonObject);
160 verify(getCallback()).stateUpdated(
161 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_IMPULSE_SWITCH), OnOffType.ON);
162 verify(getCallback(), times(2)).stateUpdated(
163 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_IMPULSE_LENGTH),
164 new DecimalType(100));
165 verify(getCallback()).stateUpdated(
166 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_INSTANT_OF_LAST_IMPULSE),
170 private void configureImpulseSwitchMode()
171 throws BoschSHCException, InterruptedException, TimeoutException, ExecutionException {
172 getDevice().deviceServiceIds = List.of(ImpulseSwitchService.IMPULSE_SWITCH_SERVICE_NAME);
173 getFixture().initialize();
175 assertThat(getFixture().getThing().getChannel(BoschSHCBindingConstants.CHANNEL_IMPULSE_SWITCH),
177 assertThat(getFixture().getThing().getChannel(BoschSHCBindingConstants.CHANNEL_IMPULSE_LENGTH),
179 assertThat(getFixture().getThing().getChannel(BoschSHCBindingConstants.CHANNEL_INSTANT_OF_LAST_IMPULSE),
183 JsonElement impulseSwitchServiceState = JsonParser.parseString("""
185 "@type": "ImpulseSwitchState",
186 "impulseState": false,
187 "impulseLength": 100,
188 "instantOfLastImpulse": "2024-04-14T15:52:31.677366Z"
191 getFixture().processUpdate(ImpulseSwitchService.IMPULSE_SWITCH_SERVICE_NAME, impulseSwitchServiceState);
195 void testHandleCommandChildProtection()
196 throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
197 getFixture().handleCommand(
198 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_PROTECTION), OnOffType.ON);
199 verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("ChildProtection"),
200 childProtectionServiceStateCaptor.capture());
201 ChildProtectionServiceState state = childProtectionServiceStateCaptor.getValue();
202 assertThat(state.childLockActive, is(true));
206 void testHandleCommandChildProtectionInvalidCommand()
207 throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
208 getFixture().handleCommand(
209 new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_PROTECTION),
211 verify(getBridgeHandler(), times(0)).putState(eq(getDeviceID()), eq("ChildProtection"), any());
215 void testHandleCommandImpulseStateOn()
216 throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
217 configureImpulseSwitchMode();
219 Instant testDate = Instant.now();
220 getFixture().setCurrentDateTimeProvider(() -> testDate);
222 getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_IMPULSE_SWITCH),
224 verify(getBridgeHandler()).putState(eq(getDeviceID()), eq(ImpulseSwitchService.IMPULSE_SWITCH_SERVICE_NAME),
225 impulseSwitchServiceStateCaptor.capture());
226 ImpulseSwitchServiceState state = impulseSwitchServiceStateCaptor.getValue();
227 assertThat(state.impulseState, is(true));
228 assertThat(state.impulseLength, is(100));
229 assertThat(state.instantOfLastImpulse, is(testDate.toString()));
233 void testHandleCommandImpulseLength()
234 throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
235 configureImpulseSwitchMode();
237 Instant testDate = Instant.now();
238 getFixture().setCurrentDateTimeProvider(() -> testDate);
240 getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_IMPULSE_LENGTH),
241 new DecimalType(15));
242 verify(getBridgeHandler()).putState(eq(getDeviceID()), eq(ImpulseSwitchService.IMPULSE_SWITCH_SERVICE_NAME),
243 impulseSwitchServiceStateCaptor.capture());
244 ImpulseSwitchServiceState state = impulseSwitchServiceStateCaptor.getValue();
245 assertThat(state.impulseState, is(false));
246 assertThat(state.impulseLength, is(15));
247 assertThat(state.instantOfLastImpulse, is("2024-04-14T15:52:31.677366Z"));
251 void testHandleCommandImpulseStateOff()
252 throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
253 getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_IMPULSE_SWITCH),
255 verify(getBridgeHandler(), times(0)).postState(eq(getDeviceID()),
256 eq(ImpulseSwitchService.IMPULSE_SWITCH_SERVICE_NAME), any());