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