2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.io.hueemulation.internal.rest;
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.*;
19 import java.io.IOException;
20 import java.lang.reflect.Type;
22 import java.util.Map.Entry;
24 import javax.ws.rs.client.Entity;
25 import javax.ws.rs.core.Response;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.glassfish.jersey.server.ResourceConfig;
29 import org.hamcrest.CoreMatchers;
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.Rule;
34 import org.openhab.core.automation.RuleRegistry;
35 import org.openhab.core.automation.util.RuleBuilder;
36 import org.openhab.core.items.GenericItem;
37 import org.openhab.core.items.GroupItem;
38 import org.openhab.core.items.ItemRegistry;
39 import org.openhab.core.library.items.ColorItem;
40 import org.openhab.core.library.items.DimmerItem;
41 import org.openhab.core.library.items.RollershutterItem;
42 import org.openhab.core.library.items.SwitchItem;
43 import org.openhab.core.library.types.HSBType;
44 import org.openhab.core.library.types.OnOffType;
45 import org.openhab.core.library.types.PercentType;
46 import org.openhab.core.types.Command;
47 import org.openhab.core.types.State;
48 import org.openhab.io.hueemulation.internal.ConfigStore;
49 import org.openhab.io.hueemulation.internal.dto.HueSceneEntry;
50 import org.openhab.io.hueemulation.internal.rest.mocks.DummyItemRegistry;
51 import org.openhab.io.hueemulation.internal.rest.mocks.DummyRuleRegistry;
53 import com.google.gson.Gson;
54 import com.google.gson.reflect.TypeToken;
57 * Tests for various scene API endpoints.
59 * @author David Graeff - Initial contribution
62 public class SceneTests {
63 protected @NonNullByDefault({}) CommonSetup commonSetup;
64 protected @NonNullByDefault({}) ConfigStore cs;
65 protected @NonNullByDefault({}) ItemRegistry itemRegistry;
66 protected @NonNullByDefault({}) RuleRegistry ruleRegistry;
68 Scenes subject = new Scenes();
70 private void addItemToReg(GenericItem item, State state, String tag) {
73 itemRegistry.add(item);
77 public void setUp() throws IOException {
78 commonSetup = new CommonSetup(false);
79 this.cs = commonSetup.cs;
81 itemRegistry = new DummyItemRegistry();
82 ruleRegistry = new DummyRuleRegistry();
84 subject.cs = commonSetup.cs;
85 subject.userManagement = commonSetup.userManagement;
86 subject.itemRegistry = itemRegistry;
87 subject.ruleRegistry = ruleRegistry;
90 // Add simulated lights
91 addItemToReg(new SwitchItem("switch1"), OnOffType.ON, "Switchable");
92 addItemToReg(new ColorItem("color1"), HSBType.BLUE, "ColorLighting");
93 addItemToReg(new DimmerItem("white1"), new PercentType(12), "Lighting");
94 addItemToReg(new RollershutterItem("roller1"), new PercentType(12), "Lighting");
95 addItemToReg(new DimmerItem("white1"), new PercentType(12), "Lighting");
96 addItemToReg(new GroupItem("group1"), OnOffType.ON, "Switchable");
98 commonSetup.start(new ResourceConfig().registerInstances(subject));
102 public void tearDown() throws Exception {
103 commonSetup.dispose();
106 @SuppressWarnings("null")
108 public void addUpdateRemoveSceneToRegistry() {
109 Rule rule = RuleBuilder.create("demo1").withTags("scene") //
110 .withActions(Scenes.actionFromState("switch1", (Command) OnOffType.ON)).build();
112 ruleRegistry.add(rule);
114 HueSceneEntry sceneEntry = cs.ds.scenes.get("demo1");
115 assertThat(sceneEntry.lights.get(0), CoreMatchers.is("switch1"));
118 rule = RuleBuilder.create("demo1").withTags("scene") //
119 .withActions(Scenes.actionFromState("white1", (Command) OnOffType.ON)).build();
120 ruleRegistry.update(rule);
122 sceneEntry = cs.ds.scenes.get("demo1");
123 assertThat(sceneEntry.lights.get(0), CoreMatchers.is("white1"));
127 ruleRegistry.remove("demo1");
128 sceneEntry = cs.ds.scenes.get("demo1");
129 assertThat(sceneEntry, CoreMatchers.nullValue());
132 @SuppressWarnings("null")
134 public void addGetRemoveSceneViaRest() {
136 String body = "{ 'name':'Cozy dinner', 'recycle':false, 'lights':['switch1','white1'], 'type':'LightScene'}";
137 Response response = commonSetup.client.target(commonSetup.basePath + "/testuser/scenes").request()
138 .post(Entity.json(body));
139 assertEquals(200, response.getStatus());
140 assertThat(response.readEntity(String.class), containsString("success"));
142 // 1.1 Check for scene entry
143 Entry<String, HueSceneEntry> entry = cs.ds.scenes.entrySet().stream().findAny().get();
144 assertThat(entry.getValue().name, is("Cozy dinner"));
145 assertThat(entry.getValue().lights.get(0), is("switch1"));
146 assertThat(entry.getValue().lights.get(1), is("white1"));
148 // 1.2 Check for rule
149 Rule rule = ruleRegistry.get(entry.getKey());
150 assertThat(rule.getName(), is("Cozy dinner"));
151 assertThat(rule.getActions().get(0).getId(), is("switch1"));
152 assertThat(rule.getActions().get(1).getId(), is("white1"));
155 response = commonSetup.client.target(commonSetup.basePath + "/testuser/scenes/" + entry.getKey()).request()
157 assertEquals(200, response.getStatus());
158 HueSceneEntry fromJson = new Gson().fromJson(response.readEntity(String.class), HueSceneEntry.class);
159 assertThat(fromJson.name, is(entry.getValue().name));
162 response = commonSetup.client.target(commonSetup.basePath + "/testuser/scenes/" + entry.getKey()).request()
164 assertEquals(200, response.getStatus());
165 assertTrue(cs.ds.scenes.isEmpty());
168 @SuppressWarnings("null")
170 public void updateSceneViaRest() {
171 Rule rule = RuleBuilder.create("demo1").withTags("scene").withName("Some name") //
172 .withActions(Scenes.actionFromState("switch1", (Command) OnOffType.ON)).build();
174 ruleRegistry.add(rule);
176 // 3. Modify (just the name)
177 String body = "{ 'name':'A new name'}";
178 Response response = commonSetup.client.target(commonSetup.basePath + "/testuser/scenes/demo1").request()
179 .put(Entity.json(body));
180 assertEquals(200, response.getStatus());
181 assertThat(response.readEntity(String.class), containsString("name"));
183 Entry<String, HueSceneEntry> sceneEntry = cs.ds.scenes.entrySet().stream().findAny().get();
184 assertThat(sceneEntry.getValue().name, is("A new name"));
185 assertThat(sceneEntry.getValue().lights.get(0), is("switch1")); // nothing else should have changed
187 // 3. Modify (just the lights)
188 rule = RuleBuilder.create("demo1").withTags("scene").withName("Some name") //
189 .withActions(Scenes.actionFromState("switch1", (Command) OnOffType.ON)).build();
191 ruleRegistry.update(rule); // Reset rule
193 sceneEntry = cs.ds.scenes.entrySet().stream().findAny().get();
194 String uid = sceneEntry.getKey();
196 // Without store lights
197 body = "{ 'lights':['white1']}";
198 response = commonSetup.client.target(commonSetup.basePath + "/testuser/scenes/demo1").request()
199 .put(Entity.json(body));
200 assertEquals(200, response.getStatus());
201 assertThat(response.readEntity(String.class), containsString("lights"));
203 sceneEntry = cs.ds.scenes.entrySet().stream().findAny().get();
204 assertThat(sceneEntry.getValue().name, is("Some name")); // should not have changed
205 assertThat(sceneEntry.getKey(), is(uid));
206 assertThat(sceneEntry.getValue().lights.get(0), is("switch1")); // storelightstate not set, lights not changed
209 body = "{ 'lights':['white1'], 'storelightstate':true }";
210 response = commonSetup.client.target(commonSetup.basePath + "/testuser/scenes/demo1").request()
211 .put(Entity.json(body));
212 assertEquals(200, response.getStatus());
213 assertThat(response.readEntity(String.class), containsString("lights"));
215 sceneEntry = cs.ds.scenes.entrySet().stream().findAny().get();
216 assertThat(sceneEntry.getValue().lights.get(0), is("white1"));
220 public void getAll() {
221 Rule rule = RuleBuilder.create("demo1").withTags("scene") //
222 .withActions(Scenes.actionFromState("switch1", (Command) OnOffType.ON)).build();
224 ruleRegistry.add(rule);
226 Response response = commonSetup.client.target(commonSetup.basePath + "/testuser/scenes").request().get();
227 Type type = new TypeToken<Map<String, HueSceneEntry>>() {
229 Map<String, HueSceneEntry> fromJson = new Gson().fromJson(response.readEntity(String.class), type);
230 assertTrue(fromJson.containsKey("demo1"));