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