2 * Copyright (c) 2010-2021 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.binding.webthing.internal.link;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.Mockito.*;
19 import java.nio.file.Files;
20 import java.nio.file.Paths;
22 import java.util.Objects;
23 import java.util.concurrent.ConcurrentHashMap;
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.junit.jupiter.api.Test;
27 import org.openhab.binding.webthing.internal.ChannelHandler;
28 import org.openhab.binding.webthing.internal.channel.Channels;
29 import org.openhab.binding.webthing.internal.client.Mocks;
30 import org.openhab.binding.webthing.internal.client.WebthingTest;
31 import org.openhab.binding.webthing.internal.client.dto.PropertyStatusMessage;
32 import org.openhab.core.library.types.*;
33 import org.openhab.core.thing.*;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.State;
37 import com.google.gson.Gson;
42 * Please consider that changes of 'ItemType<->PropertyType mapping' validated by this test
43 * will break the compatibility to former releases.
45 * @author Gregor Roth - Initial contribution
48 public class WebthingChannelLinkTest {
49 private final Gson gson = new Gson();
52 public void testChannelToProperty() throws Exception {
53 var httpClient = mock(org.eclipse.jetty.client.HttpClient.class);
54 var request = Mocks.mockRequest(null, load("/awning_response.json"));
55 when(httpClient.newRequest(URI.create("http://example.org:8090/0"))).thenReturn(request);
57 var request2 = Mocks.mockRequest("{\"target_position\":10}", load("/awning_property.json"));
58 when(httpClient.newRequest(URI.create("http://example.org:8090/0/properties/target_position")))
59 .thenReturn(request2);
61 var thingUID = new ThingUID("webthing", "anwing");
62 var channelUID = Channels.createChannelUID(thingUID, "target_position");
64 var webthing = WebthingTest.createTestWebthing("http://example.org:8090/0", httpClient);
65 var channel = Channels.createChannel(thingUID, "target_position",
66 Objects.requireNonNull(webthing.getPropertyDescription("target_position")));
68 var testWebthingThingHandler = new TestWebthingThingHandler();
69 ChannelToPropertyLink.establish(testWebthingThingHandler, channel, webthing, "target_position");
71 testWebthingThingHandler.listeners.get(channelUID).onItemStateChanged(channelUID, new DecimalType(10));
75 public void testChannelToPropertyServerError() throws Exception {
76 var httpClient = mock(org.eclipse.jetty.client.HttpClient.class);
77 var request = Mocks.mockRequest(null, load("/awning_response.json"));
78 when(httpClient.newRequest(URI.create("http://example.org:8090/0"))).thenReturn(request);
80 var request2 = Mocks.mockRequest("{\"target_position\":130}", load("/awning_property.json"), 200, 500);
81 when(httpClient.newRequest(URI.create("http://example.org:8090/0/properties/target_position")))
82 .thenReturn(request2);
84 var thingUID = new ThingUID("webthing", "anwing");
85 var channelUID = Channels.createChannelUID(thingUID, "target_position");
87 var webthing = WebthingTest.createTestWebthing("http://example.org:8090/0", httpClient);
88 var channel = Channels.createChannel(thingUID, "target_position",
89 Objects.requireNonNull(webthing.getPropertyDescription("target_position")));
91 var testWebthingThingHandler = new TestWebthingThingHandler();
92 ChannelToPropertyLink.establish(testWebthingThingHandler, channel, webthing, "target_position");
94 testWebthingThingHandler.listeners.get(channelUID).onItemStateChanged(channelUID, new DecimalType(130));
98 public void testPropertyToChannel() throws Exception {
99 var httpClient = mock(org.eclipse.jetty.client.HttpClient.class);
100 var request = Mocks.mockRequest(null, load("/awning_response.json"));
101 when(httpClient.newRequest(URI.create("http://example.org:8090/0"))).thenReturn(request);
103 var request2 = Mocks.mockRequest("{\"target_position\":10}", load("/awning_property.json"));
104 when(httpClient.newRequest(URI.create("http://example.org:8090/0/properties/target_position")))
105 .thenReturn(request2);
107 var thingUID = new ThingUID("webthing", "anwing");
108 var channelUID = Channels.createChannelUID(thingUID, "target_position");
110 var errorHandler = new WebthingTest.ErrorHandler();
111 var websocketConnectionFactory = new WebthingTest.TestWebsocketConnectionFactory();
112 var webthing = WebthingTest.createTestWebthing("http://example.org:8090/0", httpClient, errorHandler,
113 websocketConnectionFactory);
114 var channel = Channels.createChannel(thingUID, "target_position",
115 Objects.requireNonNull(webthing.getPropertyDescription("target_position")));
117 var testWebthingThingHandler = new TestWebthingThingHandler();
118 PropertyToChannelLink.establish(webthing, "target_position", testWebthingThingHandler, channel);
120 var message = new PropertyStatusMessage();
121 message.messageType = "propertyStatus";
122 message.data = Map.of("target_position", 77);
123 websocketConnectionFactory.webSocketRef.get().sendToClient(message);
125 assertEquals(new DecimalType(77), testWebthingThingHandler.itemState.get(channelUID));
129 public void testDataTypeMapping() throws Exception {
130 performDataTypeMappingTest("level_prop", 56.5, new DecimalType(56.5), 3.5, new DecimalType(3.5));
131 performDataTypeMappingTest("level_unit_prop", 10, new PercentType(10), 90, new PercentType(90));
132 performDataTypeMappingTest("thermo_prop", "off", new StringType("off"), "auto", new StringType("auto"));
133 performDataTypeMappingTest("temp_prop", 18.6, new DecimalType(18.6), 23.2, new DecimalType(23.2));
134 performDataTypeMappingTest("targettemp_prop", 18.6, new DecimalType(18.6), 23.2, new DecimalType(23.2));
135 performDataTypeMappingTest("open_prop", true, OpenClosedType.OPEN, false, OpenClosedType.CLOSED);
136 performDataTypeMappingTest("colortemp_prop", 10, new PercentType(10), 60, new PercentType(60));
137 performDataTypeMappingTest("color_prop", "#f2fe00", new HSBType("62,100,99"), "#ff0000",
138 new HSBType("0.0,100.0,100.0"));
139 performDataTypeMappingTest("colormode_prop", "color", new StringType("color"), "temperature",
140 new StringType("temperature"));
141 performDataTypeMappingTest("brightness_prop", 33, new PercentType(33), 65, new PercentType(65));
142 performDataTypeMappingTest("voltage_prop", 4.5, new DecimalType(4.5), 30.2, new DecimalType(30.2));
143 performDataTypeMappingTest("heating_prop", "off", new StringType("off"), "cooling", new StringType("cooling"));
144 performDataTypeMappingTest("onoff_prop", true, OnOffType.ON, false, OnOffType.OFF);
145 performDataTypeMappingTest("string_prop", "initial", new StringType("initial"), "updated",
146 new StringType("updated"));
147 performDataTypeMappingTest("number_prop", 80.5, new DecimalType(80.5), 60.9, new DecimalType(60.9));
148 performDataTypeMappingTest("integer_prop", 11, new DecimalType(11), 77, new DecimalType(77));
149 performDataTypeMappingTest("boolean_prop", true, OnOffType.ON, false, OnOffType.OFF);
152 private void performDataTypeMappingTest(String propertyName, Object initialValue, State initialState,
153 Object updatedValue, State updatedState) throws Exception {
154 var httpClient = mock(org.eclipse.jetty.client.HttpClient.class);
155 var request = Mocks.mockRequest(null, load("/datatypes_test_response.json"));
156 when(httpClient.newRequest(URI.create("http://example.org:8090/"))).thenReturn(request);
158 var request2 = Mocks.mockRequest(gson.toJson(Map.of(propertyName, updatedValue)),
159 gson.toJson(Map.of(propertyName, initialValue)));
160 when(httpClient.newRequest(URI.create("http://example.org:8090/properties/" + propertyName)))
161 .thenReturn(request2);
163 var thingUID = new ThingUID("webthing", "test");
164 var channelUID = Channels.createChannelUID(thingUID, propertyName);
166 var errorHandler = new WebthingTest.ErrorHandler();
167 var websocketConnectionFactory = new WebthingTest.TestWebsocketConnectionFactory();
168 var webthing = WebthingTest.createTestWebthing("http://example.org:8090/", httpClient, errorHandler,
169 websocketConnectionFactory);
170 var channel = Channels.createChannel(thingUID, propertyName,
171 Objects.requireNonNull(webthing.getPropertyDescription(propertyName)));
173 var testWebthingThingHandler = new TestWebthingThingHandler();
175 PropertyToChannelLink.establish(webthing, propertyName, testWebthingThingHandler, channel);
177 var message = new PropertyStatusMessage();
178 message.messageType = "propertyStatus";
179 message.data = Map.of(propertyName, initialValue);
180 websocketConnectionFactory.webSocketRef.get().sendToClient(message);
182 assertEquals(initialState, testWebthingThingHandler.itemState.get(channelUID));
184 ChannelToPropertyLink.establish(testWebthingThingHandler, channel, webthing, propertyName);
185 testWebthingThingHandler.listeners.get(channelUID).onItemStateChanged(channelUID, updatedState);
188 public static String load(String name) throws Exception {
189 return new String(Files.readAllBytes(Paths.get(WebthingTest.class.getResource(name).toURI())));
192 private static class TestWebthingThingHandler implements ChannelHandler {
193 public final Map<ChannelUID, ItemChangedListener> listeners = new ConcurrentHashMap<>();
194 public final Map<ChannelUID, Command> itemState = new ConcurrentHashMap<>();
197 public void observeChannel(ChannelUID channelUID, ItemChangedListener listener) {
198 listeners.put(channelUID, listener);
202 public void updateItemState(ChannelUID channelUID, Command command) {
203 itemState.put(channelUID, command);