]> git.basschouten.com Git - openhab-addons.git/blob
58c6e9c34d9897aa1a0efd1be2c4e289ba222440
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.robonect.internal.handler;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.ArgumentMatchers.eq;
17 import static org.mockito.Mockito.*;
18
19 import java.time.Month;
20 import java.time.ZoneId;
21 import java.time.ZonedDateTime;
22
23 import org.eclipse.jetty.client.HttpClient;
24 import org.junit.jupiter.api.BeforeEach;
25 import org.junit.jupiter.api.Test;
26 import org.junit.jupiter.api.extension.ExtendWith;
27 import org.mockito.ArgumentCaptor;
28 import org.mockito.Mock;
29 import org.mockito.Mockito;
30 import org.mockito.junit.jupiter.MockitoExtension;
31 import org.mockito.junit.jupiter.MockitoSettings;
32 import org.mockito.quality.Strictness;
33 import org.openhab.binding.robonect.internal.RobonectBindingConstants;
34 import org.openhab.binding.robonect.internal.RobonectClient;
35 import org.openhab.binding.robonect.internal.model.ErrorEntry;
36 import org.openhab.binding.robonect.internal.model.ErrorList;
37 import org.openhab.binding.robonect.internal.model.MowerInfo;
38 import org.openhab.binding.robonect.internal.model.MowerMode;
39 import org.openhab.binding.robonect.internal.model.MowerStatus;
40 import org.openhab.binding.robonect.internal.model.NextTimer;
41 import org.openhab.binding.robonect.internal.model.Status;
42 import org.openhab.binding.robonect.internal.model.Timer;
43 import org.openhab.binding.robonect.internal.model.Wlan;
44 import org.openhab.core.i18n.TimeZoneProvider;
45 import org.openhab.core.library.types.DateTimeType;
46 import org.openhab.core.library.types.DecimalType;
47 import org.openhab.core.library.types.OnOffType;
48 import org.openhab.core.library.types.QuantityType;
49 import org.openhab.core.library.types.StringType;
50 import org.openhab.core.thing.ChannelUID;
51 import org.openhab.core.thing.Thing;
52 import org.openhab.core.thing.ThingUID;
53 import org.openhab.core.thing.binding.ThingHandlerCallback;
54 import org.openhab.core.types.RefreshType;
55 import org.openhab.core.types.State;
56 import org.openhab.core.types.UnDefType;
57
58 /**
59  * The goal of this class is to test RobonectHandler in isolation.
60  *
61  * @author Marco Meyer - Initial contribution
62  */
63 @ExtendWith(MockitoExtension.class)
64 @MockitoSettings(strictness = Strictness.LENIENT)
65 public class RobonectHandlerTest {
66
67     private RobonectHandler subject;
68
69     private @Mock Thing robonectThingMock;
70     private @Mock RobonectClient robonectClientMock;
71     private @Mock ThingHandlerCallback callbackMock;
72     private @Mock HttpClient httpClientMock;
73     private @Mock TimeZoneProvider timezoneProvider;
74
75     @BeforeEach
76     public void setUp() {
77         subject = new RobonectHandler(robonectThingMock, httpClientMock, timezoneProvider);
78         subject.setCallback(callbackMock);
79         subject.setRobonectClient(robonectClientMock);
80
81         Mockito.when(timezoneProvider.getTimeZone()).thenReturn(ZoneId.of("Europe/Berlin"));
82     }
83
84     @Test
85     public void shouldUpdateNextTimerChannelWithDateTimeState() throws InterruptedException {
86         ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
87
88         // given
89         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
90         Timer timer = new Timer();
91         timer.setStatus(Timer.TimerMode.ACTIVE);
92         NextTimer nextTimer = new NextTimer();
93         nextTimer.setDate("01.05.2017");
94         nextTimer.setTime("19:00:00");
95         nextTimer.setUnix("1493665200");
96         timer.setNext(nextTimer);
97
98         // when
99         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
100         when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
101
102         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_TIMER_NEXT_TIMER),
103                 RefreshType.REFRESH);
104
105         // then
106         verify(callbackMock, times(1)).stateUpdated(
107                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_TIMER_NEXT_TIMER)),
108                 stateCaptor.capture());
109
110         State value = stateCaptor.getValue();
111         assertTrue(value instanceof DateTimeType);
112
113         ZonedDateTime zdt = ((DateTimeType) value).getZonedDateTime();
114         assertEquals(1, zdt.getDayOfMonth());
115         assertEquals(2017, zdt.getYear());
116         assertEquals(Month.MAY, zdt.getMonth());
117         assertEquals(19, zdt.getHour());
118         assertEquals(0, zdt.getMinute());
119         assertEquals(0, zdt.getSecond());
120     }
121
122     @Test
123     public void shouldUpdateErrorChannelsIfErrorStatusReturned() throws InterruptedException {
124         ArgumentCaptor<State> errorCodeCaptor = ArgumentCaptor.forClass(State.class);
125         ArgumentCaptor<State> errorMessageCaptor = ArgumentCaptor.forClass(State.class);
126         ArgumentCaptor<State> errorDateCaptor = ArgumentCaptor.forClass(State.class);
127
128         // given
129         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
130         ErrorEntry error = new ErrorEntry();
131         error.setDate("01.05.2017");
132         error.setTime("19:00:00");
133         error.setUnix("1493665200");
134         error.setErrorCode(Integer.valueOf(22));
135         error.setErrorMessage("Dummy Message");
136         mowerInfo.getStatus().setStatus(MowerStatus.ERROR_STATUS);
137         mowerInfo.setError(error);
138         ErrorList errorList = new ErrorList();
139         errorList.setSuccessful(true);
140
141         // when
142         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
143         when(robonectClientMock.errorList()).thenReturn(errorList);
144         when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
145
146         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
147                 RefreshType.REFRESH);
148
149         // then
150         verify(callbackMock, times(1)).stateUpdated(
151                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_CODE)),
152                 errorCodeCaptor.capture());
153         verify(callbackMock, times(1)).stateUpdated(
154                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_MESSAGE)),
155                 errorMessageCaptor.capture());
156         verify(callbackMock, times(1)).stateUpdated(
157                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_DATE)),
158                 errorDateCaptor.capture());
159
160         State errorDate = errorDateCaptor.getValue();
161         assertTrue(errorDate instanceof DateTimeType);
162
163         ZonedDateTime zdt = ((DateTimeType) errorDate).getZonedDateTime();
164         assertEquals(1, zdt.getDayOfMonth());
165         assertEquals(2017, zdt.getYear());
166         assertEquals(Month.MAY, zdt.getMonth());
167         assertEquals(19, zdt.getHour());
168         assertEquals(0, zdt.getMinute());
169         assertEquals(0, zdt.getSecond());
170
171         State errorMessage = errorMessageCaptor.getValue();
172         assertTrue(errorMessage instanceof StringType);
173         StringType msgStringType = (StringType) errorMessage;
174         assertEquals("Dummy Message", msgStringType.toFullString());
175
176         State errorCode = errorCodeCaptor.getValue();
177         assertTrue(errorCode instanceof DecimalType);
178         DecimalType codeDecimaltype = (DecimalType) errorCode;
179         assertEquals(22, codeDecimaltype.intValue());
180     }
181
182     @Test
183     public void shouldResetErrorStateIfNoErrorInStatusUpdate() throws InterruptedException {
184         ArgumentCaptor<State> errorCodeCaptor = ArgumentCaptor.forClass(State.class);
185         ArgumentCaptor<State> errorMessageCaptor = ArgumentCaptor.forClass(State.class);
186         ArgumentCaptor<State> errorDateCaptor = ArgumentCaptor.forClass(State.class);
187
188         // given
189         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
190         mowerInfo.getStatus().setStatus(MowerStatus.MOWING);
191         mowerInfo.setError(null);
192
193         // when
194         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
195         when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
196
197         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
198                 RefreshType.REFRESH);
199
200         // then
201         verify(callbackMock, times(1)).stateUpdated(
202                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_CODE)),
203                 errorCodeCaptor.capture());
204         verify(callbackMock, times(1)).stateUpdated(
205                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_MESSAGE)),
206                 errorMessageCaptor.capture());
207         verify(callbackMock, times(1)).stateUpdated(
208                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_DATE)),
209                 errorDateCaptor.capture());
210
211         assertEquals(errorCodeCaptor.getValue(), UnDefType.UNDEF);
212         assertEquals(errorMessageCaptor.getValue(), UnDefType.UNDEF);
213         assertEquals(errorDateCaptor.getValue(), UnDefType.UNDEF);
214     }
215
216     @Test
217     public void shouldUpdateNumericStateOnMowerStatusRefresh() throws InterruptedException {
218         ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
219
220         // given
221         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
222         mowerInfo.getStatus().setStatus(MowerStatus.MOWING);
223
224         // when
225         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
226         when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
227
228         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
229                 RefreshType.REFRESH);
230
231         // then
232         verify(callbackMock, times(1)).stateUpdated(
233                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS)),
234                 stateCaptor.capture());
235
236         State value = stateCaptor.getValue();
237         assertTrue(value instanceof DecimalType);
238         DecimalType status = (DecimalType) value;
239
240         assertEquals(MowerStatus.MOWING.getStatusCode(), status.intValue());
241     }
242
243     @Test
244     public void shouldUpdateAllChannels() {
245         ArgumentCaptor<State> stateCaptorName = ArgumentCaptor.forClass(State.class);
246         ArgumentCaptor<State> stateCaptorBattery = ArgumentCaptor.forClass(State.class);
247         ArgumentCaptor<State> stateCaptorStatus = ArgumentCaptor.forClass(State.class);
248         ArgumentCaptor<State> stateCaptorDuration = ArgumentCaptor.forClass(State.class);
249         ArgumentCaptor<State> stateCaptorHours = ArgumentCaptor.forClass(State.class);
250         ArgumentCaptor<State> stateCaptorMode = ArgumentCaptor.forClass(State.class);
251         ArgumentCaptor<State> stateCaptorStarted = ArgumentCaptor.forClass(State.class);
252         ArgumentCaptor<State> stateCaptorWlan = ArgumentCaptor.forClass(State.class);
253
254         // given
255         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
256         ErrorList errorList = new ErrorList();
257         errorList.setSuccessful(true);
258
259         // when
260         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
261         when(robonectClientMock.errorList()).thenReturn(errorList);
262         when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
263
264         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
265                 RefreshType.REFRESH);
266
267         // then
268         verify(callbackMock, times(1)).stateUpdated(
269                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_MOWER_NAME)),
270                 stateCaptorName.capture());
271         verify(callbackMock, times(1)).stateUpdated(
272                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_BATTERY)),
273                 stateCaptorBattery.capture());
274         verify(callbackMock, times(1)).stateUpdated(
275                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS)),
276                 stateCaptorStatus.capture());
277         verify(callbackMock, times(1)).stateUpdated(
278                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_DURATION)),
279                 stateCaptorDuration.capture());
280         verify(callbackMock, times(1)).stateUpdated(
281                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_HOURS)),
282                 stateCaptorHours.capture());
283         verify(callbackMock, times(1)).stateUpdated(
284                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_MODE)),
285                 stateCaptorMode.capture());
286         verify(callbackMock, times(1)).stateUpdated(
287                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_MOWER_START)),
288                 stateCaptorStarted.capture());
289         verify(callbackMock, times(1)).stateUpdated(
290                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_WLAN_SIGNAL)),
291                 stateCaptorWlan.capture());
292
293         assertEquals("Mowy", stateCaptorName.getValue().toFullString());
294         assertEquals(99, ((DecimalType) stateCaptorBattery.getValue()).intValue());
295         assertEquals(4, ((DecimalType) stateCaptorStatus.getValue()).intValue());
296         assertEquals(55, ((QuantityType<?>) stateCaptorDuration.getValue()).intValue());
297         assertEquals(22, ((QuantityType<?>) stateCaptorHours.getValue()).intValue());
298         assertEquals(MowerMode.AUTO.name(), stateCaptorMode.getValue().toFullString());
299         assertEquals(OnOffType.ON, stateCaptorStarted.getValue());
300         assertEquals(-88, ((DecimalType) stateCaptorWlan.getValue()).intValue());
301     }
302
303     private MowerInfo createSuccessfulMowerInfoResponse() {
304         MowerInfo mowerInfo = new MowerInfo();
305         Timer timer = new Timer();
306         timer.setStatus(Timer.TimerMode.ACTIVE);
307         NextTimer nextTimer = new NextTimer();
308         nextTimer.setDate("01.05.2017");
309         nextTimer.setTime("19:00:00");
310         nextTimer.setUnix("1493665200");
311         timer.setNext(nextTimer);
312         mowerInfo.setTimer(timer);
313         Status status = new Status();
314         status.setBattery(99);
315         status.setDuration(55);
316         status.setHours(22);
317         status.setMode(MowerMode.AUTO);
318         status.setStatus(MowerStatus.CHARGING);
319         mowerInfo.setStatus(status);
320         mowerInfo.setName("Mowy");
321         Wlan wlan = new Wlan();
322         wlan.setSignal(-88);
323         mowerInfo.setWlan(wlan);
324         mowerInfo.setSuccessful(true);
325         mowerInfo.getStatus().setStopped(false);
326         return mowerInfo;
327     }
328 }