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.core.Is.is;
17 import static org.hamcrest.core.IsIterableContaining.hasItems;
18 import static org.mockito.Mockito.any;
19 import static org.mockito.Mockito.eq;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.never;
22 import static org.mockito.Mockito.times;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.when;
25 import static org.mockito.MockitoAnnotations.openMocks;
26 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.DATEUTC_DATETIME_CHANNELTYPEUID;
27 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.HUMIDITY_GROUP;
28 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.LAST_QUERY_STATE_CHANNELTYPEUID;
29 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.LAST_QUERY_TRIGGER_CHANNELTYPEUID;
30 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.LAST_RECEIVED_DATETIME_CHANNELTYPEUID;
31 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.METADATA_GROUP;
32 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.POLLUTION_GROUP;
33 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.PRESSURE_GROUP;
34 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.RAIN_GROUP;
35 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.SUNLIGHT_GROUP;
36 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.TEMPERATURE_GROUP;
37 import static org.openhab.binding.wundergroundupdatereceiver.internal.WundergroundUpdateReceiverBindingConstants.WIND_GROUP;
39 import java.io.IOException;
40 import java.util.List;
43 import javax.servlet.ServletException;
44 import javax.servlet.http.HttpServletResponse;
46 import org.eclipse.jdt.annotation.NonNullByDefault;
47 import org.eclipse.jetty.http.HttpFields;
48 import org.eclipse.jetty.http.HttpURI;
49 import org.eclipse.jetty.http.HttpVersion;
50 import org.eclipse.jetty.http.MetaData;
51 import org.eclipse.jetty.server.HttpChannel;
52 import org.eclipse.jetty.server.Request;
53 import org.junit.jupiter.api.BeforeEach;
54 import org.junit.jupiter.api.Test;
55 import org.mockito.Answers;
56 import org.mockito.ArgumentCaptor;
57 import org.mockito.Mock;
58 import org.openhab.core.config.core.Configuration;
59 import org.openhab.core.library.types.DateTimeType;
60 import org.openhab.core.library.types.DecimalType;
61 import org.openhab.core.library.types.OnOffType;
62 import org.openhab.core.library.types.QuantityType;
63 import org.openhab.core.library.types.StringType;
64 import org.openhab.core.library.unit.ImperialUnits;
65 import org.openhab.core.library.unit.Units;
66 import org.openhab.core.thing.Channel;
67 import org.openhab.core.thing.ChannelUID;
68 import org.openhab.core.thing.ManagedThingProvider;
69 import org.openhab.core.thing.Thing;
70 import org.openhab.core.thing.ThingStatus;
71 import org.openhab.core.thing.ThingUID;
72 import org.openhab.core.thing.binding.ThingHandlerCallback;
73 import org.openhab.core.thing.binding.builder.ChannelBuilder;
74 import org.openhab.core.thing.binding.builder.ThingBuilder;
75 import org.openhab.core.thing.type.ChannelKind;
76 import org.openhab.core.thing.type.ChannelTypeBuilder;
77 import org.openhab.core.thing.type.ChannelTypeRegistry;
78 import org.osgi.service.http.HttpService;
79 import org.osgi.service.http.NamespaceException;
82 * @author Daniel Demus - Initial contribution
85 class WundergroundUpdateReceiverServletTest {
87 private static final String STATION_ID_1 = "abcd1234";
88 private static final String STATION_ID_2 = "1234abcd";
89 private static final String REQ_STATION_ID = "dfggger";
90 private static final ThingUID TEST_THING_UID = new ThingUID(
91 WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER, "test-receiver");
93 private @Mock HttpService httpService;
94 private @Mock ChannelTypeRegistry channelTypeRegistry;
95 private @Mock WundergroundUpdateReceiverDiscoveryService discoveryService;
96 private @Mock ManagedThingProvider managedThingProvider;
104 void theServletIsActiveAfterTheFirstHandlerIsAdded() throws ServletException, NamespaceException {
106 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
107 WundergroundUpdateReceiverHandler handler = mock(WundergroundUpdateReceiverHandler.class);
108 when(handler.getStationId()).thenReturn(STATION_ID_1);
111 sut.addHandler(handler);
114 verify(httpService).registerServlet(eq(WundergroundUpdateReceiverServlet.SERVLET_URL), eq(sut), any(), any());
115 assertThat(sut.isActive(), is(true));
119 void theServletIsInactiveAfterTheLastHandlerIsRemovedAndBackgroundDiscoveryIsDisabled()
120 throws ServletException, NamespaceException {
122 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
123 WundergroundUpdateReceiverHandler handler = mock(WundergroundUpdateReceiverHandler.class);
124 when(handler.getStationId()).thenReturn(STATION_ID_1);
125 when(discoveryService.isBackgroundDiscoveryEnabled()).thenReturn(false);
128 sut.addHandler(handler);
131 verify(httpService).registerServlet(eq(WundergroundUpdateReceiverServlet.SERVLET_URL), eq(sut), any(), any());
132 assertThat(sut.isActive(), is(true));
135 sut.removeHandler(handler.getStationId());
138 verify(httpService).unregister(WundergroundUpdateReceiverServlet.SERVLET_URL);
139 assertThat(sut.isActive(), is(false));
143 void theServletIsActiveAfterTheLastHandlerIsRemovedButBackgroundDiscoveryIsEnabled()
144 throws ServletException, NamespaceException {
146 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
147 WundergroundUpdateReceiverHandler handler = mock(WundergroundUpdateReceiverHandler.class);
148 when(handler.getStationId()).thenReturn(STATION_ID_1);
149 when(discoveryService.isBackgroundDiscoveryEnabled()).thenReturn(true);
152 sut.addHandler(handler);
155 verify(httpService).registerServlet(eq(WundergroundUpdateReceiverServlet.SERVLET_URL), eq(sut), any(), any());
156 assertThat(sut.isActive(), is(true));
159 sut.removeHandler(handler.getStationId());
162 verify(httpService, never()).unregister(WundergroundUpdateReceiverServlet.SERVLET_URL);
163 assertThat(sut.isActive(), is(true));
167 void onDisposeAllHandlersAreRemovedAndServletIsInactive() throws ServletException, NamespaceException {
169 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
170 WundergroundUpdateReceiverHandler handler1 = mock(WundergroundUpdateReceiverHandler.class);
171 when(handler1.getStationId()).thenReturn(STATION_ID_1);
172 WundergroundUpdateReceiverHandler handler2 = mock(WundergroundUpdateReceiverHandler.class);
173 when(handler2.getStationId()).thenReturn(STATION_ID_2);
176 sut.addHandler(handler1);
177 sut.addHandler(handler2);
180 verify(httpService).registerServlet(eq(WundergroundUpdateReceiverServlet.SERVLET_URL), eq(sut), any(), any());
181 assertThat(sut.isActive(), is(true));
187 verify(httpService, times(2)).unregister(WundergroundUpdateReceiverServlet.SERVLET_URL);
188 assertThat(sut.isActive(), is(false));
192 void OnDisposeAllHandlersAreRemovedAndServletIsInactiveEvenThoughBackgroundDiscoveryIsEnabled()
193 throws ServletException, NamespaceException {
195 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
196 WundergroundUpdateReceiverHandler handler1 = mock(WundergroundUpdateReceiverHandler.class);
197 when(handler1.getStationId()).thenReturn(STATION_ID_1);
198 WundergroundUpdateReceiverHandler handler2 = mock(WundergroundUpdateReceiverHandler.class);
199 when(handler2.getStationId()).thenReturn(STATION_ID_2);
200 when(discoveryService.isBackgroundDiscoveryEnabled()).thenReturn(true);
203 sut.addHandler(handler1);
204 sut.addHandler(handler2);
207 verify(httpService).registerServlet(eq(WundergroundUpdateReceiverServlet.SERVLET_URL), eq(sut), any(), any());
208 assertThat(sut.isActive(), is(true));
214 verify(httpService).unregister(WundergroundUpdateReceiverServlet.SERVLET_URL);
215 assertThat(sut.isActive(), is(false));
219 void changedStationIdPropagatesToHandlerKey() throws ServletException, NamespaceException {
221 Thing thing = mock(Thing.class);
222 when(thing.getUID()).thenReturn(TEST_THING_UID);
223 when(thing.getConfiguration()).thenReturn(new Configuration(
224 Map.of(WundergroundUpdateReceiverBindingConstants.REPRESENTATION_PROPERTY, STATION_ID_1)));
225 when(thing.getStatus()).thenReturn(ThingStatus.ONLINE);
226 when(this.channelTypeRegistry.getChannelType(LAST_RECEIVED_DATETIME_CHANNELTYPEUID))
227 .thenReturn(ChannelTypeBuilder.state(LAST_RECEIVED_DATETIME_CHANNELTYPEUID, "Label", "String").build());
228 when(this.channelTypeRegistry.getChannelType(DATEUTC_DATETIME_CHANNELTYPEUID))
229 .thenReturn(ChannelTypeBuilder.state(DATEUTC_DATETIME_CHANNELTYPEUID, "Label", "DateTime").build());
230 when(this.channelTypeRegistry.getChannelType(LAST_QUERY_STATE_CHANNELTYPEUID))
231 .thenReturn(ChannelTypeBuilder.state(LAST_QUERY_STATE_CHANNELTYPEUID, "Label", "String").build());
232 when(this.channelTypeRegistry.getChannelType(LAST_QUERY_TRIGGER_CHANNELTYPEUID))
233 .thenReturn(ChannelTypeBuilder.trigger(LAST_QUERY_TRIGGER_CHANNELTYPEUID, "Label").build());
234 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
235 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(thing, sut, discoveryService,
236 new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry, managedThingProvider);
237 ThingHandlerCallback mockCallback = mock(ThingHandlerCallback.class);
238 handler.setCallback(mockCallback);
241 handler.initialize();
244 verify(httpService).registerServlet(eq(WundergroundUpdateReceiverServlet.SERVLET_URL), eq(sut), any(), any());
245 assertThat(sut.isActive(), is(true));
246 assertThat(sut.getStationIds(), hasItems(STATION_ID_1));
249 handler.handleConfigurationUpdate(
250 Map.of(WundergroundUpdateReceiverBindingConstants.REPRESENTATION_PROPERTY, STATION_ID_2));
253 assertThat(sut.isActive(), is(true));
254 ArgumentCaptor<Thing> thingArg = ArgumentCaptor.forClass(Thing.class);
255 verify(mockCallback).configurationUpdated(thingArg.capture());
256 assertThat(thingArg.getValue().getConfiguration().getProperties()
257 .get(WundergroundUpdateReceiverBindingConstants.REPRESENTATION_PROPERTY), is(STATION_ID_2));
261 void aGetRequestIsCorrectlyParsed() throws IOException {
263 ThingUID testThingUID = new ThingUID(WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER,
265 final String queryString = "ID=dfggger&PASSWORD=XXXXXX&tempf=26.1&humidity=74&dewptf=18.9&windchillf=26.1&winddir=14&windspeedmph=1.34&windgustmph=2.46&rainin=0.00&dailyrainin=0.00&weeklyrainin=0.00&monthlyrainin=0.08&yearlyrainin=3.06&solarradiation=42.24&UV=1&indoortempf=69.3&indoorhumidity=32&baromin=30.39&AqNOX=21&lowbatt=1&dateutc=2021-02-07%2014:04:03&softwaretype=WH2600%20V2.2.8&action=updateraw&realtime=1&rtfreq=5";
266 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
267 List<Channel> channels = List.of(
269 .create(new ChannelUID(testThingUID, METADATA_GROUP,
270 WundergroundUpdateReceiverBindingConstants.DATEUTC), "String")
271 .withKind(ChannelKind.STATE).build(),
273 .create(new ChannelUID(testThingUID, METADATA_GROUP,
274 WundergroundUpdateReceiverBindingConstants.REALTIME_FREQUENCY), "Number")
275 .withKind(ChannelKind.STATE).build(),
277 .create(new ChannelUID(testThingUID, METADATA_GROUP,
278 WundergroundUpdateReceiverBindingConstants.LOW_BATTERY), "Switch")
279 .withKind(ChannelKind.STATE).build(),
281 .create(new ChannelUID(testThingUID, WIND_GROUP,
282 WundergroundUpdateReceiverBindingConstants.WIND_DIRECTION), "Number:Angle")
283 .withKind(ChannelKind.STATE).build(),
285 .create(new ChannelUID(testThingUID, WIND_GROUP,
286 WundergroundUpdateReceiverBindingConstants.WIND_SPEED), "Number:Speed")
287 .withKind(ChannelKind.STATE).build(),
289 .create(new ChannelUID(testThingUID, WIND_GROUP,
290 WundergroundUpdateReceiverBindingConstants.GUST_SPEED), "Number:Speed")
291 .withKind(ChannelKind.STATE).build(),
293 .create(new ChannelUID(testThingUID, TEMPERATURE_GROUP,
294 WundergroundUpdateReceiverBindingConstants.TEMPERATURE), "Number:Temperature")
295 .withKind(ChannelKind.STATE).build(),
297 .create(new ChannelUID(testThingUID, RAIN_GROUP,
298 WundergroundUpdateReceiverBindingConstants.RAIN_IN), "Number:Length")
299 .withKind(ChannelKind.STATE).build(),
301 .create(new ChannelUID(testThingUID, SUNLIGHT_GROUP,
302 WundergroundUpdateReceiverBindingConstants.SOLAR_RADIATION), "Number:Intensity")
303 .withKind(ChannelKind.STATE).build(),
305 .create(new ChannelUID(testThingUID, SUNLIGHT_GROUP,
306 WundergroundUpdateReceiverBindingConstants.UV), "Number")
307 .withKind(ChannelKind.STATE).build(),
309 .create(new ChannelUID(testThingUID, PRESSURE_GROUP,
310 WundergroundUpdateReceiverBindingConstants.BAROM_IN), "Number:Pressure")
311 .withKind(ChannelKind.STATE).build(),
313 .create(new ChannelUID(testThingUID, HUMIDITY_GROUP,
314 WundergroundUpdateReceiverBindingConstants.DEWPOINT), "Number:Temperature")
315 .withKind(ChannelKind.STATE).build(),
317 .create(new ChannelUID(testThingUID, HUMIDITY_GROUP,
318 WundergroundUpdateReceiverBindingConstants.HUMIDITY), "Number:Dimensionless")
319 .withKind(ChannelKind.STATE).build(),
321 .create(new ChannelUID(testThingUID, POLLUTION_GROUP,
322 WundergroundUpdateReceiverBindingConstants.AQ_NOX), "Number:Dimensionless")
323 .withKind(ChannelKind.STATE).build(),
325 .create(new ChannelUID(testThingUID, METADATA_GROUP,
326 WundergroundUpdateReceiverBindingConstants.LAST_QUERY_TRIGGER), "StringType")
327 .withKind(ChannelKind.TRIGGER).build());
329 Configuration config = new Configuration(Map.of("stationId", REQ_STATION_ID));
330 Thing testThing = ThingBuilder
331 .create(WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER, testThingUID)
332 .withChannels(channels).withConfiguration(config).build();
333 ThingHandlerCallback callback = mock(ThingHandlerCallback.class);
334 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(testThing, sut,
335 discoveryService, new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry,
336 managedThingProvider);
337 handler.setCallback(callback);
338 handler.initialize();
340 HttpChannel httpChannel = mock(HttpChannel.class);
341 MetaData.Request request = new MetaData.Request("GET",
342 new HttpURI("http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + queryString),
343 HttpVersion.HTTP_1_1, new HttpFields());
344 Request req = new Request(httpChannel, null);
345 req.setMetaData(request);
348 sut.doGet(req, mock(HttpServletResponse.class, Answers.RETURNS_MOCKS));
351 verify(callback).stateUpdated(
352 new ChannelUID(TEST_THING_UID, METADATA_GROUP, WundergroundUpdateReceiverBindingConstants.DATEUTC),
353 StringType.valueOf("2021-02-07 14:04:03"));
354 verify(callback).stateUpdated(
355 new ChannelUID(TEST_THING_UID, METADATA_GROUP, WundergroundUpdateReceiverBindingConstants.LOW_BATTERY),
357 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
358 WundergroundUpdateReceiverBindingConstants.REALTIME_FREQUENCY), new DecimalType(5));
359 verify(callback).stateUpdated(
360 new ChannelUID(TEST_THING_UID, WIND_GROUP, WundergroundUpdateReceiverBindingConstants.WIND_DIRECTION),
361 new QuantityType<>(14, Units.DEGREE_ANGLE));
362 verify(callback).stateUpdated(
363 new ChannelUID(TEST_THING_UID, WIND_GROUP, WundergroundUpdateReceiverBindingConstants.WIND_SPEED),
364 new QuantityType<>(1.34, ImperialUnits.MILES_PER_HOUR));
365 verify(callback).stateUpdated(
366 new ChannelUID(TEST_THING_UID, WIND_GROUP, WundergroundUpdateReceiverBindingConstants.GUST_SPEED),
367 new QuantityType<>(2.46, ImperialUnits.MILES_PER_HOUR));
368 verify(callback).stateUpdated(
369 new ChannelUID(TEST_THING_UID, TEMPERATURE_GROUP,
370 WundergroundUpdateReceiverBindingConstants.TEMPERATURE),
371 new QuantityType<>(26.1, ImperialUnits.FAHRENHEIT));
372 verify(callback).stateUpdated(
373 new ChannelUID(TEST_THING_UID, RAIN_GROUP, WundergroundUpdateReceiverBindingConstants.RAIN_IN),
374 new QuantityType<>(0, ImperialUnits.INCH));
375 verify(callback).stateUpdated(
376 new ChannelUID(TEST_THING_UID, SUNLIGHT_GROUP,
377 WundergroundUpdateReceiverBindingConstants.SOLAR_RADIATION),
378 new QuantityType<>(42.24, Units.IRRADIANCE));
379 verify(callback).stateUpdated(
380 new ChannelUID(TEST_THING_UID, SUNLIGHT_GROUP, WundergroundUpdateReceiverBindingConstants.UV),
382 verify(callback).stateUpdated(
383 new ChannelUID(TEST_THING_UID, PRESSURE_GROUP, WundergroundUpdateReceiverBindingConstants.BAROM_IN),
384 new QuantityType<>(30.39, ImperialUnits.INCH_OF_MERCURY));
385 verify(callback).stateUpdated(
386 new ChannelUID(TEST_THING_UID, HUMIDITY_GROUP, WundergroundUpdateReceiverBindingConstants.DEWPOINT),
387 new QuantityType<>(18.9, ImperialUnits.FAHRENHEIT));
388 verify(callback).stateUpdated(
389 new ChannelUID(TEST_THING_UID, HUMIDITY_GROUP, WundergroundUpdateReceiverBindingConstants.HUMIDITY),
390 new QuantityType<>(74, Units.PERCENT));
391 verify(callback).stateUpdated(
392 new ChannelUID(TEST_THING_UID, POLLUTION_GROUP, WundergroundUpdateReceiverBindingConstants.AQ_NOX),
393 new QuantityType<>(21, Units.PARTS_PER_BILLION));
394 verify(callback, never()).stateUpdated(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
395 WundergroundUpdateReceiverBindingConstants.SOFTWARE_TYPE), StringType.valueOf("WH2600 V2.2.8"));
396 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
397 WundergroundUpdateReceiverBindingConstants.LAST_QUERY_STATE), StringType.valueOf(queryString));
398 verify(callback).stateUpdated(eq(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
399 WundergroundUpdateReceiverBindingConstants.LAST_RECEIVED)), any(DateTimeType.class));
400 verify(callback).channelTriggered(testThing, new ChannelUID(TEST_THING_UID, METADATA_GROUP,
401 WundergroundUpdateReceiverBindingConstants.LAST_QUERY_TRIGGER), queryString);
405 void aGetRequestWithIndexedParametresAreCorrectlyParsed() throws IOException {
407 ThingUID testThingUID = new ThingUID(WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER,
409 final String queryString = "ID=dfggger&PASSWORD=XXXXXX&temp1f=26.1&humidity=74&temp2f=25.1&lowbatt=1&soilmoisture1=78&soilmoisture2=73&dateutc=2021-02-07%2014:04:03&softwaretype=WH2600%20V2.2.8&action=updateraw&realtime=1&rtfreq=5";
410 WundergroundUpdateReceiverServlet sut = new WundergroundUpdateReceiverServlet(httpService, discoveryService);
411 List<Channel> channels = List.of(
413 .create(new ChannelUID(testThingUID, METADATA_GROUP,
414 WundergroundUpdateReceiverBindingConstants.DATEUTC), "String")
415 .withKind(ChannelKind.STATE).build(),
417 .create(new ChannelUID(testThingUID, METADATA_GROUP,
418 WundergroundUpdateReceiverBindingConstants.REALTIME_FREQUENCY), "Number")
419 .withKind(ChannelKind.STATE).build(),
421 .create(new ChannelUID(testThingUID, METADATA_GROUP,
422 WundergroundUpdateReceiverBindingConstants.LOW_BATTERY), "Switch")
423 .withKind(ChannelKind.STATE).build(),
424 ChannelBuilder.create(new ChannelUID(testThingUID, TEMPERATURE_GROUP, "temp1f"), "Number:Temperature")
425 .withKind(ChannelKind.STATE).build(),
426 ChannelBuilder.create(new ChannelUID(testThingUID, TEMPERATURE_GROUP, "temp2f"), "Number:Temperature")
427 .withKind(ChannelKind.STATE).build(),
429 .create(new ChannelUID(testThingUID, HUMIDITY_GROUP, "soilmoisture1"), "Number:Dimensionless")
430 .withKind(ChannelKind.STATE).build(),
432 .create(new ChannelUID(testThingUID, HUMIDITY_GROUP, "soilmoisture2"), "Number:Dimensionless")
433 .withKind(ChannelKind.STATE).build(),
435 .create(new ChannelUID(testThingUID, HUMIDITY_GROUP,
436 WundergroundUpdateReceiverBindingConstants.HUMIDITY), "Number:Dimensionless")
437 .withKind(ChannelKind.STATE).build(),
439 .create(new ChannelUID(testThingUID, METADATA_GROUP,
440 WundergroundUpdateReceiverBindingConstants.LAST_QUERY_TRIGGER), "StringType")
441 .withKind(ChannelKind.TRIGGER).build());
443 Configuration config = new Configuration(Map.of("stationId", REQ_STATION_ID));
444 Thing testThing = ThingBuilder
445 .create(WundergroundUpdateReceiverBindingConstants.THING_TYPE_UPDATE_RECEIVER, testThingUID)
446 .withChannels(channels).withConfiguration(config).build();
447 ThingHandlerCallback callback = mock(ThingHandlerCallback.class);
448 WundergroundUpdateReceiverHandler handler = new WundergroundUpdateReceiverHandler(testThing, sut,
449 discoveryService, new WundergroundUpdateReceiverUnknownChannelTypeProvider(), channelTypeRegistry,
450 managedThingProvider);
451 handler.setCallback(callback);
452 handler.initialize();
454 HttpChannel httpChannel = mock(HttpChannel.class);
455 MetaData.Request request = new MetaData.Request("GET",
456 new HttpURI("http://localhost" + WundergroundUpdateReceiverServlet.SERVLET_URL + "?" + queryString),
457 HttpVersion.HTTP_1_1, new HttpFields());
458 Request req = new Request(httpChannel, null);
459 req.setMetaData(request);
462 sut.doGet(req, mock(HttpServletResponse.class, Answers.RETURNS_MOCKS));
465 verify(callback).stateUpdated(
466 new ChannelUID(TEST_THING_UID, METADATA_GROUP, WundergroundUpdateReceiverBindingConstants.DATEUTC),
467 StringType.valueOf("2021-02-07 14:04:03"));
468 verify(callback).stateUpdated(
469 new ChannelUID(TEST_THING_UID, METADATA_GROUP, WundergroundUpdateReceiverBindingConstants.LOW_BATTERY),
471 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
472 WundergroundUpdateReceiverBindingConstants.REALTIME_FREQUENCY), new DecimalType(5));
473 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, TEMPERATURE_GROUP, "temp1f"),
474 new QuantityType<>(26.1, ImperialUnits.FAHRENHEIT));
475 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, TEMPERATURE_GROUP, "temp2f"),
476 new QuantityType<>(25.1, ImperialUnits.FAHRENHEIT));
477 verify(callback).stateUpdated(
478 new ChannelUID(TEST_THING_UID, HUMIDITY_GROUP, WundergroundUpdateReceiverBindingConstants.HUMIDITY),
479 new QuantityType<>(74, Units.PERCENT));
480 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, HUMIDITY_GROUP, "soilmoisture1"),
481 new QuantityType<>(78, Units.PERCENT));
482 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, HUMIDITY_GROUP, "soilmoisture2"),
483 new QuantityType<>(73, Units.PERCENT));
484 verify(callback, never()).stateUpdated(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
485 WundergroundUpdateReceiverBindingConstants.SOFTWARE_TYPE), StringType.valueOf("WH2600 V2.2.8"));
486 verify(callback).stateUpdated(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
487 WundergroundUpdateReceiverBindingConstants.LAST_QUERY_STATE), StringType.valueOf(queryString));
488 verify(callback).stateUpdated(eq(new ChannelUID(TEST_THING_UID, METADATA_GROUP,
489 WundergroundUpdateReceiverBindingConstants.LAST_RECEIVED)), any(DateTimeType.class));
490 verify(callback).channelTriggered(testThing, new ChannelUID(TEST_THING_UID, METADATA_GROUP,
491 WundergroundUpdateReceiverBindingConstants.LAST_QUERY_TRIGGER), queryString);