added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.modbus.tests</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab2-addons

View File

@@ -0,0 +1,74 @@
-include: ../itest-common.bndrun
Bundle-SymbolicName: ${project.artifactId}
Fragment-Host: org.openhab.binding.modbus
-runrequires: \
bnd.identity;id='org.openhab.binding.modbus.tests',\
bnd.identity;id='org.openhab.core.binding.xml',\
bnd.identity;id='org.openhab.core.thing.xml',\
bnd.identity;id='ch.qos.logback.core',\
bnd.identity;id='ch.qos.logback.classic'
# 1) We would like to use the "volatile" storage only, drop other storage
# 2) We use logback (see logback.xml), drop others logging implementation
# to avoid conflicts
-runblacklist: \
bnd.identity;id='org.openhab.core.storage.json',\
bnd.identity;id='org.openhab.core.storage.mapdb',\
bnd.identity;id='slf4j.simple',\
bnd.identity;id='org.apache.log4j'
-runproperties: \
logback.configurationFile=file:${.}/logback.xml
#
# done
#
-runbundles: \
javax.measure.unit-api;version='[1.0.0,1.0.1)',\
org.apache.commons.io;version='[2.2.0,2.2.1)',\
org.apache.commons.lang;version='[2.6.0,2.6.1)',\
org.apache.felix.configadmin;version='[1.9.8,1.9.9)',\
org.apache.felix.scr;version='[2.1.10,2.1.11)',\
org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\
org.osgi.service.event;version='[1.4.0,1.4.1)',\
osgi.enroute.hamcrest.wrapper;version='[1.3.0,1.3.1)',\
osgi.enroute.junit.wrapper;version='[4.12.0,4.12.1)',\
org.openhab.core;version='[2.5.0,2.5.1)',\
org.openhab.core.config.core;version='[2.5.0,2.5.1)',\
org.objenesis;version='[2.6.0,2.6.1)',\
org.openhab.core.config.discovery;version='[2.5.0,2.5.1)',\
org.openhab.core.io.console;version='[2.5.0,2.5.1)',\
org.openhab.core.thing;version='[2.5.0,2.5.1)',\
slf4j.api;version='[1.7.25,1.7.26)',\
com.google.gson;version='[2.8.2,2.8.3)',\
org.apache.servicemix.specs.activation-api-1.1;version='[2.9.0,2.9.1)',\
org.apache.servicemix.specs.jaxb-api-2.2;version='[2.9.0,2.9.1)',\
org.apache.servicemix.specs.stax-api-1.2;version='[2.9.0,2.9.1)',\
tec.uom.lib.uom-lib-common;version='[1.0.3,1.0.4)',\
tec.uom.se;version='[1.0.10,1.0.11)',\
org.apache.servicemix.bundles.jaxb-impl;version='[2.2.11,2.2.12)',\
net.bytebuddy.byte-buddy;version='[1.9.10,1.9.11)',\
net.bytebuddy.byte-buddy-agent;version='[1.9.10,1.9.11)',\
org.mockito.mockito-core;version='[3.1.0,3.1.1)',\
com.neuronrobotics.nrjavaserial;version='[3.15.0,3.15.1)',\
org.openhab.core.transform;version='[2.5.0,2.5.1)',\
org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
org.eclipse.jetty.http;version='[9.4.20,9.4.21)',\
org.eclipse.jetty.io;version='[9.4.20,9.4.21)',\
org.eclipse.jetty.security;version='[9.4.20,9.4.21)',\
org.eclipse.jetty.server;version='[9.4.20,9.4.21)',\
org.eclipse.jetty.servlet;version='[9.4.20,9.4.21)',\
org.eclipse.jetty.util;version='[9.4.20,9.4.21)',\
org.openhab.core.test;version='[2.5.0,2.5.1)',\
org.apache.servicemix.bundles.xstream;version='[1.4.7,1.4.8)',\
org.openhab.core.binding.xml;version='[2.5.0,2.5.1)',\
org.openhab.core.config.xml;version='[2.5.0,2.5.1)',\
org.openhab.core.thing.xml;version='[2.5.0,2.5.1)',\
ch.qos.logback.core;version='[1.2.3,1.2.4)',\
ch.qos.logback.classic;version='[1.2.3,1.2.4)',\
org.openhab.binding.modbus;version='[2.5.9,2.5.10)',\
org.openhab.binding.modbus.tests;version='[2.5.9,2.5.10)',\
org.openhab.io.transport.modbus;version='[2.5.9,2.5.10)',\
org.apache.commons.commons-pool2;version='[2.8.1,2.8.2)'

View File

