]> git.basschouten.com Git - openhab-addons.git/blob
7a8aaad1d442035c4f1b6a6546f0a61aae28047a
[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.io.hueemulation.internal.rest;
14
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.junit.Assert.*;
17
18 import java.io.IOException;
19 import java.lang.reflect.Type;
20 import java.util.Map;
21 import java.util.Map.Entry;
22 import java.util.Random;
23
24 import javax.ws.rs.client.Entity;
25 import javax.ws.rs.core.Response;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.openhab.core.items.GenericItem;
29 import org.openhab.core.items.ItemRegistry;
30 import org.openhab.core.library.items.ColorItem;
31 import org.openhab.core.library.items.SwitchItem;
32 import org.openhab.core.library.types.HSBType;
33 import org.openhab.core.library.types.OnOffType;
34 import org.openhab.core.types.State;
35 import org.glassfish.jersey.server.ResourceConfig;
36 import org.junit.After;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.openhab.core.automation.Condition;
40 import org.openhab.core.automation.Rule;
41 import org.openhab.core.automation.RuleRegistry;
42 import org.openhab.core.automation.Trigger;
43 import org.openhab.core.automation.util.RuleBuilder;
44 import org.openhab.io.hueemulation.internal.ConfigStore;
45 import org.openhab.io.hueemulation.internal.RuleUtils;
46 import org.openhab.io.hueemulation.internal.dto.HueRuleEntry;
47 import org.openhab.io.hueemulation.internal.dto.HueRuleEntry.Operator;
48 import org.openhab.io.hueemulation.internal.dto.HueSceneEntry;
49 import org.openhab.io.hueemulation.internal.dto.changerequest.HueCommand;
50 import org.openhab.io.hueemulation.internal.rest.mocks.DummyItemRegistry;
51 import org.openhab.io.hueemulation.internal.rest.mocks.DummyRuleRegistry;
52
53 import com.google.gson.Gson;
54 import com.google.gson.reflect.TypeToken;
55
56 /**
57  * Tests for various rules API endpoints.
58  *
59  * @author David Graeff - Initial contribution
60  */
61 @NonNullByDefault
62 public class RulesTests {
63     protected @NonNullByDefault({}) CommonSetup commonSetup;
64     protected @NonNullByDefault({}) ConfigStore cs;
65     protected @NonNullByDefault({}) ItemRegistry itemRegistry;
66     protected @NonNullByDefault({}) RuleRegistry ruleRegistry;
67
68     Rules subject = new Rules();
69     LightsAndGroups lightsAndGroups = new LightsAndGroups();
70
71     private void addItemToReg(GenericItem item, State state, String tag, String label) {
72         item.setState(state);
73         item.setLabel(label);
74         item.addTag(tag);
75         itemRegistry.add(item);
76     }
77
78     @Before
79     public void setUp() throws IOException {
80         commonSetup = new CommonSetup(false);
81         this.cs = commonSetup.cs;
82
83         itemRegistry = new DummyItemRegistry();
84         ruleRegistry = new DummyRuleRegistry();
85
86         subject.cs = commonSetup.cs;
87         subject.userManagement = commonSetup.userManagement;
88         subject.ruleRegistry = ruleRegistry;
89         subject.itemRegistry = itemRegistry;
90         subject.activate();
91
92         // We need the LightsAndGroups class to convert registry entries into HueDatastore
93         // light entries
94         lightsAndGroups.cs = cs;
95         lightsAndGroups.eventPublisher = commonSetup.eventPublisher;
96         lightsAndGroups.userManagement = commonSetup.userManagement;
97         lightsAndGroups.itemRegistry = itemRegistry;
98         lightsAndGroups.activate();
99
100         addItemToReg(new SwitchItem("switch1"), OnOffType.ON, "Switchable", "name1");
101         addItemToReg(new SwitchItem("switch2"), OnOffType.ON, "Switchable", "name2");
102         addItemToReg(new ColorItem("color1"), HSBType.BLUE, "ColorLighting", "");
103
104         commonSetup.start(new ResourceConfig().registerInstances(subject));
105     }
106
107     @After
108     public void tearDown() {
109         RuleUtils.random = new Random();
110         commonSetup.dispose();
111     }
112
113     @Test
114     public void addUpdateRemoveScheduleToRegistry() {
115         assertThat(cs.ds.lights.get("switch1"), is(notNullValue()));
116
117         HueCommand command = new HueCommand("/api/testuser/lights/switch1/state", "PUT", "{'on':true}");
118         HueRuleEntry.Condition condition = new HueRuleEntry.Condition("/lights/switch1/state/on", Operator.dx, null);
119
120         Entry<Trigger, Condition> triggerCond = Rules.hueConditionToAutomation(command.address.replace("/", "-"),
121                 condition, itemRegistry);
122
123         Rule rule = RuleBuilder.create("demo1").withName("test name").withTags(Rules.RULES_TAG) //
124                 .withActions(RuleUtils.createHttpAction(command, "command")) //
125                 .withTriggers(triggerCond.getKey()).withConditions(triggerCond.getValue()).build();
126
127         ruleRegistry.add(rule);
128
129         // Check hue entry
130         HueRuleEntry entry = cs.ds.rules.get("demo1");
131         assertThat(entry.conditions.get(0).address, is("/lights/switch1/state/on"));
132         assertThat(entry.conditions.get(0).operator, is(Operator.dx));
133         assertThat(entry.actions.get(0).address, is("/lights/switch1/state"));
134         assertThat(entry.actions.get(0).method, is("PUT"));
135         assertThat(entry.actions.get(0).body, is("{'on':true}"));
136
137         // Update
138         command = new HueCommand("/api/testuser/lights/switch2/state", "PUT", "{'on':false}");
139         rule = RuleBuilder.create("demo1").withName("name2").withTags(Rules.RULES_TAG) //
140                 .withActions(RuleUtils.createHttpAction(command, "command")) //
141                 .withTriggers(triggerCond.getKey()).withConditions(triggerCond.getValue()).build();
142         ruleRegistry.update(rule);
143
144         entry = cs.ds.rules.get("demo1");
145         assertThat(entry.actions.get(0).address, is("/lights/switch2/state"));
146         assertThat(entry.actions.get(0).method, is("PUT"));
147         assertThat(entry.actions.get(0).body, is("{'on':false}"));
148         assertThat(entry.name, is("name2"));
149
150         // Remove
151
152         ruleRegistry.remove("demo1");
153         entry = cs.ds.rules.get("demo1");
154         assertThat(entry, nullValue());
155     }
156
157     @SuppressWarnings("null")
158     @Test
159     public void addGetRemoveRuleViaRest() {
160         // 1. Create
161         String body = "{\"name\":\"test name\",\"description\":\"\",\"owner\":\"\",\"conditions\":[{\"address\":\"/lights/switch1/state/on\",\"operator\":\"dx\"}],\"actions\":[{\"address\":\"/lights/switch1/state\",\"method\":\"PUT\",\"body\":\"{\\u0027on\\u0027:true}\"}]}";
162         Response response = commonSetup.client.target(commonSetup.basePath + "/testuser/rules").request()
163                 .post(Entity.json(body));
164         assertEquals(200, response.getStatus());
165         assertThat(response.readEntity(String.class), containsString("success"));
166
167         // 1.1 Check for entry
168         Entry<String, HueRuleEntry> idAndEntry = cs.ds.rules.entrySet().stream().findAny().get();
169         HueRuleEntry entry = idAndEntry.getValue();
170         assertThat(entry.name, is("test name"));
171         assertThat(entry.actions.get(0).address, is("/lights/switch1/state"));
172         assertThat(entry.conditions.get(0).address, is("/lights/switch1/state/on"));
173
174         // 1.2 Check for rule
175         Rule rule = ruleRegistry.get(idAndEntry.getKey());
176         assertThat(rule.getName(), is("test name"));
177         assertThat(rule.getActions().get(0).getId(), is("-api-testuser-lights-switch1-state"));
178         assertThat(rule.getActions().get(0).getTypeUID(), is("rules.HttpAction"));
179
180         // 2. Get
181         response = commonSetup.client.target(commonSetup.basePath + "/testuser/rules/" + idAndEntry.getKey()).request()
182                 .get();
183         assertEquals(200, response.getStatus());
184         HueSceneEntry fromJson = new Gson().fromJson(response.readEntity(String.class), HueSceneEntry.class);
185         assertThat(fromJson.name, is(idAndEntry.getValue().name));
186
187         // 3. Remove
188         response = commonSetup.client.target(commonSetup.basePath + "/testuser/rules/" + idAndEntry.getKey()).request()
189                 .delete();
190         assertEquals(200, response.getStatus());
191         assertTrue(cs.ds.rules.isEmpty());
192     }
193
194     @Test
195     public void updateRuleViaRest() {
196         HueCommand command = new HueCommand("/api/testuser/lights/switch1/state", "PUT", "{'on':true}");
197         HueRuleEntry.Condition condition = new HueRuleEntry.Condition("/lights/switch1/state/on", Operator.dx, null);
198
199         Entry<Trigger, Condition> triggerCond = Rules.hueConditionToAutomation(command.address.replace("/", "-"),
200                 condition, itemRegistry);
201
202         Rule rule = RuleBuilder.create("demo1").withName("test name").withTags(Rules.RULES_TAG) //
203                 .withActions(RuleUtils.createHttpAction(command, "command")) //
204                 .withTriggers(triggerCond.getKey()).withConditions(triggerCond.getValue()).build();
205
206         ruleRegistry.add(rule);
207
208         // Modify (just the name)
209         String body = "{ 'name':'A new name'}";
210         Response response = commonSetup.client.target(commonSetup.basePath + "/testuser/rules/demo1").request()
211                 .put(Entity.json(body));
212         assertEquals(200, response.getStatus());
213         assertThat(response.readEntity(String.class), containsString("name"));
214
215         Entry<String, HueRuleEntry> idAndEntry = cs.ds.rules.entrySet().stream().findAny().get();
216         HueRuleEntry entry = idAndEntry.getValue();
217         assertThat(entry.name, is("A new name"));
218         assertThat(entry.actions.get(0).address, is("/lights/switch1/state"));
219         assertThat(entry.conditions.get(0).address, is("/lights/switch1/state/on"));
220
221         // Reset
222         rule = RuleBuilder.create("demo1").withName("test name").withTags(Rules.RULES_TAG) //
223                 .withActions(RuleUtils.createHttpAction(command, "command")) //
224                 .withTriggers(triggerCond.getKey()).withConditions(triggerCond.getValue()).build();
225
226         ruleRegistry.update(rule); // Reset rule
227
228         idAndEntry = cs.ds.rules.entrySet().stream().findAny().get();
229
230         // Modify (Change condition)
231         body = "{\"conditions\":[{\"address\":\"/lights/switch1/state/on\",\"operator\":\"ddx\"}]}";
232         response = commonSetup.client.target(commonSetup.basePath + "/testuser/rules/demo1").request()
233                 .put(Entity.json(body));
234         assertEquals(200, response.getStatus());
235         assertThat(response.readEntity(String.class), containsString("conditions"));
236
237         idAndEntry = cs.ds.rules.entrySet().stream().findAny().get();
238         entry = idAndEntry.getValue();
239         assertThat(entry.name, is("test name")); // should not have changed
240         assertThat(entry.conditions.get(0).operator, is(Operator.ddx));
241
242         // Modify (Change action)
243         body = "{\"actions\":[{\"address\":\"/lights/switch2/state\",\"method\":\"PUT\",\"body\":\"{\\u0027on\\u0027:false}\"}]}";
244         response = commonSetup.client.target(commonSetup.basePath + "/testuser/rules/demo1").request()
245                 .put(Entity.json(body));
246         assertEquals(200, response.getStatus());
247         assertThat(response.readEntity(String.class), containsString("actions"));
248
249         idAndEntry = cs.ds.rules.entrySet().stream().findAny().get();
250         entry = idAndEntry.getValue();
251         assertThat(entry.name, is("test name")); // should not have changed
252         assertThat(entry.actions.get(0).address, is("/lights/switch2/state"));
253     }
254
255     @Test
256     public void getAll() {
257         HueCommand command = new HueCommand("/api/testuser/lights/switch1/state", "PUT", "{'on':true}");
258         HueRuleEntry.Condition condition = new HueRuleEntry.Condition("/lights/switch1/state/on", Operator.dx, null);
259
260         Entry<Trigger, Condition> triggerCond = Rules.hueConditionToAutomation(command.address.replace("/", "-"),
261                 condition, itemRegistry);
262
263         Rule rule = RuleBuilder.create("demo1").withName("test name").withTags(Rules.RULES_TAG) //
264                 .withActions(RuleUtils.createHttpAction(command, "command")) //
265                 .withTriggers(triggerCond.getKey()).withConditions(triggerCond.getValue()).build();
266
267         ruleRegistry.add(rule);
268
269         Response response = commonSetup.client.target(commonSetup.basePath + "/testuser/rules").request().get();
270         Type type = new TypeToken<Map<String, HueRuleEntry>>() {
271         }.getType();
272         String body = response.readEntity(String.class);
273         Map<String, HueRuleEntry> fromJson = new Gson().fromJson(body, type);
274         HueRuleEntry entry = fromJson.get("demo1");
275         assertThat(entry.name, is("test name"));
276         assertThat(entry.actions.get(0).address, is("/lights/switch1/state"));
277         assertThat(entry.conditions.get(0).address, is("/lights/switch1/state/on"));
278     }
279 }