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