@@ -0,0 +1,19 @@
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.openhab.binding.modbus" level="trace" />
<logger name="org.openhab.binding.modbus.tests" level="trace" />
<logger name="org.openhab.io.transport.modbus" level="trace" />
<logger name="net.wimpi.modbus" level="trace" />
<logger name="org.openhab.core.internal.items.ItemUpdater" level="trace" />
<logger name="org.openhab.core.internal.items.ItemStateConverterImpl" level="debug" />
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.itests</groupId>
<artifactId>org.openhab.addons.reactor.itests</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.modbus.tests</artifactId>
<name>openHAB Add-ons :: Integration Tests :: Modbus Binding Tests</name>
<dependencies>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.modbus</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.io.transport.modbus</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.itests</groupId>
<artifactId>org.openhab.addons.reactor.itests</artifactId>
<version>2.5.9-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.modbus.tests</artifactId>
<name>openHAB Add-ons :: Integration Tests :: Modbus Binding Tests</name>
<dependencies>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.modbus</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.io.transport.modbus</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,248 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.tests;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.events.Event;
import org.openhab.core.events.EventFilter;
import org.openhab.core.events.EventSubscriber;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemProvider;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.ManagedItemProvider;
import org.openhab.core.items.events.ItemStateEvent;
import org.openhab.core.library.CoreItemFactory;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ManagedThingProvider;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingProvider;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.openhab.core.thing.link.ItemChannelLink;
import org.openhab.core.thing.link.ItemChannelLinkProvider;
import org.openhab.core.thing.link.ManagedItemChannelLinkProvider;
import org.openhab.core.transform.TransformationService;
import org.openhab.core.types.State;
import org.openhab.core.test.java.JavaOSGiTest;
import org.junit.After;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.openhab.binding.modbus.internal.ModbusHandlerFactory;
import org.openhab.io.transport.modbus.ModbusCommunicationInterface;
import org.openhab.io.transport.modbus.ModbusManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Sami Salonen - Initial contribution
*/
@NonNullByDefault
public abstract class AbstractModbusOSGiTest extends JavaOSGiTest {
private static class StateSubscriber implements EventSubscriber {
private final Logger logger = LoggerFactory.getLogger(StateSubscriber.class);
public Map<String, List<State>> stateUpdates = new HashMap<>();
@Override
public Set<@NonNull String> getSubscribedEventTypes() {
return Collections.singleton(ItemStateEvent.TYPE);
}
@Override
public @Nullable EventFilter getEventFilter() {
return null;
}
@Override
public void receive(Event event) {
// Expecting only state updates in the tests
assertThat(event, is(instanceOf(ItemStateEvent.class)));
ItemStateEvent stateEvent = (ItemStateEvent) event;
logger.trace("Captured event: {} of type {}. Payload: {}", event,
stateEvent.getItemState().getClass().getSimpleName(), event.getPayload());
stateUpdates.computeIfAbsent(stateEvent.getItemName(), (item) -> new ArrayList<>())
.add(stateEvent.getItemState());
}
}
private final Logger logger = LoggerFactory.getLogger(AbstractModbusOSGiTest.class);
@Mock
protected @NonNullByDefault({}) ModbusManager mockedModbusManager;
protected @NonNullByDefault({}) ManagedThingProvider thingProvider;
protected @NonNullByDefault({}) ManagedItemProvider itemProvider;
protected @NonNullByDefault({}) ManagedItemChannelLinkProvider itemChannelLinkProvider;
protected @NonNullByDefault({}) ItemRegistry itemRegistry;
protected @NonNullByDefault({}) CoreItemFactory coreItemFactory;
private @NonNullByDefault({}) ModbusManager realModbusManager;
private Set<Item> addedItems = new HashSet<>();
private Set<Thing> addedThings = new HashSet<>();
private Set<ItemChannelLink> addedLinks = new HashSet<>();
private StateSubscriber stateSubscriber = new StateSubscriber();
@Mock
protected @NonNullByDefault({}) ModbusCommunicationInterface comms;
public AbstractModbusOSGiTest() {
super();
}
/**
* Before each test, configure mocked services
*/
@Before
public void setUpAbstractModbusOSGiTest() {
logger.debug("setUpAbstractModbusOSGiTest BEGIN");
registerVolatileStorageService();
registerService(mockedModbusManager);
registerService(stateSubscriber);
swapModbusManagerToMocked();
thingProvider = getService(ThingProvider.class, ManagedThingProvider.class);
assertThat("Could not get ManagedThingProvider", thingProvider, is(notNullValue()));
itemProvider = getService(ItemProvider.class, ManagedItemProvider.class);
assertThat("Could not get ManagedItemProvider", itemProvider, is(notNullValue()));
itemChannelLinkProvider = getService(ItemChannelLinkProvider.class, ManagedItemChannelLinkProvider.class);
assertThat("Could not get ManagedItemChannelLinkProvider", itemChannelLinkProvider, is(notNullValue()));
itemRegistry = getService(ItemRegistry.class);
assertThat("Could not get ItemRegistry", itemRegistry, is(notNullValue()));
coreItemFactory = new CoreItemFactory();
// Clean slate for all tests
reset(mockedModbusManager);
stateSubscriber.stateUpdates.clear();
logger.debug("setUpAbstractModbusOSGiTest END");
}
@After
public void tearDownAbstractModbusOSGiTest() {
logger.debug("tearDownAbstractModbusOSGiTest BEGIN");
swapModbusManagerToReal();
for (Item item : addedItems) {
assertNotNull(itemProvider.remove(item.getName()));
}
for (Thing thing : addedThings) {
disposeThing(thing);
}
for (ItemChannelLink link : addedLinks) {
logger.debug("Unlinking {} <-> {}", link.getItemName(), link.getLinkedUID());
assertNotNull(itemChannelLinkProvider.remove(link.getUID()));
}
logger.debug("tearDownAbstractModbusOSGiTest END");
}
protected void addThing(Thing thing) {
assertThat(addedThings.contains(thing), not(equalTo(true)));
ThingHandler mockHandler = thing.getHandler();
if (mockHandler != null) {
// If there is a handler attached to fresh thing, it should be mocked (this pattern is used with some tests)
assertThat(Mockito.mockingDetails(thing.getHandler()).isMock(), is(equalTo(true)));
}
thingProvider.add(thing);
waitForAssert(() -> assertThat(thing.getHandler(), notNullValue()));
assertThat(thing.getConfiguration(), is(notNullValue()));
addedThings.add(thing);
if (mockHandler != null) {
// Re-attach mock handler
ThingHandler realHandlerInitedByCore = thing.getHandler();
assertNotNull(realHandlerInitedByCore);
assertNotSame(realHandlerInitedByCore, mockHandler);
realHandlerInitedByCore.dispose();
thing.setHandler(mockHandler);
}
}
protected void disposeThing(Thing thing) {
thingProvider.remove(thing.getUID());
}
protected void addItem(Item item) {
assertThat(addedItems.contains(item), not(equalTo(true)));
itemProvider.add(item);
addedItems.add(item);
}
protected void linkItem(String itemName, ChannelUID channelUID) {
logger.debug("Linking {} <-> {}", itemName, channelUID);
ItemChannelLink link = new ItemChannelLink(itemName, channelUID);
assertThat(addedLinks.contains(link), not(equalTo(true)));
itemChannelLinkProvider.add(link);
addedLinks.add(link);
}
protected List<State> getStateUpdates(String itemName) {
return stateSubscriber.stateUpdates.get(itemName);
}
protected void mockTransformation(String name, TransformationService service) {
Dictionary<String, Object> params = new Hashtable<>();
params.put("smarthome.transform", name);
registerService(service, params);
}
protected void mockCommsToModbusManager() {
assert comms != null;
doReturn(comms).when(mockedModbusManager).newModbusCommunicationInterface(any(), any());
}
protected void swapModbusManagerToMocked() {
assertNull(realModbusManager);
realModbusManager = getService(ModbusManager.class);
assertThat("Could not get ModbusManager", realModbusManager, is(notNullValue()));
assertThat("Could not get ModbusManagerImpl", realModbusManager.getClass().getSimpleName(),
is(equalTo("ModbusManagerImpl")));
assertNotNull(realModbusManager);
ModbusHandlerFactory modbusHandlerFactory = getService(ThingHandlerFactory.class, ModbusHandlerFactory.class);
assertThat("Could not get ModbusHandlerFactory", modbusHandlerFactory, is(notNullValue()));
assertNotNull(modbusHandlerFactory);
modbusHandlerFactory.unsetModbusManager(realModbusManager);
modbusHandlerFactory.setModbusManager(mockedModbusManager);
}
protected void swapModbusManagerToReal() {
assertNotNull(realModbusManager);
ModbusHandlerFactory modbusHandlerFactory = getService(ThingHandlerFactory.class, ModbusHandlerFactory.class);
assertThat("Could not get ModbusHandlerFactory", modbusHandlerFactory, is(notNullValue()));
assertNotNull(modbusHandlerFactory);
modbusHandlerFactory.unsetModbusManager(mockedModbusManager);
modbusHandlerFactory.setModbusManager(realModbusManager);
}
}

