]> git.basschouten.com Git - openhab-addons.git/blob
8f29c4f6cf4f4addce0a05c9c36cd2e236a7387d
[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.junit.jupiter.api.BeforeEach;
24 import org.junit.jupiter.api.Test;
25 import org.junit.jupiter.api.extension.ExtendWith;
26 import org.mockito.ArgumentCaptor;
27 import org.mockito.Mock;
28 import org.mockito.Mockito;
29 import org.mockito.junit.jupiter.MockitoExtension;
30 import org.mockito.junit.jupiter.MockitoSettings;
31 import org.mockito.quality.Strictness;
32 import org.openhab.binding.robonect.internal.RobonectBindingConstants;
33 import org.openhab.binding.robonect.internal.RobonectClient;
34 import org.openhab.binding.robonect.internal.model.ErrorEntry;
35 import org.openhab.binding.robonect.internal.model.ErrorList;
36 import org.openhab.binding.robonect.internal.model.MowerInfo;
37 import org.openhab.binding.robonect.internal.model.MowerMode;
38 import org.openhab.binding.robonect.internal.model.MowerStatus;
39 import org.openhab.binding.robonect.internal.model.NextTimer;
40 import org.openhab.binding.robonect.internal.model.Status;
41 import org.openhab.binding.robonect.internal.model.Timer;
42 import org.openhab.binding.robonect.internal.model.Wlan;
43 import org.openhab.core.i18n.TimeZoneProvider;
44 import org.openhab.core.io.net.http.HttpClientFactory;
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 HttpClientFactory httpClientFactoryMock;
73     private @Mock TimeZoneProvider timezoneProvider;
74
75     @BeforeEach
76     public void setUp() {
77         Mockito.when(robonectThingMock.getUID()).thenReturn(new ThingUID("1:2:3"));
78         Mockito.when(timezoneProvider.getTimeZone()).thenReturn(ZoneId.of("Europe/Berlin"));
79
80         subject = new RobonectHandler(robonectThingMock, httpClientFactoryMock, timezoneProvider);
81         subject.setCallback(callbackMock);
82         subject.setRobonectClient(robonectClientMock);
83     }
84
85     @Test
86     public void shouldUpdateNextTimerChannelWithDateTimeState() throws InterruptedException {
87         ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
88
89         // given
90         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
91         Timer timer = new Timer();
92         timer.setStatus(Timer.TimerMode.ACTIVE);
93         NextTimer nextTimer = new NextTimer();
94         nextTimer.setDate("01.05.2017");
95         nextTimer.setTime("19:00:00");
96         nextTimer.setUnix("1493665200");
97         timer.setNext(nextTimer);
98
99         // when
100         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
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
145         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
146                 RefreshType.REFRESH);
147
148         // then
149         verify(callbackMock, times(1)).stateUpdated(
150                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_CODE)),
151                 errorCodeCaptor.capture());
152         verify(callbackMock, times(1)).stateUpdated(
153                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_MESSAGE)),
154                 errorMessageCaptor.capture());
155         verify(callbackMock, times(1)).stateUpdated(
156                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_DATE)),
157                 errorDateCaptor.capture());
158
159         State errorDate = errorDateCaptor.getValue();
160         assertTrue(errorDate instanceof DateTimeType);
161
162         ZonedDateTime zdt = ((DateTimeType) errorDate).getZonedDateTime();
163         assertEquals(1, zdt.getDayOfMonth());
164         assertEquals(2017, zdt.getYear());
165         assertEquals(Month.MAY, zdt.getMonth());
166         assertEquals(19, zdt.getHour());
167         assertEquals(0, zdt.getMinute());
168         assertEquals(0, zdt.getSecond());
169
170         State errorMessage = errorMessageCaptor.getValue();
171         assertTrue(errorMessage instanceof StringType);
172         StringType msgStringType = (StringType) errorMessage;
173         assertEquals("Dummy Message", msgStringType.toFullString());
174
175         State errorCode = errorCodeCaptor.getValue();
176         assertTrue(errorCode instanceof DecimalType);
177         DecimalType codeDecimaltype = (DecimalType) errorCode;
178         assertEquals(22, codeDecimaltype.intValue());
179     }
180
181     @Test
182     public void shouldResetErrorStateIfNoErrorInStatusUpdate() throws InterruptedException {
183         ArgumentCaptor<State> errorCodeCaptor = ArgumentCaptor.forClass(State.class);
184         ArgumentCaptor<State> errorMessageCaptor = ArgumentCaptor.forClass(State.class);
185         ArgumentCaptor<State> errorDateCaptor = ArgumentCaptor.forClass(State.class);
186
187         // given
188         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
189         mowerInfo.getStatus().setStatus(MowerStatus.MOWING);
190         mowerInfo.setError(null);
191
192         // when
193         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
194
195         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
196                 RefreshType.REFRESH);
197
198         // then
199         verify(callbackMock, times(1)).stateUpdated(
200                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_CODE)),
201                 errorCodeCaptor.capture());
202         verify(callbackMock, times(1)).stateUpdated(
203                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_MESSAGE)),
204                 errorMessageCaptor.capture());
205         verify(callbackMock, times(1)).stateUpdated(
206                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_ERROR_DATE)),
207                 errorDateCaptor.capture());
208
209         assertEquals(errorCodeCaptor.getValue(), UnDefType.UNDEF);
210         assertEquals(errorMessageCaptor.getValue(), UnDefType.UNDEF);
211         assertEquals(errorDateCaptor.getValue(), UnDefType.UNDEF);
212     }
213
214     @Test
215     public void shouldUpdateNumericStateOnMowerStatusRefresh() throws InterruptedException {
216         ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
217
218         // given
219         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
220         mowerInfo.getStatus().setStatus(MowerStatus.MOWING);
221
222         // when
223         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
224
225         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
226                 RefreshType.REFRESH);
227
228         // then
229         verify(callbackMock, times(1)).stateUpdated(
230                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS)),
231                 stateCaptor.capture());
232
233         State value = stateCaptor.getValue();
234         assertTrue(value instanceof DecimalType);
235         DecimalType status = (DecimalType) value;
236
237         assertEquals(MowerStatus.MOWING.getStatusCode(), status.intValue());
238     }
239
240     @Test
241     public void shouldUpdateAllChannels() {
242         ArgumentCaptor<State> stateCaptorName = ArgumentCaptor.forClass(State.class);
243         ArgumentCaptor<State> stateCaptorBattery = ArgumentCaptor.forClass(State.class);
244         ArgumentCaptor<State> stateCaptorStatus = ArgumentCaptor.forClass(State.class);
245         ArgumentCaptor<State> stateCaptorDuration = ArgumentCaptor.forClass(State.class);
246         ArgumentCaptor<State> stateCaptorHours = ArgumentCaptor.forClass(State.class);
247         ArgumentCaptor<State> stateCaptorMode = ArgumentCaptor.forClass(State.class);
248         ArgumentCaptor<State> stateCaptorStarted = ArgumentCaptor.forClass(State.class);
249         ArgumentCaptor<State> stateCaptorWlan = ArgumentCaptor.forClass(State.class);
250
251         // given
252         MowerInfo mowerInfo = createSuccessfulMowerInfoResponse();
253         ErrorList errorList = new ErrorList();
254         errorList.setSuccessful(true);
255
256         // when
257         when(robonectClientMock.getMowerInfo()).thenReturn(mowerInfo);
258         when(robonectClientMock.errorList()).thenReturn(errorList);
259
260         subject.handleCommand(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS),
261                 RefreshType.REFRESH);
262
263         // then
264         verify(callbackMock, times(1)).stateUpdated(
265                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_MOWER_NAME)),
266                 stateCaptorName.capture());
267         verify(callbackMock, times(1)).stateUpdated(
268                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_BATTERY)),
269                 stateCaptorBattery.capture());
270         verify(callbackMock, times(1)).stateUpdated(
271                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS)),
272                 stateCaptorStatus.capture());
273         verify(callbackMock, times(1)).stateUpdated(
274                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_DURATION)),
275                 stateCaptorDuration.capture());
276         verify(callbackMock, times(1)).stateUpdated(
277                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_HOURS)),
278                 stateCaptorHours.capture());
279         verify(callbackMock, times(1)).stateUpdated(
280                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_STATUS_MODE)),
281                 stateCaptorMode.capture());
282         verify(callbackMock, times(1)).stateUpdated(
283                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_MOWER_START)),
284                 stateCaptorStarted.capture());
285         verify(callbackMock, times(1)).stateUpdated(
286                 eq(new ChannelUID(new ThingUID("1:2:3"), RobonectBindingConstants.CHANNEL_WLAN_SIGNAL)),
287                 stateCaptorWlan.capture());
288
289         assertEquals("Mowy", stateCaptorName.getValue().toFullString());
290         assertEquals(99, ((DecimalType) stateCaptorBattery.getValue()).intValue());
291         assertEquals(4, ((DecimalType) stateCaptorStatus.getValue()).intValue());
292         assertEquals(55, ((QuantityType<?>) stateCaptorDuration.getValue()).intValue());
293         assertEquals(22, ((QuantityType<?>) stateCaptorHours.getValue()).intValue());
294         assertEquals(MowerMode.AUTO.name(), stateCaptorMode.getValue().toFullString());
295         assertEquals(OnOffType.ON, stateCaptorStarted.getValue());
296         assertEquals(-88, ((DecimalType) stateCaptorWlan.getValue()).intValue());
297     }
298
299     private MowerInfo createSuccessfulMowerInfoResponse() {
300         MowerInfo mowerInfo = new MowerInfo();
301         Timer timer = new Timer();
302         timer.setStatus(Timer.TimerMode.ACTIVE);
303         NextTimer nextTimer = new NextTimer();
304         nextTimer.setDate("01.05.2017");
305         nextTimer.setTime("19:00:00");
306         nextTimer.setUnix("1493665200");
307         timer.setNext(nextTimer);
308         mowerInfo.setTimer(timer);
309         Status status = new Status();
310         status.setBattery(99);
311         status.setDuration(55);
312         status.setHours(22);
313         status.setMode(MowerMode.AUTO);
314         status.setStatus(MowerStatus.CHARGING);
315         mowerInfo.setStatus(status);
316         mowerInfo.setName("Mowy");
317         Wlan wlan = new Wlan();
318         wlan.setSignal(-88);
319         mowerInfo.setWlan(wlan);
320         mowerInfo.setSuccessful(true);
321         mowerInfo.getStatus().setStopped(false);
322         return mowerInfo;
323     }
324 }