2 * Copyright (c) 2010-2020 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.robonect.internal.handler;
15 import static org.junit.Assert.*;
16 import static org.mockito.ArgumentMatchers.eq;
17 import static org.mockito.Mockito.*;
19 import java.time.Month;
20 import java.time.ZoneId;
21 import java.time.ZonedDateTime;
23 import org.eclipse.jetty.client.HttpClient;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.ArgumentCaptor;
27 import org.mockito.Mock;
28 import org.mockito.Mockito;
29 import org.mockito.MockitoAnnotations;
30 import org.openhab.binding.robonect.internal.RobonectBindingConstants;
31 import org.openhab.binding.robonect.internal.RobonectClient;
32 import org.openhab.binding.robonect.internal.model.ErrorEntry;
33 import org.openhab.binding.robonect.internal.model.ErrorList;
34 import org.openhab.binding.robonect.internal.model.MowerInfo;
35 import org.openhab.binding.robonect.internal.model.MowerMode;
36 import org.openhab.binding.robonect.internal.model.MowerStatus;
37 import org.openhab.binding.robonect.internal.model.NextTimer;
38 import org.openhab.binding.robonect.internal.model.Status;
39 import org.openhab.binding.robonect.internal.model.Timer;
40 import org.openhab.binding.robonect.internal.model.Wlan;
41 import org.openhab.core.i18n.TimeZoneProvider;
42 import org.openhab.core.library.types.DateTimeType;
43 import org.openhab.core.library.types.DecimalType;
44 import org.openhab.core.library.types.OnOffType;
45 import org.openhab.core.library.types.QuantityType;
46 import org.openhab.core.library.types.StringType;
47 import org.openhab.core.thing.ChannelUID;
48 import org.openhab.core.thing.Thing;
49 import org.openhab.core.thing.ThingUID;
50 import org.openhab.core.thing.binding.ThingHandlerCallback;
51 import org.openhab.core.types.RefreshType;
52 import org.openhab.core.types.State;
53 import org.openhab.core.types.UnDefType;
56 * The goal of this class is to test RobonectHandler in isolation.
58 * @author Marco Meyer - Initial contribution
60 public class RobonectHandlerTest {
62 private RobonectHandler subject;
65 private Thing robonectThingMock;
68 private RobonectClient robonectClientMock;
71 private ThingHandlerCallback callbackMock;
74 private HttpClient httpClientMock;
77 private TimeZoneProvider timezoneProvider;
81 MockitoAnnotations.initMocks(this);
82 subject = new RobonectHandler(robonectThingMock, httpClientMock, timezoneProvider);
83 subject.setCallback(callbackMock);
84 subject.setRobonectClient(robonectClientMock);
86 Mockito.when(timezoneProvider.getTimeZone()).thenReturn(ZoneId.of("Europe/Berlin"));
90 public void shouldUpdateNextTimerChannelWithDateTimeState() throws InterruptedException {
91 ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
94 MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
95 Timer timer = new Timer();
96 timer.setStatus(Timer.TimerMode.ACTIVE);
97 NextTimer nextTimer = new NextTimer();
98 nextTimer.setDate("01.05.2017");
99 nextTimer.setTime("19:00:00");
100 nextTimer.setUnix("1493665200");
101 timer.setNext(nextTimer);
104 when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
105 when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
107 subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_TIMER_NEXT_TIMER),
108 RefreshType.REFRESH);
111 verify(callbackMock, times(1)).stateUpdated(
112 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_TIMER_NEXT_TIMER)),
113 stateCaptor.capture());
115 State value = stateCaptor.getValue();
116 assertTrue(value instanceof DateTimeType);
118 ZonedDateTime zdt = ((DateTimeType) value).getZonedDateTime();
119 assertEquals(1, zdt.getDayOfMonth());
120 assertEquals(2017, zdt.getYear());
121 assertEquals(Month.MAY, zdt.getMonth());
122 assertEquals(19, zdt.getHour());
123 assertEquals(0, zdt.getMinute());
124 assertEquals(0, zdt.getSecond());
128 public void shouldUpdateErrorChannelsIfErrorStatusReturned() throws InterruptedException {
129 ArgumentCaptor<State> errorCodeCaptor = ArgumentCaptor.forClass(State.class);
130 ArgumentCaptor<State> errorMessageCaptor = ArgumentCaptor.forClass(State.class);
131 ArgumentCaptor<State> errorDateCaptor = ArgumentCaptor.forClass(State.class);
134 MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
135 ErrorEntry error = new ErrorEntry();
136 error.setDate("01.05.2017");
137 error.setTime("19:00:00");
138 error.setUnix("1493665200");
139 error.setErrorCode(Integer.valueOf(22));
140 error.setErrorMessage("Dummy Message");
141 mowerInfo.getStatus().setStatus(MowerStatus.ERROR_STATUS);
142 mowerInfo.setError(error);
143 ErrorList errorList = new ErrorList();
144 errorList.setSuccessful(true);
147 when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
148 when(robonectClientMock.errorList()).thenReturn(errorList);
149 when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
151 subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
152 RefreshType.REFRESH);
155 verify(callbackMock, times(1)).stateUpdated(
156 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_CODE)),
157 errorCodeCaptor.capture());
158 verify(callbackMock, times(1)).stateUpdated(
159 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_MESSAGE)),
160 errorMessageCaptor.capture());
161 verify(callbackMock, times(1)).stateUpdated(
162 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_DATE)),
163 errorDateCaptor.capture());
165 State errorDate = errorDateCaptor.getValue();
166 assertTrue(errorDate instanceof DateTimeType);
168 ZonedDateTime zdt = ((DateTimeType) errorDate).getZonedDateTime();
169 assertEquals(1, zdt.getDayOfMonth());
170 assertEquals(2017, zdt.getYear());
171 assertEquals(Month.MAY, zdt.getMonth());
172 assertEquals(19, zdt.getHour());
173 assertEquals(0, zdt.getMinute());
174 assertEquals(0, zdt.getSecond());
176 State errorMessage = errorMessageCaptor.getValue();
177 assertTrue(errorMessage instanceof StringType);
178 StringType msgStringType = (StringType) errorMessage;
179 assertEquals("Dummy Message", msgStringType.toFullString());
181 State errorCode = errorCodeCaptor.getValue();
182 assertTrue(errorCode instanceof DecimalType);
183 DecimalType codeDecimaltype = (DecimalType) errorCode;
184 assertEquals(22, codeDecimaltype.intValue());
188 public void shouldResetErrorStateIfNoErrorInStatusUpdate() throws InterruptedException {
189 ArgumentCaptor<State> errorCodeCaptor = ArgumentCaptor.forClass(State.class);
190 ArgumentCaptor<State> errorMessageCaptor = ArgumentCaptor.forClass(State.class);
191 ArgumentCaptor<State> errorDateCaptor = ArgumentCaptor.forClass(State.class);
194 MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
195 mowerInfo.getStatus().setStatus(MowerStatus.MOWING);
196 mowerInfo.setError(null);
199 when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
200 when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
202 subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
203 RefreshType.REFRESH);
206 verify(callbackMock, times(1)).stateUpdated(
207 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_CODE)),
208 errorCodeCaptor.capture());
209 verify(callbackMock, times(1)).stateUpdated(
210 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_MESSAGE)),
211 errorMessageCaptor.capture());
212 verify(callbackMock, times(1)).stateUpdated(
213 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_DATE)),
214 errorDateCaptor.capture());
216 assertEquals(errorCodeCaptor.getValue(), UnDefType.UNDEF);
217 assertEquals(errorMessageCaptor.getValue(), UnDefType.UNDEF);
218 assertEquals(errorDateCaptor.getValue(), UnDefType.UNDEF);
222 public void shouldUpdateNumericStateOnMowerStatusRefresh() throws InterruptedException {
223 ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
226 MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
227 mowerInfo.getStatus().setStatus(MowerStatus.MOWING);
230 when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
231 when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
233 subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
234 RefreshType.REFRESH);
237 verify(callbackMock, times(1)).stateUpdated(
238 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS)),
239 stateCaptor.capture());
241 State value = stateCaptor.getValue();
242 assertTrue(value instanceof DecimalType);
243 DecimalType status = (DecimalType) value;
245 assertEquals(MowerStatus.MOWING.getStatusCode(), status.intValue());
249 public void shouldUpdateAllChannels() {
250 ArgumentCaptor<State> stateCaptorName = ArgumentCaptor.forClass(State.class);
251 ArgumentCaptor<State> stateCaptorBattery = ArgumentCaptor.forClass(State.class);
252 ArgumentCaptor<State> stateCaptorStatus = ArgumentCaptor.forClass(State.class);
253 ArgumentCaptor<State> stateCaptorDuration = ArgumentCaptor.forClass(State.class);
254 ArgumentCaptor<State> stateCaptorHours = ArgumentCaptor.forClass(State.class);
255 ArgumentCaptor<State> stateCaptorMode = ArgumentCaptor.forClass(State.class);
256 ArgumentCaptor<State> stateCaptorStarted = ArgumentCaptor.forClass(State.class);
257 ArgumentCaptor<State> stateCaptorWlan = ArgumentCaptor.forClass(State.class);
260 MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
261 ErrorList errorList = new ErrorList();
262 errorList.setSuccessful(true);
265 when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
266 when(robonectClientMock.errorList()).thenReturn(errorList);
267 when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
269 subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
270 RefreshType.REFRESH);
273 verify(callbackMock, times(1)).stateUpdated(
274 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_MOWER_NAME)),
275 stateCaptorName.capture());
276 verify(callbackMock, times(1)).stateUpdated(
277 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_BATTERY)),
278 stateCaptorBattery.capture());
279 verify(callbackMock, times(1)).stateUpdated(
280 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS)),
281 stateCaptorStatus.capture());
282 verify(callbackMock, times(1)).stateUpdated(
283 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_DURATION)),
284 stateCaptorDuration.capture());
285 verify(callbackMock, times(1)).stateUpdated(
286 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_HOURS)),
287 stateCaptorHours.capture());
288 verify(callbackMock, times(1)).stateUpdated(
289 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_MODE)),
290 stateCaptorMode.capture());
291 verify(callbackMock, times(1)).stateUpdated(
292 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_MOWER_START)),
293 stateCaptorStarted.capture());
294 verify(callbackMock, times(1)).stateUpdated(
295 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_WLAN_SIGNAL)),
296 stateCaptorWlan.capture());
298 assertEquals("Mowy", stateCaptorName.getValue().toFullString());
299 assertEquals(99, ((DecimalType) stateCaptorBattery.getValue()).intValue());
300 assertEquals(4, ((DecimalType) stateCaptorStatus.getValue()).intValue());
301 assertEquals(55, ((QuantityType<?>) stateCaptorDuration.getValue()).intValue());
302 assertEquals(22, ((QuantityType<?>) stateCaptorHours.getValue()).intValue());
303 assertEquals(MowerMode.AUTO.name(), stateCaptorMode.getValue().toFullString());
304 assertEquals(OnOffType.ON, stateCaptorStarted.getValue());
305 assertEquals(-88, ((DecimalType) stateCaptorWlan.getValue()).intValue());
308 private MowerInfo createSuccessfulMowerInfoResponse() {
309 MowerInfo mowerInfo = new MowerInfo();
310 Timer timer = new Timer();
311 timer.setStatus(Timer.TimerMode.ACTIVE);
312 NextTimer nextTimer = new NextTimer();
313 nextTimer.setDate("01.05.2017");
314 nextTimer.setTime("19:00:00");
315 nextTimer.setUnix("1493665200");
316 timer.setNext(nextTimer);
317 mowerInfo.setTimer(timer);
318 Status status = new Status();
319 status.setBattery(99);
320 status.setDuration(55);
322 status.setMode(MowerMode.AUTO);
323 status.setStatus(MowerStatus.CHARGING);
324 mowerInfo.setStatus(status);
325 mowerInfo.setName("Mowy");
326 Wlan wlan = new Wlan();
328 mowerInfo.setWlan(wlan);
329 mowerInfo.setSuccessful(true);
330 mowerInfo.getStatus().setStopped(false);