View File

@@ -0,0 +1,855 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.tests;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import java.lang.reflect.Field;
import java.util.concurrent.atomic.AtomicReference;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandlerCallback;
import org.openhab.core.thing.binding.builder.BridgeBuilder;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.openhab.binding.modbus.handler.ModbusPollerThingHandler;
import org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal;
import org.openhab.binding.modbus.internal.handler.ModbusDataThingHandler;
import org.openhab.io.transport.modbus.AsyncModbusFailure;
import org.openhab.io.transport.modbus.AsyncModbusReadResult;
import org.openhab.io.transport.modbus.BitArray;
import org.openhab.io.transport.modbus.ModbusConstants;
import org.openhab.io.transport.modbus.ModbusFailureCallback;
import org.openhab.io.transport.modbus.ModbusReadCallback;
import org.openhab.io.transport.modbus.ModbusReadFunctionCode;
import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
import org.openhab.io.transport.modbus.PollTask;
import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Sami Salonen - Initial contribution
*/
@RunWith(MockitoJUnitRunner.class)
public class ModbusPollerThingHandlerTest extends AbstractModbusOSGiTest {
private static final String HOST = "thisishost";
private static final int PORT = 44;
private final Logger logger = LoggerFactory.getLogger(ModbusPollerThingHandlerTest.class);
private Bridge endpoint;
private Bridge poller;
@Mock
private ThingHandlerCallback thingCallback;
public static BridgeBuilder createTcpThingBuilder(String id) {
return BridgeBuilder
.create(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP,
new ThingUID(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP, id))
.withLabel("label for " + id);
}
public static BridgeBuilder createPollerThingBuilder(String id) {
return BridgeBuilder
.create(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_POLLER,
new ThingUID(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_POLLER, id))
.withLabel("label for " + id);
}
/**
* Verify that basic poller <-> endpoint interaction has taken place (on poller init)
*/
private void verifyEndpointBasicInitInteraction() {
verify(mockedModbusManager).newModbusCommunicationInterface(any(), any());
}
public ModbusReadCallback getPollerCallback(ModbusPollerThingHandler handler)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field callbackField = ModbusPollerThingHandler.class.getDeclaredField("callbackDelegator");
callbackField.setAccessible(true);
return (ModbusReadCallback) callbackField.get(handler);
}
public ModbusFailureCallback<ModbusReadRequestBlueprint> getPollerFailureCallback(ModbusPollerThingHandler handler)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field callbackField = ModbusPollerThingHandler.class.getDeclaredField("callbackDelegator");
callbackField.setAccessible(true);
return (ModbusFailureCallback<ModbusReadRequestBlueprint>) callbackField.get(handler);
}
/**
* Before each test, setup TCP endpoint thing, configure mocked item registry
*/
@Before
public void setUp() {
mockCommsToModbusManager();
Configuration tcpConfig = new Configuration();
tcpConfig.put("host", HOST);
tcpConfig.put("port", PORT);
tcpConfig.put("id", 9);
endpoint = createTcpThingBuilder("tcpendpoint").withConfiguration(tcpConfig).build();
addThing(endpoint);
assertThat(endpoint.getStatus(), is(equalTo(ThingStatus.ONLINE)));
}
@After
public void tearDown() {
if (endpoint != null) {
thingProvider.remove(endpoint.getUID());
}
if (poller != null) {
thingProvider.remove(poller.getUID());
}
}
@Test
public void testInitializeNonPolling()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 0L); // 0 -> non polling
pollerConfig.put("start", 5);
pollerConfig.put("length", 9);
pollerConfig.put("type", ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER);
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
logger.info("Poller created, registering to registry...");
addThing(poller);
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
logger.info("Poller registered");
verifyEndpointBasicInitInteraction();
// polling is _not_ setup
verifyNoMoreInteractions(mockedModbusManager);
}
private void testPollerLengthCheck(String type, int length, boolean expectedOnline) {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 0L);
pollerConfig.put("start", 5);
pollerConfig.put("length", length);
pollerConfig.put("type", type);
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
assertThat(poller.getStatus(), is(equalTo(expectedOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE)));
if (!expectedOnline) {
assertThat(poller.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.CONFIGURATION_ERROR)));
}
verifyEndpointBasicInitInteraction();
verifyNoMoreInteractions(mockedModbusManager);
}
@Test
public void testPollerWithMaxRegisters()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER,
ModbusConstants.MAX_REGISTERS_READ_COUNT, true);
}
@Test
public void testPollerLengthOutOfBoundsWithRegisters()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_HOLDING_REGISTER,
ModbusConstants.MAX_REGISTERS_READ_COUNT + 1, false);
}
@Test
public void testPollerWithMaxInputRegisters()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_INPUT_REGISTER,
ModbusConstants.MAX_REGISTERS_READ_COUNT, true);
}
@Test
public void testPollerLengthOutOfBoundsWithInputRegisters()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_INPUT_REGISTER,
ModbusConstants.MAX_REGISTERS_READ_COUNT + 1, false);
}
@Test
public void testPollerWithMaxCoils()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_COIL, ModbusConstants.MAX_BITS_READ_COUNT, true);
}
@Test
public void testPollerLengthOutOfBoundsWithCoils()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_COIL, ModbusConstants.MAX_BITS_READ_COUNT + 1,
false);
}
@Test
public void testPollerWithMaxDiscreteInput()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_DISCRETE_INPUT,
ModbusConstants.MAX_BITS_READ_COUNT, true);
}
@Test
public void testPollerLengthOutOfBoundsWithDiscreteInput()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollerLengthCheck(ModbusBindingConstantsInternal.READ_TYPE_DISCRETE_INPUT,
ModbusConstants.MAX_BITS_READ_COUNT + 1, false);
}
public void testPollingGeneric(String type, ModbusReadFunctionCode expectedFunctionCode)
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
PollTask pollTask = Mockito.mock(PollTask.class);
doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 150L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", type);
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
assertThat(poller.getStatusInfo().toString(), poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
verifyEndpointBasicInitInteraction();
verify(mockedModbusManager).newModbusCommunicationInterface(argThat(new TypeSafeMatcher<ModbusSlaveEndpoint>() {
@Override
public void describeTo(Description description) {
description.appendText("correct endpoint (");
}
@Override
protected boolean matchesSafely(ModbusSlaveEndpoint endpoint) {
return checkEndpoint(endpoint);
}
}), any());
verify(comms).registerRegularPoll(argThat(new TypeSafeMatcher<ModbusReadRequestBlueprint>() {
@Override
public void describeTo(Description description) {
description.appendText("correct request");
}
@Override
protected boolean matchesSafely(ModbusReadRequestBlueprint request) {
return checkRequest(request, expectedFunctionCode);
}
}), eq(150l), eq(0L), notNull(), notNull());
verifyNoMoreInteractions(mockedModbusManager);
}
@SuppressWarnings("null")
private boolean checkEndpoint(ModbusSlaveEndpoint endpointParam) {
return endpointParam.equals(new ModbusTCPSlaveEndpoint(HOST, PORT));
}
private boolean checkRequest(ModbusReadRequestBlueprint request, ModbusReadFunctionCode functionCode) {
return request.getDataLength() == 13 && request.getFunctionCode() == functionCode
&& request.getProtocolID() == 0 && request.getReference() == 5 && request.getUnitID() == 9;
}
@Test
public void testInitializePollingWithCoils()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollingGeneric("coil", ModbusReadFunctionCode.READ_COILS);
}
@Test
public void testInitializePollingWithDiscrete()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollingGeneric("discrete", ModbusReadFunctionCode.READ_INPUT_DISCRETES);
}
@Test
public void testInitializePollingWithInputRegisters()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollingGeneric("input", ModbusReadFunctionCode.READ_INPUT_REGISTERS);
}
@Test
public void testInitializePollingWithHoldingRegisters()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
testPollingGeneric("holding", ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS);
}
@Test
public void testPollUnregistrationOnDispose()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
PollTask pollTask = Mockito.mock(PollTask.class);
doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 150L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
// verify registration
final AtomicReference<ModbusReadCallback> callbackRef = new AtomicReference<>();
verify(mockedModbusManager).newModbusCommunicationInterface(argThat(new TypeSafeMatcher<ModbusSlaveEndpoint>() {
@Override
public void describeTo(Description description) {
description.appendText("correct endpoint");
}
@Override
protected boolean matchesSafely(ModbusSlaveEndpoint endpoint) {
return checkEndpoint(endpoint);
}
}), any());
verify(comms).registerRegularPoll(argThat(new TypeSafeMatcher<ModbusReadRequestBlueprint>() {
@Override
public void describeTo(Description description) {
}
@Override
protected boolean matchesSafely(ModbusReadRequestBlueprint request) {
return checkRequest(request, ModbusReadFunctionCode.READ_COILS);
}
}), eq(150l), eq(0L), argThat(new TypeSafeMatcher<ModbusReadCallback>() {
@Override
public void describeTo(Description description) {
}
@Override
protected boolean matchesSafely(ModbusReadCallback callback) {
callbackRef.set(callback);
return true;
}
}), notNull());
verifyNoMoreInteractions(mockedModbusManager);
// reset call counts for easy assertions
reset(mockedModbusManager);
// remove the thing
disposeThing(poller);
// 1) should first unregister poll task
verify(comms).unregisterRegularPoll(eq(pollTask));
verifyNoMoreInteractions(mockedModbusManager);
}
@Test
public void testInitializeWithNoBridge()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 150L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).build();
addThing(poller);
verifyEndpointBasicInitInteraction();
assertThat(poller.getStatus(), is(equalTo(ThingStatus.OFFLINE)));
assertThat(poller.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.BRIDGE_OFFLINE)));
verifyNoMoreInteractions(mockedModbusManager);
}
@Test
public void testInitializeWithOfflineBridge()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 150L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
endpoint.setStatusInfo(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, ""));
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
assertThat(poller.getStatus(), is(equalTo(ThingStatus.OFFLINE)));
assertThat(poller.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.BRIDGE_OFFLINE)));
verifyNoMoreInteractions(mockedModbusManager);
}
@Test
public void testRegistersPassedToChildDataThings()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
PollTask pollTask = Mockito.mock(PollTask.class);
doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 150L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
ArgumentCaptor<ModbusReadCallback> callbackCapturer = ArgumentCaptor.forClass(ModbusReadCallback.class);
verify(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), callbackCapturer.capture(), notNull());
ModbusReadCallback readCallback = callbackCapturer.getValue();
assertNotNull(readCallback);
ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
// has one data child
thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child1).onReadResult(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
reset(child1);
// two children (one child initialized)
thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child1).onReadResult(result);
verify(child2).onReadResult(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
reset(child1);
reset(child2);
// one child disposed
thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child2).onReadResult(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
}
@Test
public void testBitsPassedToChildDataThings()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
PollTask pollTask = Mockito.mock(PollTask.class);
doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 150L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
ArgumentCaptor<ModbusReadCallback> callbackCapturer = ArgumentCaptor.forClass(ModbusReadCallback.class);
verify(comms).registerRegularPoll(any(), eq(150l), eq(0L), callbackCapturer.capture(), notNull());
ModbusReadCallback readCallback = callbackCapturer.getValue();
assertNotNull(readCallback);
ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
BitArray bits = Mockito.mock(BitArray.class);
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
AsyncModbusReadResult result = new AsyncModbusReadResult(request, bits);
// has one data child
thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child1).onReadResult(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
reset(child1);
// two children (one child initialized)
thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child1).onReadResult(result);
verify(child2).onReadResult(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
reset(child1);
reset(child2);
// one child disposed
thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child2).onReadResult(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
}
@Test
public void testErrorPassedToChildDataThings()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
PollTask pollTask = Mockito.mock(PollTask.class);
doReturn(pollTask).when(comms).registerRegularPoll(notNull(), eq(150l), eq(0L), notNull(), notNull());
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 150L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
final ArgumentCaptor<ModbusFailureCallback<ModbusReadRequestBlueprint>> callbackCapturer = ArgumentCaptor
.forClass((Class) ModbusFailureCallback.class);
verify(comms).registerRegularPoll(any(), eq(150l), eq(0L), notNull(), callbackCapturer.capture());
ModbusFailureCallback<ModbusReadRequestBlueprint> readCallback = callbackCapturer.getValue();
assertNotNull(readCallback);
ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
Exception error = Mockito.mock(Exception.class);
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
ModbusDataThingHandler child2 = Mockito.mock(ModbusDataThingHandler.class);
AsyncModbusFailure<ModbusReadRequestBlueprint> result = new AsyncModbusFailure<ModbusReadRequestBlueprint>(
request, error);
// has one data child
thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child1).handleReadError(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
reset(child1);
// two children (one child initialized)
thingHandler.childHandlerInitialized(child2, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child1).handleReadError(result);
verify(child2).handleReadError(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
reset(child1);
reset(child2);
// one child disposed
thingHandler.childHandlerDisposed(child1, Mockito.mock(Thing.class));
readCallback.handle(result);
verify(child2).handleReadError(result);
verifyNoMoreInteractions(child1);
verifyNoMoreInteractions(child2);
}
@Test
public void testRefresh()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 0L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
verify(comms, never()).submitOneTimePoll(any(), any(), any());
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
thingHandler.refresh();
verify(comms).submitOneTimePoll(any(), any(), any());
}
/**
* When there's no recently received data, refresh() will re-use that instead
*
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws SecurityException
*/
@Test
public void testRefreshWithPreviousData()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 0L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
pollerConfig.put("cacheMillis", 10000L);
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
verify(comms, never()).submitOneTimePoll(any(), any(), any());
// data is received
ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
pollerReadCallback.handle(result);
// data child receives the data
verify(child1).onReadResult(result);
verifyNoMoreInteractions(child1);
reset(child1);
// call refresh
// cache is still valid, we should not have real data poll this time
thingHandler.refresh();
verify(comms, never()).submitOneTimePoll(any(), any(), any());
// data child receives the cached data
verify(child1).onReadResult(result);
verifyNoMoreInteractions(child1);
}
/**
* When there's no recently received data, refresh() will re-use that instead
*
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws SecurityException
*/
@Test
public void testRefreshWithPreviousDataCacheDisabled()
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 0L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
pollerConfig.put("cacheMillis", 0L);
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
verify(comms, never()).submitOneTimePoll(any(), any(), any());
// data is received
ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
pollerReadCallback.handle(result);
// data child receives the data
verify(child1).onReadResult(result);
verifyNoMoreInteractions(child1);
reset(child1);
// call refresh
// caching disabled, should poll from manager
thingHandler.refresh();
verify(comms).submitOneTimePoll(any(), any(), any());
verifyNoMoreInteractions(mockedModbusManager);
// data child receives the cached data
verifyNoMoreInteractions(child1);
}
/**
* Testing again caching, such that most recently received data is propagated to children
*
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws SecurityException
* @throws InterruptedException
*/
@Test
public void testRefreshWithPreviousData2() throws IllegalArgumentException, IllegalAccessException,
NoSuchFieldException, SecurityException, InterruptedException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 0L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
pollerConfig.put("cacheMillis", 10000L);
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
verify(comms, never()).submitOneTimePoll(any(), any(), any());
// data is received
ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
ModbusFailureCallback<ModbusReadRequestBlueprint> failureCallback = getPollerFailureCallback(thingHandler);
ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
ModbusReadRequestBlueprint request2 = Mockito.mock(ModbusReadRequestBlueprint.class);
ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
Exception error = Mockito.mock(Exception.class);
AsyncModbusReadResult registersResult = new AsyncModbusReadResult(request, registers);
AsyncModbusFailure<ModbusReadRequestBlueprint> errorResult = new AsyncModbusFailure<ModbusReadRequestBlueprint>(
request2, error);
pollerReadCallback.handle(registersResult);
// data child should receive the data
verify(child1).onReadResult(registersResult);
verifyNoMoreInteractions(child1);
reset(child1);
// Sleep to have time between the data
Thread.sleep(5L);
// error is received
failureCallback.handle(errorResult);
// data child should receive the error
verify(child1).handleReadError(errorResult);
verifyNoMoreInteractions(child1);
reset(child1);
// call refresh, should return latest data (that is, error)
// cache is still valid, we should not have real data poll this time
thingHandler.refresh();
verify(comms, never()).submitOneTimePoll(any(), any(), any());
// data child receives the cached error
verify(child1).handleReadError(errorResult);
verifyNoMoreInteractions(child1);
}
@Test
public void testRefreshWithOldPreviousData() throws IllegalArgumentException, IllegalAccessException,
NoSuchFieldException, SecurityException, InterruptedException {
Configuration pollerConfig = new Configuration();
pollerConfig.put("refresh", 0L);
pollerConfig.put("start", 5);
pollerConfig.put("length", 13);
pollerConfig.put("type", "coil");
pollerConfig.put("cacheMillis", 10L);
poller = createPollerThingBuilder("poller").withConfiguration(pollerConfig).withBridge(endpoint.getUID())
.build();
addThing(poller);
verifyEndpointBasicInitInteraction();
ModbusPollerThingHandler thingHandler = (ModbusPollerThingHandler) poller.getHandler();
assertNotNull(thingHandler);
ModbusDataThingHandler child1 = Mockito.mock(ModbusDataThingHandler.class);
thingHandler.childHandlerInitialized(child1, Mockito.mock(Thing.class));
assertThat(poller.getStatus(), is(equalTo(ThingStatus.ONLINE)));
verify(comms, never()).submitOneTimePoll(any(), any(), any());
// data is received
ModbusReadCallback pollerReadCallback = getPollerCallback(thingHandler);
ModbusReadRequestBlueprint request = Mockito.mock(ModbusReadRequestBlueprint.class);
ModbusRegisterArray registers = Mockito.mock(ModbusRegisterArray.class);
AsyncModbusReadResult result = new AsyncModbusReadResult(request, registers);
pollerReadCallback.handle(result);
// data child should receive the data
verify(child1).onReadResult(result);
verifyNoMoreInteractions(child1);
reset(child1);
// Sleep to ensure cache expiry
Thread.sleep(15L);
// call refresh. Since cache expired, will poll for more
verify(comms, never()).submitOneTimePoll(any(), any(), any());
thingHandler.refresh();
verify(comms).submitOneTimePoll(any(), any(), any());
}
}

