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.binding.wundergroundupdatereceiver.internal;
15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.Matchers.*;
17 import static org.hamcrest.core.Is.is;
18 import static org.mockito.Mockito.*;
19 import static org.mockito.MockitoAnnotations.openMocks;
20 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.*;
22 import java.io.IOException;
23 import java.util.Arrays;
24 import java.util.List;
26 import java.util.stream.Collectors;
28 import javax.servlet.ServletException;
29 import javax.servlet.http.HttpServletResponse;
31 import org.eclipse.jdt.annotation.NonNullByDefault;
32 import org.eclipse.jetty.http.HttpFields;
33 import org.eclipse.jetty.http.HttpURI;
34 import org.eclipse.jetty.http.HttpVersion;
35 import org.eclipse.jetty.http.MetaData;
36 import org.eclipse.jetty.server.HttpChannel;
37 import org.eclipse.jetty.server.Request;
38 import org.hamcrest.Matcher;
39 import org.junit.jupiter.api.BeforeEach;
40 import org.junit.jupiter.api.Test;
41 import org.mockito.Answers;
42 import org.openhab.core.config.core.Configuration;
43 import org.openhab.core.thing.Channel;
44 import org.openhab.core.thing.ChannelUID;
45 import org.openhab.core.thing.DefaultSystemChannelTypeProvider;
46 import org.openhab.core.thing.ManagedThingProvider;
47 import org.openhab.core.thing.Thing;
48 import org.openhab.core.thing.ThingUID;
49 import org.openhab.core.thing.binding.ThingHandlerCallback;
50 import org.openhab.core.thing.binding.builder.ThingBuilder;
51 import org.openhab.core.thing.internal.type.StateChannelTypeBuilderImpl;
52 import org.openhab.core.thing.internal.type.TriggerChannelTypeBuilderImpl;
53 import org.openhab.core.thing.type.ChannelKind;
54 import org.openhab.core.thing.type.ChannelTypeProvider;
55 import org.openhab.core.thing.type.ChannelTypeRegistry;
56 import org.openhab.core.thing.type.ChannelTypeUID;
57 import org.osgi.service.http.NamespaceException;
60 * @author Daniel Demus - Initial contribution
63 class WundergroundUpdateReceiverDiscoveryServiceTest {
65 private static final String STATION_ID_1 = "abcd1234";
66 private static final String REQ_STATION_ID = "dfggger";
67 private static final ThingUID TEST_THING_UID = new ThingUID(THING_TYPE_UPDATE_RECEIVER, "test-receiver");
75 void programmaticChannelsAreAddedCorrectlyOnce() {
77 final String queryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "humidity=74&" + "AqPM2.5=30&"
78 + "windspdmph_avg2m=10&" + "dateutc=2021-02-07%2014:04:03&" + "softwaretype=WH2600%20V2.2.8&"
79 + "action=updateraw&" + "realtime=1&" + "rtfreq=5";
80 MetaData.Request request = new MetaData.Request("GET",
81 new HttpURI("http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + queryString),
82 HttpVersion.HTTP_1_1, new HttpFields());
83 HttpChannel httpChannel = mock(HttpChannel.class);
84 Request req = new Request(httpChannel, null);
85 req.setMetaData(request);
87 TestChannelTypeRegistry channelTypeRegistry = new TestChannelTypeRegistry();
88 WundergroundUpdateReceiverDiscoveryService discoveryService = new WundergroundUpdateReceiverDiscoveryService(
90 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(discoveryService);
91 discoveryService.addUnhandledStationId(REQ_STATION_ID, sut.normalizeParameterMap(req.getParameterMap()));
92 Thing thing = ThingBuilder.create(SUPPORTED_THING_TYPES_UIDS.stream().findFirst().get(), TEST_THING_UID)
93 .withConfiguration(new Configuration(Map.of(REPRESENTATION_PROPERTY, REQ_STATION_ID)))
94 .withLabel("test thing").withLocation("location").build();
95 ManagedThingProvider managedThingProvider = mock(ManagedThingProvider.class);
96 when(managedThingProvider.get(any())).thenReturn(thing);
97 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(thing, sut, discoveryService,
98 new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry, managedThingProvider);
99 handler.setCallback(mock(ThingHandlerCallback.class));
102 handler.initialize();
103 var actual = handler.getThing().getChannels();
106 assertThat(actual.size(), is(9));
108 assertChannel(actual, METADATA_GROUP, LAST_RECEIVED, LAST_RECEIVED_DATETIME_CHANNELTYPEUID, ChannelKind.STATE,
110 assertChannel(actual, METADATA_GROUP, LAST_QUERY_TRIGGER, LAST_QUERY_TRIGGER_CHANNELTYPEUID,
111 ChannelKind.TRIGGER, nullValue());
112 assertChannel(actual, METADATA_GROUP, LAST_QUERY_STATE, LAST_QUERY_STATE_CHANNELTYPEUID, ChannelKind.STATE,
114 assertChannel(actual, METADATA_GROUP, DATEUTC, DATEUTC_CHANNELTYPEUID, ChannelKind.STATE, is("String"));
115 assertChannel(actual, METADATA_GROUP, REALTIME_FREQUENCY, REALTIME_FREQUENCY_CHANNELTYPEUID, ChannelKind.STATE,
117 assertChannel(actual, METADATA_GROUP, SOFTWARE_TYPE, SOFTWARETYPE_CHANNELTYPEUID, ChannelKind.STATE,
119 assertChannel(actual, HUMIDITY_GROUP, HUMIDITY, HUMIDITY_CHANNELTYPEUID, ChannelKind.STATE,
120 is("Number:Dimensionless"));
121 assertChannel(actual, WIND_GROUP, WIND_SPEED_AVG_2MIN, WIND_SPEED_AVG_2MIN_CHANNELTYPEUID, ChannelKind.STATE,
123 assertChannel(actual, POLLUTION_GROUP, AQ_PM2_5, PM2_5_MASS_CHANNELTYPEUID, ChannelKind.STATE,
124 is("Number:Density"));
128 void aRequestWithAnUnregisteredStationidIsAddedToTheQueueOnce()
129 throws ServletException, NamespaceException, IOException {
131 final String queryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "tempf=26.1&" + "humidity=74&" + "dewptf=18.9&"
132 + "windchillf=26.1&" + "winddir=14&" + "windspeedmph=1.34&" + "windgustmph=2.46&" + "rainin=0.00&"
133 + "dailyrainin=0.00&" + "weeklyrainin=0.00&" + "monthlyrainin=0.08&" + "yearlyrainin=3.06&"
134 + "solarradiation=42.24&" + "UV=1&indoortempf=69.3&" + "indoorhumidity=32&" + "baromin=30.39&"
135 + "AqNOX=21&" + "lowbatt=1&" + "dateutc=2021-02-07%2014:04:03&" + "softwaretype=WH2600%20V2.2.8&"
136 + "action=updateraw&" + "realtime=1&" + "rtfreq=5";
137 WundergroundUpdateReceiverDiscoveryService discoveryService = mock(
138 WundergroundUpdateReceiverDiscoveryService.class);
139 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(discoveryService);
140 WundergroundUpdateReceiverHandler handler = mock(WundergroundUpdateReceiverHandler.class);
141 when(handler.getStationId()).thenReturn(STATION_ID_1);
142 sut.addHandler(handler);
143 when(discoveryService.isBackgroundDiscoveryEnabled()).thenReturn(false);
146 assertThat(sut.isActive(), is(true));
148 HttpChannel httpChannel = mock(HttpChannel.class);
149 MetaData.Request request = new MetaData.Request("GET",
150 new HttpURI("http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + queryString),
151 HttpVersion.HTTP_1_1, new HttpFields());
152 Request req = new Request(httpChannel, null);
153 req.setMetaData(request);
156 sut.doGet(req, mock(HttpServletResponse.class, Answers.RETURNS_MOCKS));
159 verify(handler, never()).updateChannelStates(any());
160 verify(discoveryService).addUnhandledStationId(eq("dfggger"), any());
161 assertThat(sut.isActive(), is(true));
165 void multipleIndexedParametersOfTheSameChanneltypeAreCorrectlyDiscovered() throws IOException {
167 final String queryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "temp1f=26.1&" + "humidity=74&" + "temp2f=25.1&"
168 + "lowbatt=1&" + "soilmoisture1=78&" + "soilmoisture2=73&" + "dateutc=2021-02-07%2014:04:03&"
169 + "softwaretype=WH2600%20V2.2.8&" + "action=updateraw&" + "realtime=1&" + "rtfreq=5";
170 MetaData.Request request = new MetaData.Request("GET",
171 new HttpURI("http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + queryString),
172 HttpVersion.HTTP_1_1, new HttpFields());
173 HttpChannel httpChannel = mock(HttpChannel.class);
174 Request req = new Request(httpChannel, null);
175 req.setMetaData(request);
177 TestChannelTypeRegistry channelTypeRegistry = new TestChannelTypeRegistry();
178 WundergroundUpdateReceiverDiscoveryService discoveryService = new WundergroundUpdateReceiverDiscoveryService(
180 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(discoveryService);
181 discoveryService.addUnhandledStationId(REQ_STATION_ID, sut.normalizeParameterMap(req.getParameterMap()));
182 Thing thing = ThingBuilder.create(SUPPORTED_THING_TYPES_UIDS.stream().findFirst().get(), TEST_THING_UID)
183 .withConfiguration(new Configuration(Map.of(REPRESENTATION_PROPERTY, REQ_STATION_ID)))
184 .withLabel("test thing").withLocation("location").build();
185 ManagedThingProvider managedThingProvider = mock(ManagedThingProvider.class);
186 when(managedThingProvider.get(TEST_THING_UID)).thenReturn(thing);
187 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(thing, sut, discoveryService,
188 new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry, managedThingProvider);
189 handler.setCallback(mock(ThingHandlerCallback.class));
190 handler.initialize();
191 sut.addHandler(handler);
197 assertThat(sut.isActive(), is(true));
200 sut.doGet(req, mock(HttpServletResponse.class, Answers.RETURNS_MOCKS));
203 assertThat(sut.getHandlers().size(), is(1));
204 assertThat(sut.getHandlers().containsKey(REQ_STATION_ID), is(true));
205 assertThat(handler.getThing().getChannels().stream()
206 .filter(channel -> channel.getChannelTypeUID() == TEMPERATURE_CHANNELTYPEUID).count(), is(2L));
210 void unregisteredChannelsAreAddedOnTheFlyWhenDiscovered() throws IOException {
212 final String firstDeviceQueryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "tempf=26.1&" + "humidity=74&"
213 + "dateutc=2021-02-07%2014:04:03&" + "softwaretype=WH2600%20V2.2.8&" + "action=updateraw&"
214 + "realtime=1&" + "rtfreq=5";
215 MetaData.Request request1 = new MetaData.Request("GET", new HttpURI(
216 "http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + firstDeviceQueryString),
217 HttpVersion.HTTP_1_1, new HttpFields());
218 HttpChannel httpChannel = mock(HttpChannel.class);
219 Request req1 = new Request(httpChannel, null);
220 req1.setMetaData(request1);
222 TestChannelTypeRegistry channelTypeRegistry = new TestChannelTypeRegistry();
223 WundergroundUpdateReceiverDiscoveryService discoveryService = new WundergroundUpdateReceiverDiscoveryService(
225 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(discoveryService);
226 discoveryService.addUnhandledStationId(REQ_STATION_ID, sut.normalizeParameterMap(req1.getParameterMap()));
227 Thing thing = ThingBuilder.create(SUPPORTED_THING_TYPES_UIDS.stream().findFirst().get(), TEST_THING_UID)
228 .withConfiguration(new Configuration(Map.of(REPRESENTATION_PROPERTY, REQ_STATION_ID)))
229 .withLabel("test thing").withLocation("location").build();
230 ManagedThingProvider managedThingProvider = mock(ManagedThingProvider.class);
231 when(managedThingProvider.get(any())).thenReturn(thing);
232 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(thing, sut, discoveryService,
233 new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry, managedThingProvider);
234 handler.setCallback(mock(ThingHandlerCallback.class));
237 handler.initialize();
238 sut.addHandler(handler);
241 ChannelTypeUID[] expectedBefore = new ChannelTypeUID[] { TEMPERATURE_CHANNELTYPEUID, HUMIDITY_CHANNELTYPEUID,
242 DATEUTC_CHANNELTYPEUID, SOFTWARETYPE_CHANNELTYPEUID, REALTIME_FREQUENCY_CHANNELTYPEUID,
243 LAST_QUERY_STATE_CHANNELTYPEUID, LAST_RECEIVED_DATETIME_CHANNELTYPEUID,
244 LAST_QUERY_TRIGGER_CHANNELTYPEUID };
245 List<ChannelTypeUID> before = handler.getThing().getChannels().stream().map(Channel::getChannelTypeUID)
246 .collect(Collectors.toList());
247 assertThat(before, hasItems(expectedBefore));
250 final String secondDeviceQueryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "lowbatt=1&" + "soilmoisture1=78&"
251 + "soilmoisture2=73&" + "solarradiation=42.24&" + "dateutc=2021-02-07%2014:04:03&"
252 + "softwaretype=WH2600%20V2.2.8&" + "action=updateraw&" + "realtime=1&" + "rtfreq=5";
253 MetaData.Request request = new MetaData.Request("GET", new HttpURI(
254 "http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + secondDeviceQueryString),
255 HttpVersion.HTTP_1_1, new HttpFields());
256 Request req2 = new Request(httpChannel, null);
257 req2.setMetaData(request);
261 assertThat(sut.isActive(), is(true));
264 sut.doGet(req2, mock(HttpServletResponse.class, Answers.RETURNS_MOCKS));
267 ChannelTypeUID[] expectedActual = Arrays.copyOf(expectedBefore, expectedBefore.length + 3);
268 System.arraycopy(new ChannelTypeUID[] { LOW_BATTERY_CHANNELTYPEUID, SOIL_MOISTURE_CHANNELTYPEUID,
269 SOLARRADIATION_CHANNELTYPEUID }, 0, expectedActual, expectedBefore.length, 3);
270 List<ChannelTypeUID> actual = handler.getThing().getChannels().stream().map(Channel::getChannelTypeUID)
271 .collect(Collectors.toList());
272 assertThat(actual, hasItems(expectedActual));
276 void unregisteredChannelsAreNotAddedOnUnmanagedThings() throws IOException {
278 final String firstDeviceQueryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "tempf=26.1&" + "humidity=74&"
279 + "dateutc=2021-02-07%2014:04:03&" + "softwaretype=WH2600%20V2.2.8&" + "action=updateraw&"
280 + "realtime=1&" + "rtfreq=5";
281 MetaData.Request request1 = new MetaData.Request("GET", new HttpURI(
282 "http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + firstDeviceQueryString),
283 HttpVersion.HTTP_1_1, new HttpFields());
284 HttpChannel httpChannel = mock(HttpChannel.class);
285 Request req1 = new Request(httpChannel, null);
286 req1.setMetaData(request1);
288 TestChannelTypeRegistry channelTypeRegistry = new TestChannelTypeRegistry();
289 WundergroundUpdateReceiverDiscoveryService discoveryService = new WundergroundUpdateReceiverDiscoveryService(
291 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(discoveryService);
292 discoveryService.addUnhandledStationId(REQ_STATION_ID, sut.normalizeParameterMap(req1.getParameterMap()));
293 Thing thing = ThingBuilder.create(SUPPORTED_THING_TYPES_UIDS.stream().findFirst().get(), TEST_THING_UID)
294 .withConfiguration(new Configuration(Map.of(REPRESENTATION_PROPERTY, REQ_STATION_ID)))
295 .withLabel("test thing").withLocation("location").build();
296 ManagedThingProvider managedThingProvider = mock(ManagedThingProvider.class);
297 when(managedThingProvider.get(any())).thenReturn(null);
298 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(thing, sut, discoveryService,
299 new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry, managedThingProvider);
300 handler.setCallback(mock(ThingHandlerCallback.class));
303 handler.initialize();
304 sut.addHandler(handler);
307 ChannelTypeUID[] expectedBefore = new ChannelTypeUID[] { TEMPERATURE_CHANNELTYPEUID, HUMIDITY_CHANNELTYPEUID,
308 DATEUTC_CHANNELTYPEUID, SOFTWARETYPE_CHANNELTYPEUID, REALTIME_FREQUENCY_CHANNELTYPEUID,
309 LAST_QUERY_STATE_CHANNELTYPEUID, LAST_RECEIVED_DATETIME_CHANNELTYPEUID,
310 LAST_QUERY_TRIGGER_CHANNELTYPEUID };
311 List<ChannelTypeUID> before = handler.getThing().getChannels().stream().map(Channel::getChannelTypeUID)
312 .collect(Collectors.toList());
313 assertThat(before, hasItems(expectedBefore));
316 final String secondDeviceQueryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "lowbatt=1&" + "soilmoisture1=78&"
317 + "soilmoisture2=73&" + "solarradiation=42.24&" + "dateutc=2021-02-07%2014:04:03&"
318 + "softwaretype=WH2600%20V2.2.8&" + "action=updateraw&" + "realtime=1&" + "rtfreq=5";
319 MetaData.Request request = new MetaData.Request("GET", new HttpURI(
320 "http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + secondDeviceQueryString),
321 HttpVersion.HTTP_1_1, new HttpFields());
322 Request req2 = new Request(httpChannel, null);
323 req2.setMetaData(request);
327 assertThat(sut.isActive(), is(true));
330 sut.doGet(req2, mock(HttpServletResponse.class, Answers.RETURNS_MOCKS));
333 List<ChannelTypeUID> actual = handler.getThing().getChannels().stream().map(Channel::getChannelTypeUID)
334 .collect(Collectors.toList());
335 assertThat(actual, equalTo(before));
339 void lastQueryTriggerIsMigratedSuccessfully() throws IOException {
341 final String firstDeviceQueryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "tempf=26.1&" + "humidity=74&"
342 + "dateutc=2021-02-07%2014:04:03&" + "softwaretype=WH2600%20V2.2.8&" + "action=updateraw&"
343 + "realtime=1&" + "rtfreq=5";
344 MetaData.Request request1 = new MetaData.Request("GET", new HttpURI(
345 "http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + firstDeviceQueryString),
346 HttpVersion.HTTP_1_1, new HttpFields());
347 HttpChannel httpChannel = mock(HttpChannel.class);
348 Request req1 = new Request(httpChannel, null);
349 req1.setMetaData(request1);
351 UpdatingChannelTypeRegistry channelTypeRegistry = new UpdatingChannelTypeRegistry();
352 WundergroundUpdateReceiverDiscoveryService discoveryService = new WundergroundUpdateReceiverDiscoveryService(
354 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(discoveryService);
355 discoveryService.addUnhandledStationId(REQ_STATION_ID, sut.normalizeParameterMap(req1.getParameterMap()));
356 Thing thing = ThingBuilder.create(SUPPORTED_THING_TYPES_UIDS.stream().findFirst().get(), TEST_THING_UID)
357 .withConfiguration(new Configuration(Map.of(REPRESENTATION_PROPERTY, REQ_STATION_ID)))
358 .withLabel("test thing").withLocation("location").build();
359 ManagedThingProvider managedThingProvider = mock(ManagedThingProvider.class);
360 when(managedThingProvider.get(any())).thenReturn(null);
361 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(thing, sut, discoveryService,
362 new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry, managedThingProvider);
363 handler.setCallback(mock(ThingHandlerCallback.class));
366 handler.initialize();
367 sut.addHandler(handler);
370 ChannelTypeUID[] expectedBefore = new ChannelTypeUID[] { TEMPERATURE_CHANNELTYPEUID, HUMIDITY_CHANNELTYPEUID,
371 DATEUTC_CHANNELTYPEUID, SOFTWARETYPE_CHANNELTYPEUID, REALTIME_FREQUENCY_CHANNELTYPEUID,
372 LAST_QUERY_STATE_CHANNELTYPEUID, LAST_RECEIVED_DATETIME_CHANNELTYPEUID,
373 LAST_QUERY_TRIGGER_CHANNELTYPEUID };
374 List<ChannelTypeUID> before = handler.getThing().getChannels().stream().map(Channel::getChannelTypeUID)
375 .collect(Collectors.toList());
376 assertThat(before, hasItems(expectedBefore));
379 var actual = handler.getThing().getChannels();
382 assertThat(actual.size(), is(8));
383 assertChannel(actual, METADATA_GROUP, LAST_QUERY_TRIGGER, LAST_QUERY_TRIGGER_CHANNELTYPEUID, ChannelKind.STATE,
388 handler.initialize();
390 final String secondDeviceQueryString = "ID=dfggger&" + "PASSWORD=XXXXXX&" + "lowbatt=1&" + "soilmoisture1=78&"
391 + "soilmoisture2=73&" + "solarradiation=42.24&" + "dateutc=2021-02-07%2014:04:03&"
392 + "softwaretype=WH2600%20V2.2.8&" + "action=updateraw&" + "realtime=1&" + "rtfreq=5";
393 MetaData.Request request = new MetaData.Request("GET", new HttpURI(
394 "http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + secondDeviceQueryString),
395 HttpVersion.HTTP_1_1, new HttpFields());
396 Request req2 = new Request(httpChannel, null);
397 req2.setMetaData(request);
401 assertThat(sut.isActive(), is(true));
404 sut.doGet(req2, mock(HttpServletResponse.class, Answers.RETURNS_MOCKS));
405 actual = handler.getThing().getChannels();
408 assertThat(actual.size(), is(8));
409 assertChannel(actual, METADATA_GROUP, LAST_QUERY_TRIGGER, LAST_QUERY_TRIGGER_CHANNELTYPEUID,
410 ChannelKind.TRIGGER, nullValue());
413 private void assertChannel(List<Channel> channels, String expectedGroup, String expectedName,
414 ChannelTypeUID expectedUid, ChannelKind expectedKind, Matcher<Object> expectedItemType) {
415 ChannelUID channelUID = new ChannelUID(TEST_THING_UID, expectedGroup, expectedName);
416 Channel actual = channels.stream().filter(c -> channelUID.equals(c.getUID())).findFirst().orElse(null);
417 assertThat(actual, is(notNullValue()));
418 assertThat(actual.getLabel() + " UID", actual.getUID(), is(channelUID));
419 assertThat(actual.getLabel() + " ChannelTypeUID", actual.getChannelTypeUID(), is(expectedUid));
420 assertThat(actual.getLabel() + " Kind", actual.getKind(), is(expectedKind));
421 assertThat(actual.getLabel() + " AcceptedItemType", actual.getAcceptedItemType(), expectedItemType);
424 abstract class AbstractTestChannelTypeRegistry extends ChannelTypeRegistry {
426 protected final ChannelTypeProvider provider;
428 AbstractTestChannelTypeRegistry(ChannelTypeProvider mock) {
430 this.provider = mock;
431 when(provider.getChannelType(eq(SOFTWARETYPE_CHANNELTYPEUID), any())).thenReturn(
432 new StateChannelTypeBuilderImpl(SOFTWARETYPE_CHANNELTYPEUID, "Software type", "String").build());
433 when(provider.getChannelType(eq(TEMPERATURE_CHANNELTYPEUID), any()))
434 .thenReturn(DefaultSystemChannelTypeProvider.SYSTEM_OUTDOOR_TEMPERATURE);
435 when(provider.getChannelType(eq(SOIL_MOISTURE_CHANNELTYPEUID), any()))
436 .thenReturn(new StateChannelTypeBuilderImpl(SOIL_MOISTURE_CHANNELTYPEUID, "Soilmoisture",
437 "Number:Dimensionless").build());
438 when(provider.getChannelType(eq(SOLARRADIATION_CHANNELTYPEUID), any()))
439 .thenReturn(new StateChannelTypeBuilderImpl(SOLARRADIATION_CHANNELTYPEUID, "Solar Radiation",
440 "Number:Intensity").build());
441 when(provider.getChannelType(eq(HUMIDITY_CHANNELTYPEUID), any())).thenReturn(
442 new StateChannelTypeBuilderImpl(HUMIDITY_CHANNELTYPEUID, "Humidity", "Number:Dimensionless")
444 when(provider.getChannelType(eq(WIND_SPEED_AVG_2MIN_CHANNELTYPEUID), any()))
445 .thenReturn(new StateChannelTypeBuilderImpl(WIND_SPEED_AVG_2MIN_CHANNELTYPEUID,
446 "Wind Speed 2min Average", "Number:Speed").build());
447 when(provider.getChannelType(eq(PM2_5_MASS_CHANNELTYPEUID), any())).thenReturn(
448 new StateChannelTypeBuilderImpl(PM2_5_MASS_CHANNELTYPEUID, "PM2.5 Mass", "Number:Density").build());
449 when(provider.getChannelType(eq(DATEUTC_CHANNELTYPEUID), any())).thenReturn(
450 new StateChannelTypeBuilderImpl(DATEUTC_CHANNELTYPEUID, "Last Updated", "String").build());
451 when(provider.getChannelType(eq(LOW_BATTERY_CHANNELTYPEUID), any()))
452 .thenReturn(DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_LOW_BATTERY);
453 when(provider.getChannelType(eq(REALTIME_FREQUENCY_CHANNELTYPEUID), any())).thenReturn(
454 new StateChannelTypeBuilderImpl(REALTIME_FREQUENCY_CHANNELTYPEUID, "Realtime frequency", "Number")
456 when(provider.getChannelType(eq(LAST_QUERY_STATE_CHANNELTYPEUID), any())).thenReturn(
457 new StateChannelTypeBuilderImpl(LAST_QUERY_STATE_CHANNELTYPEUID, "The last query", "String")
459 when(provider.getChannelType(eq(LAST_RECEIVED_DATETIME_CHANNELTYPEUID), any())).thenReturn(
460 new StateChannelTypeBuilderImpl(LAST_RECEIVED_DATETIME_CHANNELTYPEUID, "Last Received", "DateTime")
462 this.addChannelTypeProvider(provider);
463 this.addChannelTypeProvider(new WundergroundUpdateReceiverUnknownChannelTypeProvider());
467 class TestChannelTypeRegistry extends AbstractTestChannelTypeRegistry {
469 TestChannelTypeRegistry() {
470 super(mock(ChannelTypeProvider.class));
471 when(provider.getChannelType(eq(LAST_QUERY_TRIGGER_CHANNELTYPEUID), any())).thenReturn(
472 new TriggerChannelTypeBuilderImpl(LAST_QUERY_TRIGGER_CHANNELTYPEUID, "The last query").build());
476 class UpdatingChannelTypeRegistry extends AbstractTestChannelTypeRegistry {
478 UpdatingChannelTypeRegistry() {
479 super(mock(ChannelTypeProvider.class));
480 when(provider.getChannelType(eq(LAST_QUERY_TRIGGER_CHANNELTYPEUID), any()))
481 .thenReturn(new StateChannelTypeBuilderImpl(LAST_QUERY_TRIGGER_CHANNELTYPEUID, "The last query",
483 .thenReturn(new StateChannelTypeBuilderImpl(LAST_QUERY_TRIGGER_CHANNELTYPEUID, "The last query",
485 .thenReturn(new TriggerChannelTypeBuilderImpl(LAST_QUERY_TRIGGER_CHANNELTYPEUID, "The last query")