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.modbus.tests;
15 import static org.hamcrest.CoreMatchers.equalTo;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.hamcrest.core.Is.is;
18 import static org.junit.jupiter.api.Assertions.assertNotNull;
19 import static org.mockito.ArgumentMatchers.*;
20 import static org.mockito.Mockito.*;
21 import static org.mockito.hamcrest.MockitoHamcrest.argThat;
23 import java.lang.reflect.Field;
24 import java.util.concurrent.atomic.AtomicReference;
26 import org.hamcrest.Description;
27 import org.hamcrest.TypeSafeMatcher;
28 import org.junit.jupiter.api.AfterEach;
29 import org.junit.jupiter.api.BeforeEach;
30 import org.junit.jupiter.api.Test;
31 import org.mockito.ArgumentCaptor;
32 import org.mockito.Mock;
33 import org.mockito.Mockito;
34 import org.openhab.binding.modbus.handler.ModbusPollerThingHandler;
35 import org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal;
36 import org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler;
37 import org.openhab.core.config.core.Configuration;
38 import org.openhab.core.io.transport.modbus.AsyncModbusFailure;
39 import org.openhab.core.io.transport.modbus.AsyncModbusReadResult;
40 import org.openhab.core.io.transport.modbus.BitArray;
41 import org.openhab.core.io.transport.modbus.ModbusConstants;
42 import org.openhab.core.io.transport.modbus.ModbusFailureCallback;
43 import org.openhab.core.io.transport.modbus.ModbusReadCallback;
44 import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode;
45 import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint;
46 import org.openhab.core.io.transport.modbus.ModbusRegisterArray;
47 import org.openhab.core.io.transport.modbus.PollTask;
48 import org.openhab.core.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
49 import org.openhab.core.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint;
50 import org.openhab.core.thing.Bridge;
51 import org.openhab.core.thing.Thing;
52 import org.openhab.core.thing.ThingStatus;
53 import org.openhab.core.thing.ThingStatusDetail;
54 import org.openhab.core.thing.ThingStatusInfo;
55 import org.openhab.core.thing.ThingUID;
56 import org.openhab.core.thing.binding.ThingHandlerCallback;
57 import org.openhab.core.thing.binding.builder.BridgeBuilder;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
62 * @author Sami Salonen - Initial contribution
64 public class ModbusPollerThingHandlerTest extends AbstractModbusOSGiTest {
66 private static final String HOST = "thisishost";
67 private static final int PORT = 44;
69 private final Logger logger = LoggerFactory.getLogger(ModbusPollerThingHandlerTest.class);
71 private Bridge endpoint;
72 private Bridge poller;
74 private @Mock ThingHandlerCallback thingCallback;
76 public static BridgeBuilder createTcpThingBuilder(String id) {
78 .create(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP,
79 new ThingUID(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP, id))
80 .withLabel("label for " + id);
83 public static BridgeBuilder createPollerThingBuilder(String id) {
85 .create(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_POLLER,
86 new ThingUID(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_POLLER, id))
87 .withLabel("label for " + id);
91 * Verify that basic poller <-> endpoint interaction has taken place (on poller init)
93 private void verifyEndpointBasicInitInteraction() {
94 verify(mockedModbusManager).newModbusCommunicationInterface(any(), any());
97 public ModbusReadCallback getPollerCallback(ModbusPollerThingHandler handler)
98 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
99 Field callbackField = ModbusPollerThingHandler.class.getDeclaredField("callbackDelegator");
100 callbackField.setAccessible(true);
101 return (ModbusReadCallback) callbackField.get(handler);
104 public ModbusFailureCallback<ModbusReadRequestBlueprint> getPollerFailureCallback(ModbusPollerThingHandler handler)
105 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
106 Field callbackField = ModbusPollerThingHandler.class.getDeclaredField("callbackDelegator");
107 callbackField.setAccessible(true);
108 return (ModbusFailureCallback<ModbusReadRequestBlueprint>) callbackField.get(handler);
112 * Before each test, setup TCP endpoint thing, configure mocked item registry
115 public void setUp() {
116 mockCommsToModbusManager();
117 Configuration tcpConfig = new Configuration();
118 tcpConfig.put("host", HOST);
119 tcpConfig.put("port", PORT);
120 tcpConfig.put("id", 9);
121 endpoint = createTcpThingBuilder("tcpendpoint").withConfiguration(tcpConfig).build();
124 assertThat(endpoint.getStatus(), is(equalTo(ThingStatus.ONLINE)));
128 public void tearDown() {
129 if (endpoint != null) {
130 thingProvider.remove(endpoint.getUID());
132 if (poller != null) {
133 thingProvider.remove(poller.getUID());
138 public void testInitializeNonPolling()
139 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
140 Configuration pollerConfig = new Configuration();
141 pollerConfig.put("refresh", 0L); // 0 -> non polling
142 pollerConfig.put("start", 5);
143 pollerConfig.put("length", 9);
144 pollerConfig.put("type", ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER);
145 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
148 logger.info("Poller created, registering to registry...");
150 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
151 logger.info("Poller registered");
153 verifyEndpointBasicInitInteraction();
154 // polling is _not_ setup
155 verifyNoMoreInteractions(mockedModbusManager);
158 private void testPollerLengthCheck(String type, int length, boolean expectedOnline) {
159 Configuration pollerConfig = new Configuration();
160 pollerConfig.put("refresh", 0L);
161 pollerConfig.put("start", 5);
162 pollerConfig.put("length", length);
163 pollerConfig.put("type", type);
164 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
168 assertThat(poller.getStatus(), is(equalTo(expectedOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE)));
169 if (!expectedOnline) {
170 assertThat(poller.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.CONFIGURATION_ERROR)));
173 verifyEndpointBasicInitInteraction();
174 verifyNoMoreInteractions(mockedModbusManager);
178 public void testPollerWithMaxRegisters()
179 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
180 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER,
181 ModbusConstants.MAX_REGISTERS_READ_COUNT, true);
185 public void testPollerLengthOutOfBoundsWithRegisters()
186 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
187 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER,
188 ModbusConstants.MAX_REGISTERS_READ_COUNT + 1, false);
192 public void testPollerWithMaxInputRegisters()
193 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
194 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_INPUT_REGISTER,
195 ModbusConstants.MAX_REGISTERS_READ_COUNT, true);
199 public void testPollerLengthOutOfBoundsWithInputRegisters()
200 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
201 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_INPUT_REGISTER,
202 ModbusConstants.MAX_REGISTERS_READ_COUNT + 1, false);
206 public void testPollerWithMaxCoils()
207 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
208 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_COIL, ModbusConstants.MAX_BITS_READ_COUNT, true);
212 public void testPollerLengthOutOfBoundsWithCoils()
213 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
214 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_COIL, ModbusConstants.MAX_BITS_READ_COUNT + 1,
219 public void testPollerWithMaxDiscreteInput()
220 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
221 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_DISCRETE_INPUT,
222 ModbusConstants.MAX_BITS_READ_COUNT, true);
226 public void testPollerLengthOutOfBoundsWithDiscreteInput()
227 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
228 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_DISCRETE_INPUT,
229 ModbusConstants.MAX_BITS_READ_COUNT + 1, false);
232 public void testPollingGeneric(String type, ModbusReadFunctionCode expectedFunctionCode)
233 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
234 PollTask pollTask = Mockito.mock(PollTask.class);
235 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
237 Configuration pollerConfig = new Configuration();
238 pollerConfig.put("refresh", 150L);
239 pollerConfig.put("start", 5);
240 pollerConfig.put("length", 13);
241 pollerConfig.put("type", type);
242 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
246 assertThat(poller.getStatusInfo().toString(), poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
248 verifyEndpointBasicInitInteraction();
249 verify(mockedModbusManager).newModbusCommunicationInterface(argThat(new TypeSafeMatcher<ModbusSlaveEndpoint>() {
252 public void describeTo(Description description) {
253 description.appendText("correct endpoint (");
257 protected boolean matchesSafely(ModbusSlaveEndpoint endpoint) {
258 return checkEndpoint(endpoint);
262 verify(comms).registerRegularPoll(argThat(new TypeSafeMatcher<ModbusReadRequestBlueprint>() {
265 public void describeTo(Description description) {
266 description.appendText("correct request");
270 protected boolean matchesSafely(ModbusReadRequestBlueprint request) {
271 return checkRequest(request, expectedFunctionCode);
273 }), eq(150l), eq(0L), notNull(), notNull());
274 verifyNoMoreInteractions(mockedModbusManager);
277 @SuppressWarnings("null")
278 private boolean checkEndpoint(ModbusSlaveEndpoint endpointParam) {
279 return endpointParam.equals(new ModbusTCPSlaveEndpoint(HOST, PORT, false));
282 private boolean checkRequest(ModbusReadRequestBlueprint request, ModbusReadFunctionCode functionCode) {
283 return request.getDataLength() == 13 && request.getFunctionCode() == functionCode
284 && request.getProtocolID() == 0 && request.getReference() == 5 && request.getUnitID() == 9;
288 public void testInitializePollingWithCoils()
289 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
290 testPollingGeneric("coil", ModbusReadFunctionCode.READ_COILS);
294 public void testInitializePollingWithDiscrete()
295 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
296 testPollingGeneric("discrete", ModbusReadFunctionCode.READ_INPUT_DISCRETES);
300 public void testInitializePollingWithInputRegisters()
301 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
302 testPollingGeneric("input", ModbusReadFunctionCode.READ_INPUT_REGISTERS);
306 public void testInitializePollingWithHoldingRegisters()
307 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
308 testPollingGeneric("holding", ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS);
312 public void testPollUnregistrationOnDispose()
313 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
314 PollTask pollTask = Mockito.mock(PollTask.class);
315 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
317 Configuration pollerConfig = new Configuration();
318 pollerConfig.put("refresh", 150L);
319 pollerConfig.put("start", 5);
320 pollerConfig.put("length", 13);
321 pollerConfig.put("type", "coil");
322 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
325 verifyEndpointBasicInitInteraction();
327 // verify registration
328 final AtomicReference<ModbusReadCallback> callbackRef = new AtomicReference<>();
329 verify(mockedModbusManager).newModbusCommunicationInterface(argThat(new TypeSafeMatcher<ModbusSlaveEndpoint>() {
332 public void describeTo(Description description) {
333 description.appendText("correct endpoint");
337 protected boolean matchesSafely(ModbusSlaveEndpoint endpoint) {
338 return checkEndpoint(endpoint);
341 verify(comms).registerRegularPoll(argThat(new TypeSafeMatcher<ModbusReadRequestBlueprint>() {
344 public void describeTo(Description description) {
348 protected boolean matchesSafely(ModbusReadRequestBlueprint request) {
349 return checkRequest(request, ModbusReadFunctionCode.READ_COILS);
351 }), eq(150l), eq(0L), argThat(new TypeSafeMatcher<ModbusReadCallback>() {
354 public void describeTo(Description description) {
358 protected boolean matchesSafely(ModbusReadCallback callback) {
359 callbackRef.set(callback);
363 verifyNoMoreInteractions(mockedModbusManager);
365 // reset call counts for easy assertions
366 reset(mockedModbusManager);
369 disposeThing(poller);
371 // 1) should first unregister poll task
372 verify(comms).unregisterRegularPoll(eq(pollTask));
374 verifyNoMoreInteractions(mockedModbusManager);
378 public void testInitializeWithOfflineBridge()
379 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
380 Configuration pollerConfig = new Configuration();
381 pollerConfig.put("refresh", 150L);
382 pollerConfig.put("start", 5);
383 pollerConfig.put("length", 13);
384 pollerConfig.put("type", "coil");
386 endpoint.setStatusInfo(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, ""));
387 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
390 verifyEndpointBasicInitInteraction();
392 assertThat(poller.getStatus(), is(equalTo(ThingStatus.OFFLINE)));
393 assertThat(poller.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.BRIDGE_OFFLINE)));
395 verifyNoMoreInteractions(mockedModbusManager);
399 public void testRegistersPassedToChildDataThings()
400 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
401 PollTask pollTask = Mockito.mock(PollTask.class);
402 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
404 Configuration pollerConfig = new Configuration();
405 pollerConfig.put("refresh", 150L);
406 pollerConfig.put("start", 5);
407 pollerConfig.put("length", 13);
408 pollerConfig.put("type", "coil");
409 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
412 verifyEndpointBasicInitInteraction();
414 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
416 ArgumentCaptor<ModbusReadCallback> callbackCapturer = ArgumentCaptor.forClass(ModbusReadCallback.class);
417 verify(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), callbackCapturer.capture(), notNull());
418 ModbusReadCallback readCallback = callbackCapturer.getValue();
420 assertNotNull(readCallback);
422 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
423 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
425 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
426 assertNotNull(thingHandler);
428 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
429 ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
431 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
433 // has one data child
434 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
435 readCallback.handle(result);
436 verify(child1).onReadResult(result);
437 verifyNoMoreInteractions(child1);
438 verifyNoMoreInteractions(child2);
442 // two children (one child initialized)
443 thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
444 readCallback.handle(result);
445 verify(child1).onReadResult(result);
446 verify(child2).onReadResult(result);
447 verifyNoMoreInteractions(child1);
448 verifyNoMoreInteractions(child2);
453 // one child disposed
454 thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
455 readCallback.handle(result);
456 verify(child2).onReadResult(result);
457 verifyNoMoreInteractions(child1);
458 verifyNoMoreInteractions(child2);
462 public void testBitsPassedToChildDataThings()
463 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
464 PollTask pollTask = Mockito.mock(PollTask.class);
465 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
467 Configuration pollerConfig = new Configuration();
468 pollerConfig.put("refresh", 150L);
469 pollerConfig.put("start", 5);
470 pollerConfig.put("length", 13);
471 pollerConfig.put("type", "coil");
472 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
475 verifyEndpointBasicInitInteraction();
477 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
479 ArgumentCaptor<ModbusReadCallback> callbackCapturer = ArgumentCaptor.forClass(ModbusReadCallback.class);
480 verify(comms).registerRegularPoll(any(), eq(150l), eq(0L), callbackCapturer.capture(), notNull());
481 ModbusReadCallback readCallback = callbackCapturer.getValue();
483 assertNotNull(readCallback);
485 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
486 BitArray bits = Mockito.mock(BitArray.class);
488 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
489 assertNotNull(thingHandler);
491 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
492 ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
494 AsyncModbusReadResult result = new AsyncModbusReadResult(request, bits);
496 // has one data child
497 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
498 readCallback.handle(result);
499 verify(child1).onReadResult(result);
500 verifyNoMoreInteractions(child1);
501 verifyNoMoreInteractions(child2);
505 // two children (one child initialized)
506 thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
507 readCallback.handle(result);
508 verify(child1).onReadResult(result);
509 verify(child2).onReadResult(result);
510 verifyNoMoreInteractions(child1);
511 verifyNoMoreInteractions(child2);
516 // one child disposed
517 thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
518 readCallback.handle(result);
519 verify(child2).onReadResult(result);
520 verifyNoMoreInteractions(child1);
521 verifyNoMoreInteractions(child2);
525 public void testErrorPassedToChildDataThings()
526 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
527 PollTask pollTask = Mockito.mock(PollTask.class);
528 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
530 Configuration pollerConfig = new Configuration();
531 pollerConfig.put("refresh", 150L);
532 pollerConfig.put("start", 5);
533 pollerConfig.put("length", 13);
534 pollerConfig.put("type", "coil");
535 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
538 verifyEndpointBasicInitInteraction();
540 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
542 final ArgumentCaptor<ModbusFailureCallback<ModbusReadRequestBlueprint>> callbackCapturer = ArgumentCaptor
543 .forClass((Class) ModbusFailureCallback.class);
544 verify(comms).registerRegularPoll(any(), eq(150l), eq(0L), notNull(), callbackCapturer.capture());
545 ModbusFailureCallback<ModbusReadRequestBlueprint> readCallback = callbackCapturer.getValue();
547 assertNotNull(readCallback);
549 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
550 Exception error = Mockito.mock(Exception.class);
552 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
553 assertNotNull(thingHandler);
555 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
556 ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
558 AsyncModbusFailure<ModbusReadRequestBlueprint> result = new AsyncModbusFailure<ModbusReadRequestBlueprint>(
561 // has one data child
562 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
563 readCallback.handle(result);
564 verify(child1).handleReadError(result);
565 verifyNoMoreInteractions(child1);
566 verifyNoMoreInteractions(child2);
570 // two children (one child initialized)
571 thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
572 readCallback.handle(result);
573 verify(child1).handleReadError(result);
574 verify(child2).handleReadError(result);
575 verifyNoMoreInteractions(child1);
576 verifyNoMoreInteractions(child2);
581 // one child disposed
582 thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
583 readCallback.handle(result);
584 verify(child2).handleReadError(result);
585 verifyNoMoreInteractions(child1);
586 verifyNoMoreInteractions(child2);
590 public void testRefresh()
591 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
592 Configuration pollerConfig = new Configuration();
593 pollerConfig.put("refresh", 0L);
594 pollerConfig.put("start", 5);
595 pollerConfig.put("length", 13);
596 pollerConfig.put("type", "coil");
597 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
600 verifyEndpointBasicInitInteraction();
602 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
604 verify(comms, never()).submitOneTimePoll(any(), any(), any());
605 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
606 assertNotNull(thingHandler);
607 thingHandler.refresh();
608 verify(comms).submitOneTimePoll(any(), any(), any());
612 * When there's no recently received data, refresh() will re-use that instead
614 * @throws IllegalArgumentException
615 * @throws IllegalAccessException
616 * @throws NoSuchFieldException
617 * @throws SecurityException
620 public void testRefreshWithPreviousData()
621 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
622 Configuration pollerConfig = new Configuration();
623 pollerConfig.put("refresh", 0L);
624 pollerConfig.put("start", 5);
625 pollerConfig.put("length", 13);
626 pollerConfig.put("type", "coil");
627 pollerConfig.put("cacheMillis", 10000L);
628 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
631 verifyEndpointBasicInitInteraction();
633 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
634 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
635 assertNotNull(thingHandler);
636 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
638 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
640 verify(comms, never()).submitOneTimePoll(any(), any(), any());
643 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
644 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
645 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
646 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
647 pollerReadCallback.handle(result);
649 // data child receives the data
650 verify(child1).onReadResult(result);
651 verifyNoMoreInteractions(child1);
655 // cache is still valid, we should not have real data poll this time
656 thingHandler.refresh();
657 verify(comms, never()).submitOneTimePoll(any(), any(), any());
659 // data child receives the cached data
660 verify(child1).onReadResult(result);
661 verifyNoMoreInteractions(child1);
665 * When there's no recently received data, refresh() will re-use that instead
667 * @throws IllegalArgumentException
668 * @throws IllegalAccessException
669 * @throws NoSuchFieldException
670 * @throws SecurityException
673 public void testRefreshWithPreviousDataCacheDisabled()
674 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
675 Configuration pollerConfig = new Configuration();
676 pollerConfig.put("refresh", 0L);
677 pollerConfig.put("start", 5);
678 pollerConfig.put("length", 13);
679 pollerConfig.put("type", "coil");
680 pollerConfig.put("cacheMillis", 0L);
681 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
684 verifyEndpointBasicInitInteraction();
686 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
687 assertNotNull(thingHandler);
688 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
689 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
691 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
693 verify(comms, never()).submitOneTimePoll(any(), any(), any());
696 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
697 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
698 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
699 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
701 pollerReadCallback.handle(result);
703 // data child receives the data
704 verify(child1).onReadResult(result);
705 verifyNoMoreInteractions(child1);
709 // caching disabled, should poll from manager
710 thingHandler.refresh();
711 verify(comms).submitOneTimePoll(any(), any(), any());
712 verifyNoMoreInteractions(mockedModbusManager);
714 // data child receives the cached data
715 verifyNoMoreInteractions(child1);
719 * Testing again caching, such that most recently received data is propagated to children
721 * @throws IllegalArgumentException
722 * @throws IllegalAccessException
723 * @throws NoSuchFieldException
724 * @throws SecurityException
725 * @throws InterruptedException
728 public void testRefreshWithPreviousData2() throws IllegalArgumentException, IllegalAccessException,
729 NoSuchFieldException, SecurityException, InterruptedException {
730 Configuration pollerConfig = new Configuration();
731 pollerConfig.put("refresh", 0L);
732 pollerConfig.put("start", 5);
733 pollerConfig.put("length", 13);
734 pollerConfig.put("type", "coil");
735 pollerConfig.put("cacheMillis", 10000L);
736 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
739 verifyEndpointBasicInitInteraction();
741 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
742 assertNotNull(thingHandler);
743 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
744 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
746 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
748 verify(comms, never()).submitOneTimePoll(any(), any(), any());
751 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
752 ModbusFailureCallback<ModbusReadRequestBlueprint> failureCallback = getPollerFailureCallback(thingHandler);
753 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
754 ModbusReadRequestBlueprint request2 = Mockito.mock(ModbusReadRequestBlueprint.class);
755 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
756 Exception error = Mockito.mock(Exception.class);
757 AsyncModbusReadResult registersResult = new AsyncModbusReadResult(request, registers);
758 AsyncModbusFailure<ModbusReadRequestBlueprint> errorResult = new AsyncModbusFailure<ModbusReadRequestBlueprint>(
761 pollerReadCallback.handle(registersResult);
763 // data child should receive the data
764 verify(child1).onReadResult(registersResult);
765 verifyNoMoreInteractions(child1);
768 // Sleep to have time between the data
772 failureCallback.handle(errorResult);
774 // data child should receive the error
775 verify(child1).handleReadError(errorResult);
776 verifyNoMoreInteractions(child1);
779 // call refresh, should return latest data (that is, error)
780 // cache is still valid, we should not have real data poll this time
781 thingHandler.refresh();
782 verify(comms, never()).submitOneTimePoll(any(), any(), any());
784 // data child receives the cached error
785 verify(child1).handleReadError(errorResult);
786 verifyNoMoreInteractions(child1);
790 public void testRefreshWithOldPreviousData() throws IllegalArgumentException, IllegalAccessException,
791 NoSuchFieldException, SecurityException, InterruptedException {
793 Configuration pollerConfig = new Configuration();
794 pollerConfig.put("refresh", 0L);
795 pollerConfig.put("start", 5);
796 pollerConfig.put("length", 13);
797 pollerConfig.put("type", "coil");
798 pollerConfig.put("cacheMillis", 10L);
799 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
802 verifyEndpointBasicInitInteraction();
804 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
805 assertNotNull(thingHandler);
806 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
807 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
809 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
811 verify(comms, never()).submitOneTimePoll(any(), any(), any());
814 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
815 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
816 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
817 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
819 pollerReadCallback.handle(result);
821 // data child should receive the data
822 verify(child1).onReadResult(result);
823 verifyNoMoreInteractions(child1);
826 // Sleep to ensure cache expiry
829 // call refresh. Since cache expired, will poll for more
830 verify(comms, never()).submitOneTimePoll(any(), any(), any());
831 thingHandler.refresh();
832 verify(comms).submitOneTimePoll(any(), any(), any());