]> git.basschouten.com Git - openhab-addons.git/blob
14eb6c0aaa595c977e372df25224ac9ef31631dc
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.hdpowerview;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.openhab.binding.hdpowerview.internal.api.ActuatorClass.*;
17 import static org.openhab.binding.hdpowerview.internal.api.CoordinateSystem.*;
18
19 import java.io.BufferedReader;
20 import java.io.FileReader;
21 import java.io.IOException;
22 import java.util.List;
23 import java.util.regex.Pattern;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.eclipse.jetty.client.HttpClient;
28 import org.junit.jupiter.api.Test;
29 import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
30 import org.openhab.binding.hdpowerview.internal.HubMaintenanceException;
31 import org.openhab.binding.hdpowerview.internal.HubProcessingException;
32 import org.openhab.binding.hdpowerview.internal.api.CoordinateSystem;
33 import org.openhab.binding.hdpowerview.internal.api.ShadePosition;
34 import org.openhab.binding.hdpowerview.internal.api.responses.Scenes;
35 import org.openhab.binding.hdpowerview.internal.api.responses.Scenes.Scene;
36 import org.openhab.binding.hdpowerview.internal.api.responses.Shade;
37 import org.openhab.binding.hdpowerview.internal.api.responses.Shades;
38 import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData;
39 import org.openhab.core.library.types.PercentType;
40 import org.openhab.core.types.State;
41 import org.openhab.core.types.UnDefType;
42
43 import com.google.gson.Gson;
44 import com.google.gson.JsonParseException;
45
46 /**
47  * Unit tests for HD PowerView binding
48  *
49  * @author Andrew Fiddian-Green - Initial contribution
50  */
51 @NonNullByDefault
52 public class HDPowerViewJUnitTests {
53
54     private static final Pattern VALID_IP_V4_ADDRESS = Pattern
55             .compile("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");
56
57     /*
58      * load a test JSON string from a file
59      */
60     private String loadJson(String fileName) {
61         try (FileReader file = new FileReader(String.format("src/test/resources/%s.json", fileName));
62                 BufferedReader reader = new BufferedReader(file)) {
63             StringBuilder builder = new StringBuilder();
64             String line;
65             while ((line = reader.readLine()) != null) {
66                 builder.append(line).append("\n");
67             }
68             return builder.toString();
69         } catch (IOException e) {
70             fail(e.getMessage());
71         }
72         return "";
73     }
74
75     /**
76      * Run a series of ONLINE tests on the communication with a hub
77      *
78      * @param hubIPAddress must be a valid hub IP address to run the
79      *            tests on; or an INVALID IP address to
80      *            suppress the tests
81      * @param allowShadeMovementCommands set to true if you accept that the tests
82      *            shall physically move the shades
83      */
84     @Test
85     public void testOnlineCommunication() {
86         /*
87          * NOTE: in order to actually run these tests you must have a hub physically
88          * available, and its IP address must be correctly configured in the
89          * "hubIPAddress" string constant e.g. "192.168.1.123"
90          */
91         String hubIPAddress = "192.168.1.xxx";
92
93         /*
94          * NOTE: set allowShadeMovementCommands = true if you accept physically moving
95          * the shades during these tests
96          */
97         boolean allowShadeMovementCommands = false;
98
99         if (VALID_IP_V4_ADDRESS.matcher(hubIPAddress).matches()) {
100             // ==== initialize stuff ====
101             HttpClient client = new HttpClient();
102             assertNotNull(client);
103
104             // ==== start the client ====
105             try {
106                 client.start();
107                 assertTrue(client.isStarted());
108             } catch (Exception e) {
109                 fail(e.getMessage());
110             }
111
112             HDPowerViewWebTargets webTargets = new HDPowerViewWebTargets(client, hubIPAddress);
113             assertNotNull(webTargets);
114
115             // ==== exercise some code ====
116             ShadePosition test;
117             State pos;
118
119             // shade fully up
120             test = ShadePosition.create(ZERO_IS_CLOSED, 0);
121             assertNotNull(test);
122             pos = test.getState(PRIMARY_ACTUATOR, ZERO_IS_CLOSED);
123             assertEquals(PercentType.class, pos.getClass());
124             assertEquals(0, ((PercentType) pos).intValue());
125             pos = test.getState(PRIMARY_ACTUATOR, VANE_COORDS);
126             assertTrue(UnDefType.UNDEF.equals(pos));
127
128             // shade fully down (method 1)
129             test = ShadePosition.create(ZERO_IS_CLOSED, 100);
130             assertNotNull(test);
131             pos = test.getState(PRIMARY_ACTUATOR, ZERO_IS_CLOSED);
132             assertEquals(PercentType.class, pos.getClass());
133             assertEquals(100, ((PercentType) pos).intValue());
134             pos = test.getState(PRIMARY_ACTUATOR, VANE_COORDS);
135             assertEquals(PercentType.class, pos.getClass());
136             assertEquals(0, ((PercentType) pos).intValue());
137
138             // shade fully down (method 2)
139             test = ShadePosition.create(VANE_COORDS, 0);
140             assertNotNull(test);
141             pos = test.getState(PRIMARY_ACTUATOR, ZERO_IS_CLOSED);
142             assertEquals(PercentType.class, pos.getClass());
143             assertEquals(100, ((PercentType) pos).intValue());
144             pos = test.getState(PRIMARY_ACTUATOR, VANE_COORDS);
145             assertEquals(PercentType.class, pos.getClass());
146             assertEquals(0, ((PercentType) pos).intValue());
147
148             // shade fully down (method 2) and vane fully open
149             test = ShadePosition.create(VANE_COORDS, 100);
150             assertNotNull(test);
151             pos = test.getState(PRIMARY_ACTUATOR, ZERO_IS_CLOSED);
152             assertEquals(PercentType.class, pos.getClass());
153             assertEquals(100, ((PercentType) pos).intValue());
154             pos = test.getState(PRIMARY_ACTUATOR, VANE_COORDS);
155             assertEquals(PercentType.class, pos.getClass());
156             assertEquals(100, ((PercentType) pos).intValue());
157
158             int shadeId = 0;
159             @Nullable
160             ShadePosition shadePos = null;
161             @Nullable
162             Shades shadesX = null;
163
164             // ==== get all shades ====
165             try {
166                 shadesX = webTargets.getShades();
167                 assertNotNull(shadesX);
168                 @Nullable
169                 List<ShadeData> shadesData = shadesX.shadeData;
170                 assertNotNull(shadesData);
171                 assertTrue(!shadesData.isEmpty());
172                 @Nullable
173                 ShadeData shadeData;
174                 shadeData = shadesData.get(0);
175                 assertNotNull(shadeData);
176                 assertTrue(shadeData.getName().length() > 0);
177                 shadePos = shadeData.positions;
178                 assertNotNull(shadePos);
179                 @Nullable
180                 ShadeData shadeZero = shadesData.get(0);
181                 assertNotNull(shadeZero);
182                 shadeId = shadeZero.id;
183                 assertNotEquals(0, shadeId);
184
185                 for (ShadeData shadexData : shadesData) {
186                     String shadeName = shadexData.getName();
187                     assertNotNull(shadeName);
188                 }
189             } catch (JsonParseException | HubProcessingException | HubMaintenanceException e) {
190                 fail(e.getMessage());
191             }
192
193             // ==== get all scenes ====
194             int sceneId = 0;
195             try {
196                 Scenes scenes = webTargets.getScenes();
197                 assertNotNull(scenes);
198                 @Nullable
199                 List<Scene> scenesData = scenes.sceneData;
200                 assertNotNull(scenesData);
201                 assertTrue(!scenesData.isEmpty());
202                 @Nullable
203                 Scene sceneZero = scenesData.get(0);
204                 assertNotNull(sceneZero);
205                 sceneId = sceneZero.id;
206                 assertTrue(sceneId > 0);
207
208                 for (Scene scene : scenesData) {
209                     String sceneName = scene.getName();
210                     assertNotNull(sceneName);
211                 }
212             } catch (JsonParseException | HubProcessingException | HubMaintenanceException e) {
213                 fail(e.getMessage());
214             }
215
216             // ==== refresh a specific shade ====
217             @Nullable
218             Shade shade = null;
219             try {
220                 assertNotEquals(0, shadeId);
221                 shade = webTargets.refreshShadePosition(shadeId);
222                 assertNotNull(shade);
223             } catch (HubProcessingException | HubMaintenanceException e) {
224                 fail(e.getMessage());
225             }
226
227             // ==== move a specific shade ====
228             try {
229                 assertNotEquals(0, shadeId);
230                 assertNotNull(shade);
231                 @Nullable
232                 ShadeData shadeData = shade.shade;
233                 assertNotNull(shadeData);
234                 ShadePosition positions = shadeData.positions;
235                 assertNotNull(positions);
236                 CoordinateSystem coordSys = positions.getCoordinateSystem(PRIMARY_ACTUATOR);
237                 assertNotNull(coordSys);
238
239                 pos = positions.getState(PRIMARY_ACTUATOR, coordSys);
240                 assertEquals(PercentType.class, pos.getClass());
241
242                 pos = positions.getState(PRIMARY_ACTUATOR, ZERO_IS_CLOSED);
243                 assertEquals(PercentType.class, pos.getClass());
244
245                 int position = ((PercentType) pos).intValue();
246                 position = position + ((position <= 10) ? 5 : -5);
247
248                 ShadePosition newPos = ShadePosition.create(ZERO_IS_CLOSED, position);
249                 assertNotNull(newPos);
250
251                 if (allowShadeMovementCommands) {
252                     webTargets.moveShade(shadeId, newPos);
253                 }
254             } catch (HubProcessingException | HubMaintenanceException e) {
255                 fail(e.getMessage());
256             }
257
258             // ==== activate a specific scene ====
259             if (allowShadeMovementCommands) {
260                 try {
261                     assertNotNull(sceneId);
262                     webTargets.activateScene(sceneId);
263                 } catch (HubProcessingException | HubMaintenanceException e) {
264                     fail(e.getMessage());
265                 }
266             }
267
268             // ==== test stop command ====
269             if (allowShadeMovementCommands) {
270                 try {
271                     assertNotNull(sceneId);
272                     webTargets.stopShade(shadeId);
273                 } catch (HubProcessingException | HubMaintenanceException e) {
274                     fail(e.getMessage());
275                 }
276             }
277
278             // ==== stop the client ====
279             if (client.isRunning()) {
280                 try {
281                     client.stop();
282                 } catch (Exception e) {
283                     fail(e.getMessage());
284                 }
285             }
286         }
287     }
288
289     /**
290      * Run a series of OFFLINE tests on the JSON parsing machinery
291      */
292     @Test
293     public void testOfflineJsonParsing() {
294         final Gson gson = new Gson();
295
296         @Nullable
297         Shades shades;
298         // test generic JSON shades response
299         try {
300             @Nullable
301             String json = loadJson("shades");
302             assertNotNull(json);
303             assertNotEquals("", json);
304             shades = gson.fromJson(json, Shades.class);
305             assertNotNull(shades);
306         } catch (JsonParseException e) {
307             fail(e.getMessage());
308         }
309
310         // test generic JSON scenes response
311         try {
312             @Nullable
313             String json = loadJson("scenes");
314             assertNotNull(json);
315             assertNotEquals("", json);
316             @Nullable
317             Scenes scenes = gson.fromJson(json, Scenes.class);
318             assertNotNull(scenes);
319         } catch (JsonParseException e) {
320             fail(e.getMessage());
321         }
322
323         // test the JSON parsing for a duette top down bottom up shade
324         try {
325             @Nullable
326             ShadeData shadeData = null;
327             String json = loadJson("duette");
328             assertNotNull(json);
329             assertNotEquals("", json);
330
331             shades = gson.fromJson(json, Shades.class);
332             assertNotNull(shades);
333             @Nullable
334             List<ShadeData> shadesData = shades.shadeData;
335             assertNotNull(shadesData);
336
337             assertEquals(1, shadesData.size());
338             shadeData = shadesData.get(0);
339             assertNotNull(shadeData);
340
341             assertEquals("Gardin 1", shadeData.getName());
342             assertEquals(63778, shadeData.id);
343
344             ShadePosition shadePos = shadeData.positions;
345             assertNotNull(shadePos);
346             assertEquals(ZERO_IS_CLOSED, shadePos.getCoordinateSystem(PRIMARY_ACTUATOR));
347
348             State pos = shadePos.getState(PRIMARY_ACTUATOR, ZERO_IS_CLOSED);
349             assertEquals(PercentType.class, pos.getClass());
350             assertEquals(59, ((PercentType) pos).intValue());
351
352             pos = shadePos.getState(SECONDARY_ACTUATOR, ZERO_IS_OPEN);
353             assertEquals(PercentType.class, pos.getClass());
354             assertEquals(35, ((PercentType) pos).intValue());
355
356             pos = shadePos.getState(PRIMARY_ACTUATOR, VANE_COORDS);
357             assertEquals(UnDefType.class, pos.getClass());
358
359             assertEquals(3, shadeData.batteryStatus);
360
361             assertEquals(4, shadeData.signalStrength);
362         } catch (JsonParseException e) {
363             fail(e.getMessage());
364         }
365     }
366 }