2 * Copyright (c) 2010-2023 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;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.Mockito.*;
18 import java.nio.charset.StandardCharsets;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.TimeUnit;
21 import java.util.concurrent.TimeoutException;
23 import org.eclipse.jetty.client.HttpClient;
24 import org.eclipse.jetty.client.api.ContentResponse;
25 import org.eclipse.jetty.client.api.Request;
26 import org.eclipse.jetty.http.HttpMethod;
27 import org.junit.jupiter.api.BeforeEach;
28 import org.junit.jupiter.api.Test;
29 import org.junit.jupiter.api.extension.ExtendWith;
30 import org.mockito.Mock;
31 import org.mockito.junit.jupiter.MockitoExtension;
32 import org.openhab.binding.robonect.internal.model.ErrorList;
33 import org.openhab.binding.robonect.internal.model.MowerInfo;
34 import org.openhab.binding.robonect.internal.model.Name;
35 import org.openhab.binding.robonect.internal.model.VersionInfo;
38 * The goal of this class is to test the functionality of the RobonectClient,
39 * by mocking the module responses.
41 * @author Marco Meyer - Initial contribution
43 @ExtendWith(MockitoExtension.class)
44 public class RobonectClientTest {
46 private RobonectClient subject;
48 private @Mock HttpClient httpClientMock;
49 private @Mock ContentResponse responseMock;
50 private @Mock Request requestMock;
54 RobonectEndpoint dummyEndPoint = new RobonectEndpoint("123.456.789.123", null, null);
55 subject = new RobonectClient(httpClientMock, dummyEndPoint);
59 public void shouldCallStatusCommand() throws InterruptedException, ExecutionException, TimeoutException {
60 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=status")).thenReturn(requestMock);
61 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
62 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
63 when(requestMock.send()).thenReturn(responseMock);
64 when(responseMock.getEncoding()).thenReturn("utf8");
65 when(responseMock.getContentAsString()).thenReturn(
66 "{\"successful\": true, \"name\": \"Mein Automower\", \"status\": {\"status\": 17, \"stopped\": false, \"duration\": 4359, \"mode\": 0, \"battery\": 100, \"hours\": 29}, \"timer\": {\"status\": 2, \"next\": {\"date\": \"01.05.2017\", \"time\": \"19:00:00\", \"unix\": 1493665200}}, \"wlan\": {\"signal\": -76}}");
67 subject.getMowerInfo();
68 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=status");
72 public void shouldCallStartCommand() throws InterruptedException, ExecutionException, TimeoutException {
73 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=start")).thenReturn(requestMock);
74 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
75 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
76 when(requestMock.send()).thenReturn(responseMock);
77 when(responseMock.getEncoding()).thenReturn("utf8");
78 when(responseMock.getContentAsString()).thenReturn("{\"successful\": true}");
80 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=start");
84 public void shouldCallStopCommand() throws InterruptedException, ExecutionException, TimeoutException {
85 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=stop")).thenReturn(requestMock);
86 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
87 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
88 when(requestMock.send()).thenReturn(responseMock);
89 when(responseMock.getEncoding()).thenReturn("utf8");
90 when(responseMock.getContentAsString()).thenReturn("{\"successful\": true}");
92 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=stop");
96 public void shouldResetErrors() throws InterruptedException, ExecutionException, TimeoutException {
97 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=error&reset")).thenReturn(requestMock);
98 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
99 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
100 when(requestMock.send()).thenReturn(responseMock);
101 when(responseMock.getEncoding()).thenReturn("utf8");
102 when(responseMock.getContentAsString()).thenReturn("{\"successful\": true}");
103 subject.resetErrors();
104 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=error&reset");
108 public void shouldRetrieveName() throws InterruptedException, ExecutionException, TimeoutException {
109 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=name")).thenReturn(requestMock);
110 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
111 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
112 when(requestMock.send()).thenReturn(responseMock);
113 when(responseMock.getEncoding()).thenReturn("utf8");
114 when(responseMock.getContentAsString()).thenReturn("{\"successful\": true, \"name\": \"hugo\"}");
115 Name name = subject.getName();
116 assertEquals("hugo", name.getName());
117 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=name");
121 public void shouldSetNewName() throws InterruptedException, ExecutionException, TimeoutException {
122 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=name&name=MyRobo")).thenReturn(requestMock);
123 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
124 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
125 when(requestMock.send()).thenReturn(responseMock);
126 when(responseMock.getEncoding()).thenReturn("utf8");
127 when(responseMock.getContentAsString()).thenReturn("{\"successful\": true, \"name\": \"MyRobo\"}");
128 Name name = subject.setName("MyRobo");
129 assertEquals("MyRobo", name.getName());
130 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=name&name=MyRobo");
134 public void shouldListErrors() throws InterruptedException, ExecutionException, TimeoutException {
135 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=error")).thenReturn(requestMock);
136 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
137 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
138 when(requestMock.send()).thenReturn(responseMock);
139 when(responseMock.getEncoding()).thenReturn("utf8");
140 when(responseMock.getContentAsString()).thenReturn(
141 "{\"errors\": [{\"error_code\": 33, \"error_message\": \"Grasi ist gekippt\", \"date\": \"04.05.2017\", \"time\": \"22:22:17\", \"unix\": 1493936537}, {\"error_code\": 15, \"error_message\": \"Grasi ist angehoben\", \"date\": \"02.05.2017\", \"time\": \"20:36:43\", \"unix\": 1493757403}, {\"error_code\": 33, \"error_message\": \"Grasi ist gekippt\", \"date\": \"26.04.2017\", \"time\": \"21:31:18\", \"unix\": 1493242278}, {\"error_code\": 13, \"error_message\": \"Kein Antrieb\", \"date\": \"21.04.2017\", \"time\": \"20:17:22\", \"unix\": 1492805842}, {\"error_code\": 10, \"error_message\": \"Grasi ist umgedreht\", \"date\": \"20.04.2017\", \"time\": \"20:14:37\", \"unix\": 1492719277}, {\"error_code\": 1, \"error_message\": \"Grasi hat Arbeitsbereich überschritten\", \"date\": \"12.04.2017\", \"time\": \"19:10:09\", \"unix\": 1492024209}, {\"error_code\": 33, \"error_message\": \"Grasi ist gekippt\", \"date\": \"10.04.2017\", \"time\": \"22:59:35\", \"unix\": 1491865175}, {\"error_code\": 1, \"error_message\": \"Grasi hat Arbeitsbereich überschritten\", \"date\": \"10.04.2017\", \"time\": \"21:21:55\", \"unix\": 1491859315}, {\"error_code\": 33, \"error_message\": \"Grasi ist gekippt\", \"date\": \"10.04.2017\", \"time\": \"20:26:13\", \"unix\": 1491855973}, {\"error_code\": 1, \"error_message\": \"Grasi hat Arbeitsbereich überschritten\", \"date\": \"09.04.2017\", \"time\": \"14:50:36\", \"unix\": 1491749436}, {\"error_code\": 33, \"error_message\": \"Grasi ist gekippt\", \"date\": \"09.04.2017\", \"time\": \"14:23:27\", \"unix\": 1491747807}], \"successful\": true}");
142 ErrorList list = subject.errorList();
143 assertEquals(11, list.getErrors().size());
144 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=error");
148 public void shouldRetrieveVersionInfo() throws InterruptedException, ExecutionException, TimeoutException {
149 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=version")).thenReturn(requestMock);
150 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
151 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
152 when(requestMock.send()).thenReturn(responseMock);
153 when(responseMock.getEncoding()).thenReturn("utf8");
154 when(responseMock.getContentAsString()).thenReturn(
155 "{\"robonect\": {\"serial\": \"05D92D32-38355048-43203030\", \"version\": \"V0.9\", \"compiled\": \"2017-03-25 20:10:00\", \"comment\": \"V0.9c\"}, \"successful\": true}");
156 VersionInfo info = subject.getVersionInfo();
157 assertEquals("05D92D32-38355048-43203030", info.getRobonect().getSerial());
158 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=version");
162 public void shouldHandleProperEncoding() throws InterruptedException, ExecutionException, TimeoutException {
163 byte[] responseBytesISO88591 = "{\"successful\": true, \"name\": \"Mein Automower\", \"status\": {\"status\": 7, \"stopped\": true, \"duration\": 192, \"mode\": 1, \"battery\": 95, \"hours\": 41}, \"timer\": {\"status\": 2}, \"error\" : {\"error_code\": 15, \"error_message\": \"Utanför arbetsområdet\", \"date\": \"02.05.2017\", \"time\": \"20:36:43\", \"unix\": 1493757403}, \"wlan\": {\"signal\": -75}}"
164 .getBytes(StandardCharsets.ISO_8859_1);
165 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=status")).thenReturn(requestMock);
166 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
167 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
168 when(requestMock.send()).thenReturn(responseMock);
169 when(responseMock.getEncoding()).thenReturn(null);
170 when(responseMock.getContent()).thenReturn(responseBytesISO88591);
171 MowerInfo info = subject.getMowerInfo();
172 assertEquals("Utanför arbetsområdet", info.getError().getErrorMessage());
173 verify(httpClientMock, times(1)).newRequest("http://123.456.789.123/json?cmd=status");
177 public void shouldReceiveErrorAnswerOnInterruptedException()
178 throws InterruptedException, ExecutionException, TimeoutException {
179 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=status")).thenReturn(requestMock);
180 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
181 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
182 when(requestMock.send()).thenThrow(new InterruptedException("Mock Interrupted Exception"));
183 assertThrows(RobonectCommunicationException.class, () -> subject.getMowerInfo());
187 public void shouldReceiveErrorAnswerOnExecutionException()
188 throws InterruptedException, ExecutionException, TimeoutException {
189 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=status")).thenReturn(requestMock);
190 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
191 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
192 when(requestMock.send()).thenThrow(new ExecutionException(new Exception("Mock Exception")));
193 assertThrows(RobonectCommunicationException.class, () -> subject.getMowerInfo());
197 public void shouldReceiveErrorAnswerOnTimeoutException()
198 throws InterruptedException, ExecutionException, TimeoutException {
199 when(httpClientMock.newRequest("http://123.456.789.123/json?cmd=status")).thenReturn(requestMock);
200 when(requestMock.method(HttpMethod.GET)).thenReturn(requestMock);
201 when(requestMock.timeout(30000L, TimeUnit.MILLISECONDS)).thenReturn(requestMock);
202 when(requestMock.send()).thenThrow(new TimeoutException("Mock Timeout Exception"));
203 assertThrows(RobonectCommunicationException.class, () -> subject.getMowerInfo());