2 * Copyright (c) 2010-2020 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.core.Is.is;
17 import static org.junit.Assert.*;
18 import static org.mockito.ArgumentMatchers.*;
19 import static org.mockito.Mockito.*;
20 import static org.mockito.hamcrest.MockitoHamcrest.argThat;
22 import java.lang.reflect.Field;
23 import java.util.concurrent.atomic.AtomicReference;
25 import org.openhab.core.config.core.Configuration;
26 import org.openhab.core.thing.Bridge;
27 import org.openhab.core.thing.Thing;
28 import org.openhab.core.thing.ThingStatus;
29 import org.openhab.core.thing.ThingStatusDetail;
30 import org.openhab.core.thing.ThingStatusInfo;
31 import org.openhab.core.thing.ThingUID;
32 import org.openhab.core.thing.binding.ThingHandlerCallback;
33 import org.openhab.core.thing.binding.builder.BridgeBuilder;
34 import org.hamcrest.Description;
35 import org.hamcrest.TypeSafeMatcher;
36 import org.junit.After;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.mockito.ArgumentCaptor;
41 import org.mockito.Mock;
42 import org.mockito.Mockito;
43 import org.mockito.junit.MockitoJUnitRunner;
44 import org.openhab.binding.modbus.handler.ModbusPollerThingHandler;
45 import org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal;
46 import org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler;
47 import org.openhab.io.transport.modbus.AsyncModbusFailure;
48 import org.openhab.io.transport.modbus.AsyncModbusReadResult;
49 import org.openhab.io.transport.modbus.BitArray;
50 import org.openhab.io.transport.modbus.ModbusConstants;
51 import org.openhab.io.transport.modbus.ModbusFailureCallback;
52 import org.openhab.io.transport.modbus.ModbusReadCallback;
53 import org.openhab.io.transport.modbus.ModbusReadFunctionCode;
54 import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
55 import org.openhab.io.transport.modbus.ModbusRegisterArray;
56 import org.openhab.io.transport.modbus.PollTask;
57 import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
58 import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
63 * @author Sami Salonen - Initial contribution
65 @RunWith(MockitoJUnitRunner.class)
66 public class ModbusPollerThingHandlerTest extends AbstractModbusOSGiTest {
68 private static final String HOST = "thisishost";
69 private static final int PORT = 44;
71 private final Logger logger = LoggerFactory.getLogger(ModbusPollerThingHandlerTest.class);
73 private Bridge endpoint;
74 private Bridge poller;
77 private ThingHandlerCallback thingCallback;
79 public static BridgeBuilder createTcpThingBuilder(String id) {
81 .create(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP,
82 new ThingUID(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP, id))
83 .withLabel("label for " + id);
86 public static BridgeBuilder createPollerThingBuilder(String id) {
88 .create(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_POLLER,
89 new ThingUID(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_POLLER, id))
90 .withLabel("label for " + id);
94 * Verify that basic poller <-> endpoint interaction has taken place (on poller init)
96 private void verifyEndpointBasicInitInteraction() {
97 verify(mockedModbusManager).newModbusCommunicationInterface(any(), any());
100 public ModbusReadCallback getPollerCallback(ModbusPollerThingHandler handler)
101 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
102 Field callbackField = ModbusPollerThingHandler.class.getDeclaredField("callbackDelegator");
103 callbackField.setAccessible(true);
104 return (ModbusReadCallback) callbackField.get(handler);
107 public ModbusFailureCallback<ModbusReadRequestBlueprint> getPollerFailureCallback(ModbusPollerThingHandler handler)
108 throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
109 Field callbackField = ModbusPollerThingHandler.class.getDeclaredField("callbackDelegator");
110 callbackField.setAccessible(true);
111 return (ModbusFailureCallback<ModbusReadRequestBlueprint>) callbackField.get(handler);
115 * Before each test, setup TCP endpoint thing, configure mocked item registry
118 public void setUp() {
119 mockCommsToModbusManager();
120 Configuration tcpConfig = new Configuration();
121 tcpConfig.put("host", HOST);
122 tcpConfig.put("port", PORT);
123 tcpConfig.put("id", 9);
124 endpoint = createTcpThingBuilder("tcpendpoint").withConfiguration(tcpConfig).build();
127 assertThat(endpoint.getStatus(), is(equalTo(ThingStatus.ONLINE)));
131 public void tearDown() {
132 if (endpoint != null) {
133 thingProvider.remove(endpoint.getUID());
135 if (poller != null) {
136 thingProvider.remove(poller.getUID());
141 public void testInitializeNonPolling()
142 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
143 Configuration pollerConfig = new Configuration();
144 pollerConfig.put("refresh", 0L); // 0 -> non polling
145 pollerConfig.put("start", 5);
146 pollerConfig.put("length", 9);
147 pollerConfig.put("type", ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER);
148 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
151 logger.info("Poller created, registering to registry...");
153 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
154 logger.info("Poller registered");
156 verifyEndpointBasicInitInteraction();
157 // polling is _not_ setup
158 verifyNoMoreInteractions(mockedModbusManager);
161 private void testPollerLengthCheck(String type, int length, boolean expectedOnline) {
162 Configuration pollerConfig = new Configuration();
163 pollerConfig.put("refresh", 0L);
164 pollerConfig.put("start", 5);
165 pollerConfig.put("length", length);
166 pollerConfig.put("type", type);
167 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
171 assertThat(poller.getStatus(), is(equalTo(expectedOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE)));
172 if (!expectedOnline) {
173 assertThat(poller.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.CONFIGURATION_ERROR)));
176 verifyEndpointBasicInitInteraction();
177 verifyNoMoreInteractions(mockedModbusManager);
181 public void testPollerWithMaxRegisters()
182 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
183 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER,
184 ModbusConstants.MAX_REGISTERS_READ_COUNT, true);
188 public void testPollerLengthOutOfBoundsWithRegisters()
189 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
190 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER,
191 ModbusConstants.MAX_REGISTERS_READ_COUNT + 1, false);
195 public void testPollerWithMaxInputRegisters()
196 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
197 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_INPUT_REGISTER,
198 ModbusConstants.MAX_REGISTERS_READ_COUNT, true);
202 public void testPollerLengthOutOfBoundsWithInputRegisters()
203 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
204 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_INPUT_REGISTER,
205 ModbusConstants.MAX_REGISTERS_READ_COUNT + 1, false);
209 public void testPollerWithMaxCoils()
210 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
211 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_COIL, ModbusConstants.MAX_BITS_READ_COUNT, true);
215 public void testPollerLengthOutOfBoundsWithCoils()
216 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
217 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_COIL, ModbusConstants.MAX_BITS_READ_COUNT + 1,
222 public void testPollerWithMaxDiscreteInput()
223 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
224 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_DISCRETE_INPUT,
225 ModbusConstants.MAX_BITS_READ_COUNT, true);
229 public void testPollerLengthOutOfBoundsWithDiscreteInput()
230 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
231 testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_DISCRETE_INPUT,
232 ModbusConstants.MAX_BITS_READ_COUNT + 1, false);
235 public void testPollingGeneric(String type, ModbusReadFunctionCode expectedFunctionCode)
236 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
237 PollTask pollTask = Mockito.mock(PollTask.class);
238 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
240 Configuration pollerConfig = new Configuration();
241 pollerConfig.put("refresh", 150L);
242 pollerConfig.put("start", 5);
243 pollerConfig.put("length", 13);
244 pollerConfig.put("type", type);
245 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
249 assertThat(poller.getStatusInfo().toString(), poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
251 verifyEndpointBasicInitInteraction();
252 verify(mockedModbusManager).newModbusCommunicationInterface(argThat(new TypeSafeMatcher<ModbusSlaveEndpoint>() {
255 public void describeTo(Description description) {
256 description.appendText("correct endpoint (");
260 protected boolean matchesSafely(ModbusSlaveEndpoint endpoint) {
261 return checkEndpoint(endpoint);
265 verify(comms).registerRegularPoll(argThat(new TypeSafeMatcher<ModbusReadRequestBlueprint>() {
268 public void describeTo(Description description) {
269 description.appendText("correct request");
273 protected boolean matchesSafely(ModbusReadRequestBlueprint request) {
274 return checkRequest(request, expectedFunctionCode);
276 }), eq(150l), eq(0L), notNull(), notNull());
277 verifyNoMoreInteractions(mockedModbusManager);
280 @SuppressWarnings("null")
281 private boolean checkEndpoint(ModbusSlaveEndpoint endpointParam) {
282 return endpointParam.equals(new ModbusTCPSlaveEndpoint(HOST, PORT));
285 private boolean checkRequest(ModbusReadRequestBlueprint request, ModbusReadFunctionCode functionCode) {
286 return request.getDataLength() == 13 && request.getFunctionCode() == functionCode
287 && request.getProtocolID() == 0 && request.getReference() == 5 && request.getUnitID() == 9;
291 public void testInitializePollingWithCoils()
292 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
293 testPollingGeneric("coil", ModbusReadFunctionCode.READ_COILS);
297 public void testInitializePollingWithDiscrete()
298 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
299 testPollingGeneric("discrete", ModbusReadFunctionCode.READ_INPUT_DISCRETES);
303 public void testInitializePollingWithInputRegisters()
304 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
305 testPollingGeneric("input", ModbusReadFunctionCode.READ_INPUT_REGISTERS);
309 public void testInitializePollingWithHoldingRegisters()
310 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
311 testPollingGeneric("holding", ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS);
315 public void testPollUnregistrationOnDispose()
316 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
317 PollTask pollTask = Mockito.mock(PollTask.class);
318 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
320 Configuration pollerConfig = new Configuration();
321 pollerConfig.put("refresh", 150L);
322 pollerConfig.put("start", 5);
323 pollerConfig.put("length", 13);
324 pollerConfig.put("type", "coil");
325 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
328 verifyEndpointBasicInitInteraction();
330 // verify registration
331 final AtomicReference<ModbusReadCallback> callbackRef = new AtomicReference<>();
332 verify(mockedModbusManager).newModbusCommunicationInterface(argThat(new TypeSafeMatcher<ModbusSlaveEndpoint>() {
335 public void describeTo(Description description) {
336 description.appendText("correct endpoint");
340 protected boolean matchesSafely(ModbusSlaveEndpoint endpoint) {
341 return checkEndpoint(endpoint);
344 verify(comms).registerRegularPoll(argThat(new TypeSafeMatcher<ModbusReadRequestBlueprint>() {
347 public void describeTo(Description description) {
351 protected boolean matchesSafely(ModbusReadRequestBlueprint request) {
352 return checkRequest(request, ModbusReadFunctionCode.READ_COILS);
354 }), eq(150l), eq(0L), argThat(new TypeSafeMatcher<ModbusReadCallback>() {
357 public void describeTo(Description description) {
361 protected boolean matchesSafely(ModbusReadCallback callback) {
362 callbackRef.set(callback);
366 verifyNoMoreInteractions(mockedModbusManager);
368 // reset call counts for easy assertions
369 reset(mockedModbusManager);
372 disposeThing(poller);
374 // 1) should first unregister poll task
375 verify(comms).unregisterRegularPoll(eq(pollTask));
377 verifyNoMoreInteractions(mockedModbusManager);
381 public void testInitializeWithNoBridge()
382 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
383 Configuration pollerConfig = new Configuration();
384 pollerConfig.put("refresh", 150L);
385 pollerConfig.put("start", 5);
386 pollerConfig.put("length", 13);
387 pollerConfig.put("type", "coil");
388 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).build();
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 testInitializeWithOfflineBridge()
400 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
401 Configuration pollerConfig = new Configuration();
402 pollerConfig.put("refresh", 150L);
403 pollerConfig.put("start", 5);
404 pollerConfig.put("length", 13);
405 pollerConfig.put("type", "coil");
407 endpoint.setStatusInfo(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, ""));
408 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
411 verifyEndpointBasicInitInteraction();
413 assertThat(poller.getStatus(), is(equalTo(ThingStatus.OFFLINE)));
414 assertThat(poller.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.BRIDGE_OFFLINE)));
416 verifyNoMoreInteractions(mockedModbusManager);
420 public void testRegistersPassedToChildDataThings()
421 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
422 PollTask pollTask = Mockito.mock(PollTask.class);
423 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
425 Configuration pollerConfig = new Configuration();
426 pollerConfig.put("refresh", 150L);
427 pollerConfig.put("start", 5);
428 pollerConfig.put("length", 13);
429 pollerConfig.put("type", "coil");
430 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
433 verifyEndpointBasicInitInteraction();
435 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
437 ArgumentCaptor<ModbusReadCallback> callbackCapturer = ArgumentCaptor.forClass(ModbusReadCallback.class);
438 verify(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), callbackCapturer.capture(), notNull());
439 ModbusReadCallback readCallback = callbackCapturer.getValue();
441 assertNotNull(readCallback);
443 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
444 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
446 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
447 assertNotNull(thingHandler);
449 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
450 ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
452 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
454 // has one data child
455 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
456 readCallback.handle(result);
457 verify(child1).onReadResult(result);
458 verifyNoMoreInteractions(child1);
459 verifyNoMoreInteractions(child2);
463 // two children (one child initialized)
464 thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
465 readCallback.handle(result);
466 verify(child1).onReadResult(result);
467 verify(child2).onReadResult(result);
468 verifyNoMoreInteractions(child1);
469 verifyNoMoreInteractions(child2);
474 // one child disposed
475 thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
476 readCallback.handle(result);
477 verify(child2).onReadResult(result);
478 verifyNoMoreInteractions(child1);
479 verifyNoMoreInteractions(child2);
483 public void testBitsPassedToChildDataThings()
484 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
485 PollTask pollTask = Mockito.mock(PollTask.class);
486 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
488 Configuration pollerConfig = new Configuration();
489 pollerConfig.put("refresh", 150L);
490 pollerConfig.put("start", 5);
491 pollerConfig.put("length", 13);
492 pollerConfig.put("type", "coil");
493 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
496 verifyEndpointBasicInitInteraction();
498 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
500 ArgumentCaptor<ModbusReadCallback> callbackCapturer = ArgumentCaptor.forClass(ModbusReadCallback.class);
501 verify(comms).registerRegularPoll(any(), eq(150l), eq(0L), callbackCapturer.capture(), notNull());
502 ModbusReadCallback readCallback = callbackCapturer.getValue();
504 assertNotNull(readCallback);
506 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
507 BitArray bits = Mockito.mock(BitArray.class);
509 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
510 assertNotNull(thingHandler);
512 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
513 ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
515 AsyncModbusReadResult result = new AsyncModbusReadResult(request, bits);
517 // has one data child
518 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
519 readCallback.handle(result);
520 verify(child1).onReadResult(result);
521 verifyNoMoreInteractions(child1);
522 verifyNoMoreInteractions(child2);
526 // two children (one child initialized)
527 thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
528 readCallback.handle(result);
529 verify(child1).onReadResult(result);
530 verify(child2).onReadResult(result);
531 verifyNoMoreInteractions(child1);
532 verifyNoMoreInteractions(child2);
537 // one child disposed
538 thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
539 readCallback.handle(result);
540 verify(child2).onReadResult(result);
541 verifyNoMoreInteractions(child1);
542 verifyNoMoreInteractions(child2);
546 public void testErrorPassedToChildDataThings()
547 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
548 PollTask pollTask = Mockito.mock(PollTask.class);
549 doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
551 Configuration pollerConfig = new Configuration();
552 pollerConfig.put("refresh", 150L);
553 pollerConfig.put("start", 5);
554 pollerConfig.put("length", 13);
555 pollerConfig.put("type", "coil");
556 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
559 verifyEndpointBasicInitInteraction();
561 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
563 final ArgumentCaptor<ModbusFailureCallback<ModbusReadRequestBlueprint>> callbackCapturer = ArgumentCaptor
564 .forClass((Class) ModbusFailureCallback.class);
565 verify(comms).registerRegularPoll(any(), eq(150l), eq(0L), notNull(), callbackCapturer.capture());
566 ModbusFailureCallback<ModbusReadRequestBlueprint> readCallback = callbackCapturer.getValue();
568 assertNotNull(readCallback);
570 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
571 Exception error = Mockito.mock(Exception.class);
573 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
574 assertNotNull(thingHandler);
576 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
577 ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
579 AsyncModbusFailure<ModbusReadRequestBlueprint> result = new AsyncModbusFailure<ModbusReadRequestBlueprint>(
582 // has one data child
583 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
584 readCallback.handle(result);
585 verify(child1).handleReadError(result);
586 verifyNoMoreInteractions(child1);
587 verifyNoMoreInteractions(child2);
591 // two children (one child initialized)
592 thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
593 readCallback.handle(result);
594 verify(child1).handleReadError(result);
595 verify(child2).handleReadError(result);
596 verifyNoMoreInteractions(child1);
597 verifyNoMoreInteractions(child2);
602 // one child disposed
603 thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
604 readCallback.handle(result);
605 verify(child2).handleReadError(result);
606 verifyNoMoreInteractions(child1);
607 verifyNoMoreInteractions(child2);
611 public void testRefresh()
612 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
613 Configuration pollerConfig = new Configuration();
614 pollerConfig.put("refresh", 0L);
615 pollerConfig.put("start", 5);
616 pollerConfig.put("length", 13);
617 pollerConfig.put("type", "coil");
618 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
621 verifyEndpointBasicInitInteraction();
623 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
625 verify(comms, never()).submitOneTimePoll(any(), any(), any());
626 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
627 assertNotNull(thingHandler);
628 thingHandler.refresh();
629 verify(comms).submitOneTimePoll(any(), any(), any());
633 * When there's no recently received data, refresh() will re-use that instead
635 * @throws IllegalArgumentException
636 * @throws IllegalAccessException
637 * @throws NoSuchFieldException
638 * @throws SecurityException
641 public void testRefreshWithPreviousData()
642 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
643 Configuration pollerConfig = new Configuration();
644 pollerConfig.put("refresh", 0L);
645 pollerConfig.put("start", 5);
646 pollerConfig.put("length", 13);
647 pollerConfig.put("type", "coil");
648 pollerConfig.put("cacheMillis", 10000L);
649 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
652 verifyEndpointBasicInitInteraction();
654 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
655 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
656 assertNotNull(thingHandler);
657 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
659 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
661 verify(comms, never()).submitOneTimePoll(any(), any(), any());
664 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
665 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
666 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
667 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
668 pollerReadCallback.handle(result);
670 // data child receives the data
671 verify(child1).onReadResult(result);
672 verifyNoMoreInteractions(child1);
676 // cache is still valid, we should not have real data poll this time
677 thingHandler.refresh();
678 verify(comms, never()).submitOneTimePoll(any(), any(), any());
680 // data child receives the cached data
681 verify(child1).onReadResult(result);
682 verifyNoMoreInteractions(child1);
686 * When there's no recently received data, refresh() will re-use that instead
688 * @throws IllegalArgumentException
689 * @throws IllegalAccessException
690 * @throws NoSuchFieldException
691 * @throws SecurityException
694 public void testRefreshWithPreviousDataCacheDisabled()
695 throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
696 Configuration pollerConfig = new Configuration();
697 pollerConfig.put("refresh", 0L);
698 pollerConfig.put("start", 5);
699 pollerConfig.put("length", 13);
700 pollerConfig.put("type", "coil");
701 pollerConfig.put("cacheMillis", 0L);
702 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
705 verifyEndpointBasicInitInteraction();
707 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
708 assertNotNull(thingHandler);
709 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
710 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
712 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
714 verify(comms, never()).submitOneTimePoll(any(), any(), any());
717 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
718 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
719 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
720 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
722 pollerReadCallback.handle(result);
724 // data child receives the data
725 verify(child1).onReadResult(result);
726 verifyNoMoreInteractions(child1);
730 // caching disabled, should poll from manager
731 thingHandler.refresh();
732 verify(comms).submitOneTimePoll(any(), any(), any());
733 verifyNoMoreInteractions(mockedModbusManager);
735 // data child receives the cached data
736 verifyNoMoreInteractions(child1);
740 * Testing again caching, such that most recently received data is propagated to children
742 * @throws IllegalArgumentException
743 * @throws IllegalAccessException
744 * @throws NoSuchFieldException
745 * @throws SecurityException
746 * @throws InterruptedException
749 public void testRefreshWithPreviousData2() throws IllegalArgumentException, IllegalAccessException,
750 NoSuchFieldException, SecurityException, InterruptedException {
751 Configuration pollerConfig = new Configuration();
752 pollerConfig.put("refresh", 0L);
753 pollerConfig.put("start", 5);
754 pollerConfig.put("length", 13);
755 pollerConfig.put("type", "coil");
756 pollerConfig.put("cacheMillis", 10000L);
757 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
760 verifyEndpointBasicInitInteraction();
762 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
763 assertNotNull(thingHandler);
764 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
765 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
767 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
769 verify(comms, never()).submitOneTimePoll(any(), any(), any());
772 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
773 ModbusFailureCallback<ModbusReadRequestBlueprint> failureCallback = getPollerFailureCallback(thingHandler);
774 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
775 ModbusReadRequestBlueprint request2 = Mockito.mock(ModbusReadRequestBlueprint.class);
776 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
777 Exception error = Mockito.mock(Exception.class);
778 AsyncModbusReadResult registersResult = new AsyncModbusReadResult(request, registers);
779 AsyncModbusFailure<ModbusReadRequestBlueprint> errorResult = new AsyncModbusFailure<ModbusReadRequestBlueprint>(
782 pollerReadCallback.handle(registersResult);
784 // data child should receive the data
785 verify(child1).onReadResult(registersResult);
786 verifyNoMoreInteractions(child1);
789 // Sleep to have time between the data
793 failureCallback.handle(errorResult);
795 // data child should receive the error
796 verify(child1).handleReadError(errorResult);
797 verifyNoMoreInteractions(child1);
800 // call refresh, should return latest data (that is, error)
801 // cache is still valid, we should not have real data poll this time
802 thingHandler.refresh();
803 verify(comms, never()).submitOneTimePoll(any(), any(), any());
805 // data child receives the cached error
806 verify(child1).handleReadError(errorResult);
807 verifyNoMoreInteractions(child1);
811 public void testRefreshWithOldPreviousData() throws IllegalArgumentException, IllegalAccessException,
812 NoSuchFieldException, SecurityException, InterruptedException {
814 Configuration pollerConfig = new Configuration();
815 pollerConfig.put("refresh", 0L);
816 pollerConfig.put("start", 5);
817 pollerConfig.put("length", 13);
818 pollerConfig.put("type", "coil");
819 pollerConfig.put("cacheMillis", 10L);
820 poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
823 verifyEndpointBasicInitInteraction();
825 ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
826 assertNotNull(thingHandler);
827 ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
828 thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
830 assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
832 verify(comms, never()).submitOneTimePoll(any(), any(), any());
835 ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
836 ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
837 ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
838 AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
840 pollerReadCallback.handle(result);
842 // data child should receive the data
843 verify(child1).onReadResult(result);
844 verifyNoMoreInteractions(child1);
847 // Sleep to ensure cache expiry
850 // call refresh. Since cache expired, will poll for more
851 verify(comms, never()).submitOneTimePoll(any(), any(), any());
852 thingHandler.refresh();
853 verify(comms).submitOneTimePoll(any(), any(), any());