]> git.basschouten.com Git - openhab-addons.git/blob
ce1e0186897866dc28fbf2873385c1443f870eeb
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.salus.internal.rest;
14
15 import static org.assertj.core.api.Assertions.*;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.ArgumentMatchers.anyString;
18 import static org.mockito.ArgumentMatchers.endsWith;
19 import static org.mockito.ArgumentMatchers.eq;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.when;
22
23 import java.time.Clock;
24 import java.util.ArrayList;
25 import java.util.Optional;
26
27 import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.junit.jupiter.api.DisplayName;
30 import org.junit.jupiter.api.Test;
31
32 /**
33  * @author Martin GrzeĊ›lowski - Initial contribution
34  */
35 @SuppressWarnings("DataFlowIssue")
36 @NonNullByDefault
37 public class SalusApiTest {
38
39     // Find devices returns sorted set of devices
40     @Test
41     @DisplayName("Find devices returns sorted set of devices")
42     public void testFindDevicesReturnsSortedSetOfDevices() throws Exception {
43         // Given
44         var username = "correct_username";
45         var password = "correct_password".toCharArray();
46         var baseUrl = "https://example.com";
47         var restClient = mock(RestClient.class);
48         var mapper = mock(GsonMapper.class);
49         var clock = Clock.systemDefaultZone();
50
51         var authToken = new AuthToken("access_token", "refresh_token", 3600L, "role");
52         var response = "devices_json";
53         when(restClient.get(anyString(), any())).thenReturn(response);
54
55         var devices = new ArrayList<Device>();
56         when(mapper.parseDevices(anyString())).thenReturn(devices);
57
58         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
59         setAuthToken(salusApi, restClient, mapper, authToken);
60
61         // When
62         var result = salusApi.findDevices();
63
64         // Then
65         assertThat(result).containsExactlyInAnyOrderElementsOf(devices);
66     }
67
68     // Find device properties returns sorted set of device properties
69     @Test
70     @DisplayName("Find device properties returns sorted set of device properties")
71     public void testFindDevicePropertiesReturnsSortedSetOfDeviceProperties() throws Exception {
72         // Given
73         var username = "correct_username";
74         var password = "correct_password".toCharArray();
75         var baseUrl = "https://example.com";
76         var restClient = mock(RestClient.class);
77         var mapper = mock(GsonMapper.class);
78         var clock = Clock.systemDefaultZone();
79
80         var authToken = new AuthToken("access_token", "refresh_token", 3600L, "role");
81         var response = "device_properties_json";
82         when(restClient.get(anyString(), any())).thenReturn(response);
83
84         var deviceProperties = new ArrayList<DeviceProperty<?>>();
85         when(mapper.parseDeviceProperties(anyString())).thenReturn(deviceProperties);
86
87         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
88         setAuthToken(salusApi, restClient, mapper, authToken);
89
90         // When
91         var result = salusApi.findDeviceProperties("dsn");
92
93         // Then
94         assertThat(result).containsExactlyInAnyOrderElementsOf(deviceProperties);
95     }
96
97     // Set value for property returns OK response with datapoint value
98     @Test
99     @DisplayName("Set value for property returns OK response with datapoint value")
100     public void testSetValueForPropertyReturnsOkResponseWithDatapointValue() throws Exception {
101         // Given
102         var username = "correct_username";
103         var password = "correct_password".toCharArray();
104         var baseUrl = "https://example.com";
105         var restClient = mock(RestClient.class);
106         var mapper = mock(GsonMapper.class);
107         var clock = Clock.systemDefaultZone();
108
109         var authToken = new AuthToken("access_token", "refresh_token", 3600L, "role");
110         var response = "datapoint_value_json";
111         when(restClient.post(anyString(), any(), any())).thenReturn(response);
112
113         var datapointValue = new Object();
114         when(mapper.datapointValue(anyString())).thenReturn(Optional.of(datapointValue));
115
116         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
117         setAuthToken(salusApi, restClient, mapper, authToken);
118
119         // When
120         var result = salusApi.setValueForProperty("dsn", "property_name", "value");
121
122         // Then
123         assertThat(result).isEqualTo(datapointValue);
124     }
125
126     // Login with incorrect credentials throws HttpUnauthorizedException
127     @Test
128     @DisplayName("Login with incorrect credentials throws HttpUnauthorizedException")
129     public void testLoginWithIncorrectCredentialsThrowsHttpUnauthorizedException() throws Exception {
130         // Given
131         var username = "incorrect_username";
132         var password = "incorrect_password".toCharArray();
133         var baseUrl = "https://example.com";
134         var restClient = mock(RestClient.class);
135         var mapper = mock(GsonMapper.class);
136         var clock = Clock.systemDefaultZone();
137
138         when(restClient.post(anyString(), any(), any()))
139                 .thenThrow(new HttpSalusApiException(401, "unauthorized_error_json"));
140
141         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
142
143         // When
144         ThrowingCallable findDevicesResponse = salusApi::findDevices;
145
146         // Then
147         assertThatThrownBy(findDevicesResponse).isInstanceOf(HttpSalusApiException.class)
148                 .hasMessage("HTTP Error 401: unauthorized_error_json");
149     }
150
151     // Find devices with invalid auth token throws HttpUnauthorizedException
152     @Test
153     @DisplayName("Find devices with invalid auth token throws HttpUnauthorizedException")
154     public void testFindDevicesWithInvalidAuthTokenThrowsHttpUnauthorizedException() throws Exception {
155         // Given
156         var username = "correct_username";
157         var password = "correct_password".toCharArray();
158         var baseUrl = "https://example.com";
159         var restClient = mock(RestClient.class);
160         var mapper = mock(GsonMapper.class);
161         var clock = Clock.systemDefaultZone();
162
163         var authToken = new AuthToken("access_token", "refresh_token", 3600L, "role");
164         when(restClient.get(anyString(), any())).thenThrow(new HttpSalusApiException(401, "unauthorized_error_json"));
165
166         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
167         setAuthToken(salusApi, restClient, mapper, authToken);
168
169         // When
170         ThrowingCallable objectApiResponse = salusApi::findDevices;
171
172         // Then
173         assertThatThrownBy(objectApiResponse).isInstanceOf(HttpSalusApiException.class)
174                 .hasMessage("HTTP Error 401: unauthorized_error_json");
175     }
176
177     // Find device properties with invalid auth token throws HttpUnauthorizedException
178     @Test
179     @DisplayName("Find device properties with invalid auth token throws HttpUnauthorizedException")
180     public void testFindDevicePropertiesWithInvalidAuthTokenThrowsHttpUnauthorizedException() throws Exception {
181         // Given
182         var username = "correct_username";
183         var password = "correct_password".toCharArray();
184         var baseUrl = "https://example.com";
185         var restClient = mock(RestClient.class);
186         var mapper = mock(GsonMapper.class);
187         var clock = Clock.systemDefaultZone();
188
189         var authToken = new AuthToken("access_token", "refresh_token", 3600L, "role");
190         when(restClient.get(anyString(), any())).thenThrow(new HttpSalusApiException(401, "unauthorized_error_json"));
191
192         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
193         setAuthToken(salusApi, restClient, mapper, authToken);
194
195         // When
196         ThrowingCallable objectApiResponse = () -> salusApi.findDeviceProperties("dsn");
197
198         // Given
199         assertThatThrownBy(objectApiResponse).isInstanceOf(HttpSalusApiException.class)
200                 .hasMessage("HTTP Error 401: unauthorized_error_json");
201     }
202
203     // Set value for property with invalid auth token throws HttpUnauthorizedException
204     @Test
205     @DisplayName("Set value for property with invalid auth token throws HttpUnauthorizedException")
206     public void testSetValueForPropertyWithInvalidAuthTokenThrowsHttpUnauthorizedException() throws Exception {
207         // Given
208         var username = "correct_username";
209         var password = "correct_password".toCharArray();
210         var baseUrl = "https://example.com";
211         var restClient = mock(RestClient.class);
212         var mapper = mock(GsonMapper.class);
213         var clock = Clock.systemDefaultZone();
214
215         var authToken = new AuthToken("access_token", "refresh_token", 3600L, "role");
216         when(restClient.post(anyString(), any(), any()))
217                 .thenThrow(new HttpSalusApiException(401, "unauthorized_error_json"));
218
219         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
220
221         // When
222         ThrowingCallable objectApiResponse = () -> salusApi.setValueForProperty("dsn", "property_name", "value");
223
224         // given
225
226         assertThatThrownBy(objectApiResponse).isInstanceOf(HttpSalusApiException.class)
227                 .hasMessage("HTTP Error 401: unauthorized_error_json");
228     }
229
230     // Find device properties with invalid DSN returns ApiResponse with error
231     @Test
232     @DisplayName("Find device properties with invalid DSN returns ApiResponse with error")
233     public void testFindDevicePropertiesWithInvalidDsnReturnsApiResponseWithError() throws Exception {
234         // Given
235         var username = "correct_username";
236         var password = "correct_password".toCharArray();
237         var baseUrl = "https://example.com";
238         var restClient = mock(RestClient.class);
239         var mapper = mock(GsonMapper.class);
240         var clock = Clock.systemDefaultZone();
241
242         var authToken = new AuthToken("access_token", "refresh_token", 3600L, "role");
243         when(restClient.get(anyString(), any())).thenThrow(new HttpSalusApiException(404, "not found"));
244
245         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
246         setAuthToken(salusApi, restClient, mapper, authToken);
247
248         // When
249         ThrowingCallable result = () -> salusApi.findDeviceProperties("invalid_dsn");
250
251         // Then
252         assertThatThrownBy(result).isInstanceOf(HttpSalusApiException.class).hasMessage("HTTP Error 404: not found");
253     }
254
255     // Login with incorrect credentials 3 times throws HttpForbiddenException
256     @Test
257     @DisplayName("Login with incorrect credentials 3 times throws HttpForbiddenException")
258     public void testLoginWithIncorrectCredentials3TimesThrowsHttpForbiddenException() throws Exception {
259         // Given
260         var username = "incorrect_username";
261         var password = "incorrect_password".toCharArray();
262         var baseUrl = "https://example.com";
263         var restClient = mock(RestClient.class);
264         var mapper = mock(GsonMapper.class);
265         var clock = Clock.systemDefaultZone();
266
267         when(restClient.post(anyString(), any(), any()))
268                 .thenThrow(new HttpSalusApiException(403, "forbidden_error_json"));
269
270         var salusApi = new SalusApi(username, password, baseUrl, restClient, mapper, clock);
271
272         // When
273         ThrowingCallable findDevicesResponse = salusApi::findDevices;
274
275         // Then
276         assertThatThrownBy(findDevicesResponse).isInstanceOf(HttpSalusApiException.class)
277                 .hasMessage("HTTP Error 403: forbidden_error_json");
278     }
279
280     private void setAuthToken(SalusApi salusApi, RestClient restClient, GsonMapper mapper, AuthToken authToken)
281             throws SalusApiException {
282         var username = "correct_username";
283         var password = "correct_password".toCharArray();
284         var inputBody = "login_param_json";
285         when(mapper.loginParam(username, password)).thenReturn(inputBody);
286         var authTokenJson = "auth_token";
287         when(mapper.authToken(authTokenJson)).thenReturn(authToken);
288
289         when(restClient.post(endsWith("/users/sign_in.json"), eq(new RestClient.Content(inputBody, "application/json")),
290                 any())).thenReturn(authTokenJson);
291     }
292 }