View File

@@ -0,0 +1,185 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.tests;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Objects;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.builder.BridgeBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.openhab.binding.modbus.handler.EndpointNotInitializedException;
import org.openhab.binding.modbus.internal.ModbusBindingConstantsInternal;
import org.openhab.binding.modbus.internal.handler.ModbusTcpThingHandler;
import org.openhab.io.transport.modbus.endpoint.EndpointPoolConfiguration;
import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
import org.openhab.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint;
/**
* @author Sami Salonen - Initial contribution
*/
@RunWith(MockitoJUnitRunner.class)
public class ModbusTcpThingHandlerTest extends AbstractModbusOSGiTest {
private static BridgeBuilder createTcpThingBuilder(String id) {
return BridgeBuilder.create(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP,
new ThingUID(ModbusBindingConstantsInternal.THING_TYPE_MODBUS_TCP, id));
}
@Test
public void testInitializeAndSlaveEndpoint() throws EndpointNotInitializedException {
Configuration thingConfig = new Configuration();
thingConfig.put("host", "thisishost");
thingConfig.put("port", 44);
thingConfig.put("id", 9);
thingConfig.put("timeBetweenTransactionsMillis", 1);
thingConfig.put("timeBetweenReconnectMillis", 2);
thingConfig.put("connectMaxTries", 3);
thingConfig.put("reconnectAfterMillis", 4);
thingConfig.put("connectTimeoutMillis", 5);
EndpointPoolConfiguration expectedPoolConfiguration = new EndpointPoolConfiguration();
expectedPoolConfiguration.setConnectMaxTries(3);
expectedPoolConfiguration.setConnectTimeoutMillis(5);
expectedPoolConfiguration.setInterConnectDelayMillis(2);
expectedPoolConfiguration.setInterTransactionDelayMillis(1);
expectedPoolConfiguration.setReconnectAfterMillis(4);
Bridge thing = createTcpThingBuilder("tcpendpoint").withConfiguration(thingConfig).build();
addThing(thing);
assertThat(thing.getStatus(), is(equalTo(ThingStatus.ONLINE)));
ModbusTcpThingHandler thingHandler = (ModbusTcpThingHandler) thing.getHandler();
assertNotNull(thingHandler);
ModbusSlaveEndpoint slaveEndpoint = thingHandler.getEndpoint();
assertThat(slaveEndpoint, is(equalTo(new ModbusTCPSlaveEndpoint("thisishost", 44))));
assertThat(thingHandler.getSlaveId(), is(9));
InOrder orderedVerify = Mockito.inOrder(mockedModbusManager);
ModbusSlaveEndpoint endpoint = thingHandler.getEndpoint();
Objects.requireNonNull(endpoint);
orderedVerify.verify(mockedModbusManager).newModbusCommunicationInterface(endpoint, expectedPoolConfiguration);
}
@Test
public void testTwoDifferentEndpointWithDifferentParameters() {
// thing1
{
Configuration thingConfig = new Configuration();
thingConfig.put("host", "thisishost");
thingConfig.put("port", 44);
thingConfig.put("connectMaxTries", 1);
thingConfig.put("timeBetweenTransactionsMillis", 1);
final Bridge thing = createTcpThingBuilder("tcpendpoint").withConfiguration(thingConfig).build();
addThing(thing);
assertThat(thing.getStatus(), is(equalTo(ThingStatus.ONLINE)));
ModbusTcpThingHandler thingHandler = (ModbusTcpThingHandler) thing.getHandler();
assertNotNull(thingHandler);
}
{
Configuration thingConfig = new Configuration();
thingConfig.put("host", "thisishost");
thingConfig.put("port", 45);
thingConfig.put("connectMaxTries", 1);
thingConfig.put("timeBetweenTransactionsMillis", 100);
final Bridge thing = createTcpThingBuilder("tcpendpoint2").withConfiguration(thingConfig).build();
addThing(thing);
// Different endpoint (port 45), so should be OK even though timeBetweenTransactionsMillis is different
assertThat(thing.getStatus(), is(equalTo(ThingStatus.ONLINE)));
ModbusTcpThingHandler thingHandler = (ModbusTcpThingHandler) thing.getHandler();
assertNotNull(thingHandler);
}
}
@Test
public void testTwoIdenticalEndpointWithDifferentParameters() {
// Real implementation needed to validate this behaviour
swapModbusManagerToReal();
// thing1
{
Configuration thingConfig = new Configuration();
thingConfig.put("host", "thisishost");
thingConfig.put("port", 44);
thingConfig.put("connectMaxTries", 1);
thingConfig.put("timeBetweenTransactionsMillis", 1);
final Bridge thing = createTcpThingBuilder("tcpendpoint").withConfiguration(thingConfig).build();
addThing(thing);
assertThat(thing.getStatus(), is(equalTo(ThingStatus.ONLINE)));
ModbusTcpThingHandler thingHandler = (ModbusTcpThingHandler) thing.getHandler();
assertNotNull(thingHandler);
}
{
Configuration thingConfig = new Configuration();
thingConfig.put("host", "thisishost");
thingConfig.put("port", 44);
thingConfig.put("connectMaxTries", 1);
thingConfig.put("timeBetweenTransactionsMillis", 100);
final Bridge thing = createTcpThingBuilder("tcpendpoint2").withConfiguration(thingConfig).build();
addThing(thing);
assertThat(thing.getStatus(), is(equalTo(ThingStatus.OFFLINE)));
assertThat(thing.getStatusInfo().getStatusDetail(), is(equalTo(ThingStatusDetail.CONFIGURATION_ERROR)));
}
}
@Test
public void testTwoIdenticalEndpointWithSameParameters() {
// Real implementation needed to validate this behaviour
swapModbusManagerToReal();
// thing1
{
Configuration thingConfig = new Configuration();
thingConfig.put("host", "thisishost");
thingConfig.put("port", 44);
thingConfig.put("connectMaxTries", 1);
thingConfig.put("timeBetweenTransactionsMillis", 1);
final Bridge thing = createTcpThingBuilder("tcpendpoint").withConfiguration(thingConfig).build();
addThing(thing);
assertThat(thing.getStatus(), is(equalTo(ThingStatus.ONLINE)));
ModbusTcpThingHandler thingHandler = (ModbusTcpThingHandler) thing.getHandler();
assertNotNull(thingHandler);
}
{
Configuration thingConfig = new Configuration();
thingConfig.put("host", "thisishost");
thingConfig.put("port", 44);
thingConfig.put("connectMaxTries", 1);
thingConfig.put("timeBetweenTransactionsMillis", 1);
thingConfig.put("connectTimeoutMillis", 10000); // default
final Bridge thing = createTcpThingBuilder("tcpendpoint2").withConfiguration(thingConfig).build();
addThing(thing);
// Same endpoint and same parameters -> should not affect this thing
assertThat(thing.getStatus(), is(equalTo(ThingStatus.ONLINE)));
}
}
}