mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[mqtt] Revive disabled itests (#12431)
This fixes all the compilation/dependency issues in the MQTT itests so they can be reenabled again. The tests now create and use their own Moquette instance instead of the removed embedded MQTT broker. The moquette-broker JAR is also included in the test bundles as workaround for its missing OSGi bundle manifest headers. Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
parent
f310cf7ca0
commit
62c30d034f
2
.github/scripts/maven-build
vendored
2
.github/scripts/maven-build
vendored
@ -66,7 +66,7 @@ function addon_projects() {
|
|||||||
local addon="$1"
|
local addon="$1"
|
||||||
|
|
||||||
# include add-on projects
|
# include add-on projects
|
||||||
local projects=":$(find . -mindepth 2 -maxdepth 2 -type d -regextype egrep -regex "./(bundles|itests)/$addon(\..*)?$" | grep -Ev 'org.openhab.binding.mqtt.homeassistant.tests|org.openhab.binding.mqtt.homie.tests' | sort | sed -E 's#./(bundles|itests)/##g' | xargs | sed 's# #,:#g')"
|
local projects=":$(find . -mindepth 2 -maxdepth 2 -type d -regextype egrep -regex "./(bundles|itests)/$addon(\..*)?$" | sort | sed -E 's#./(bundles|itests)/##g' | xargs | sed 's# #,:#g')"
|
||||||
|
|
||||||
# include BOMs
|
# include BOMs
|
||||||
projects="$projects,:org.openhab.addons.bom.openhab-core-index,:org.openhab.addons.bom.runtime-index,:org.openhab.addons.bom.test-index"
|
projects="$projects,:org.openhab.addons.bom.openhab-core-index,:org.openhab.addons.bom.runtime-index,:org.openhab.addons.bom.test-index"
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
# Run all integration tests which are named xyzTest
|
# Run all integration tests which are named xyzTest
|
||||||
Test-Cases: ${classes;CONCRETE;PUBLIC;NAMED;*Test}
|
Test-Cases: ${classes;CONCRETE;PUBLIC;NAMED;*Test}
|
||||||
|
|
||||||
# A temporary inclusion until an R7 framework is available
|
|
||||||
Import-Package: org.osgi.framework.*;version="[1.8,2)",*
|
|
||||||
|
|
||||||
# We would like to use the slf4j-api and implementation provided by pax-logging
|
# We would like to use the slf4j-api and implementation provided by pax-logging
|
||||||
-runblacklist.itest-common: \
|
-runblacklist.itest-common: \
|
||||||
bnd.identity;id='slf4j.api'
|
bnd.identity;id='slf4j.api'
|
||||||
|
@ -3,92 +3,110 @@
|
|||||||
Bundle-SymbolicName: ${project.artifactId}
|
Bundle-SymbolicName: ${project.artifactId}
|
||||||
Fragment-Host: org.openhab.binding.mqtt.homeassistant
|
Fragment-Host: org.openhab.binding.mqtt.homeassistant
|
||||||
|
|
||||||
|
Import-Package: \
|
||||||
|
com.bugsnag.*;resolution:=optional,\
|
||||||
|
com.librato.metrics.reporter.*;resolution:=optional,\
|
||||||
|
*
|
||||||
|
|
||||||
|
-includeresource: \
|
||||||
|
moquette-broker-[0-9.]*.jar;lib:=true
|
||||||
|
|
||||||
-runrequires: \
|
-runrequires: \
|
||||||
bnd.identity;id='org.openhab.binding.mqtt.homeassistant.tests',\
|
bnd.identity;id='org.openhab.binding.mqtt.homeassistant.tests',\
|
||||||
bnd.identity;id='org.openhab.core.binding.xml',\
|
bnd.identity;id='org.openhab.core.binding.xml',\
|
||||||
bnd.identity;id='org.openhab.core.thing.xml',\
|
bnd.identity;id='org.openhab.core.thing.xml'
|
||||||
bnd.identity;id='org.openhab.io.mqttembeddedbroker'
|
|
||||||
|
|
||||||
# We would like to use the "volatile" storage only
|
# We would like to use the "volatile" storage only
|
||||||
-runblacklist: \
|
-runblacklist: \
|
||||||
bnd.identity;id='org.openhab.core.storage.json'
|
bnd.identity;id='org.openhab.core.storage.json'
|
||||||
|
|
||||||
-runvm: \
|
-runvm.mqtt: \
|
||||||
-Dio.netty.noUnsafe=true,\
|
-Dio.netty.noUnsafe=true,\
|
||||||
-Dmqttembeddedbroker.port=${mqttembeddedbroker.port}
|
-Dmqttbroker.port=${mqttbroker.port}
|
||||||
|
|
||||||
#
|
#
|
||||||
# done
|
# done
|
||||||
#
|
#
|
||||||
-runbundles: \
|
-runbundles: \
|
||||||
ch.qos.logback.core;version='[1.2.3,1.2.4)',\
|
|
||||||
com.google.gson;version='[2.8.2,2.8.3)',\
|
|
||||||
javax.measure.unit-api;version='[1.0.0,1.0.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.http.servlet-api;version='[1.1.2,1.1.3)',\
|
org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
|
||||||
org.apache.felix.scr;version='[2.1.10,2.1.11)',\
|
|
||||||
org.apache.servicemix.bundles.xstream;version='[1.4.7,1.4.8)',\
|
|
||||||
org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\
|
org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\
|
||||||
org.objenesis;version='[2.6.0,2.6.1)',\
|
|
||||||
org.osgi.service.event;version='[1.4.0,1.4.1)',\
|
org.osgi.service.event;version='[1.4.0,1.4.1)',\
|
||||||
slf4j.api;version='[1.7.25,1.7.26)',\
|
|
||||||
com.h2database.mvstore;version='[1.4.199,1.4.200)',\
|
|
||||||
io.netty.buffer;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.codec;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.codec-mqtt;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.common;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.handler;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.resolver;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.transport;version='[4.1.42,4.1.43)',\
|
|
||||||
tec.uom.lib.uom-lib-common;version='[1.0.3,1.0.4)',\
|
|
||||||
tec.uom.se;version='[1.0.10,1.0.11)',\
|
|
||||||
ch.qos.logback.classic;version='[1.2.3,1.2.4)',\
|
|
||||||
biz.aQute.tester.junit-platform;version='[5.1.2,5.1.3)',\
|
|
||||||
com.google.dagger;version='[2.20.0,2.20.1)',\
|
|
||||||
com.hivemq.client.mqtt;version='[1.1.2,1.1.3)',\
|
|
||||||
io.netty.codec-http;version='[4.1.34,4.1.35)',\
|
|
||||||
io.netty.transport-native-epoll;version='[4.1.34,4.1.35)',\
|
|
||||||
io.netty.transport-native-unix-common;version='[4.1.34,4.1.35)',\
|
|
||||||
io.reactivex.rxjava2.rxjava;version='[2.2.5,2.2.6)',\
|
|
||||||
junit-jupiter-api;version='[5.6.2,5.6.3)',\
|
|
||||||
junit-jupiter-engine;version='[5.6.2,5.6.3)',\
|
|
||||||
junit-platform-commons;version='[1.6.2,1.6.3)',\
|
|
||||||
junit-platform-engine;version='[1.6.2,1.6.3)',\
|
|
||||||
junit-platform-launcher;version='[1.6.2,1.6.3)',\
|
|
||||||
net.bytebuddy.byte-buddy;version='[1.10.13,1.10.14)',\
|
|
||||||
net.bytebuddy.byte-buddy-agent;version='[1.10.13,1.10.14)',\
|
|
||||||
org.apache.aries.javax.jax.rs-api;version='[1.0.0,1.0.1)',\
|
|
||||||
org.apache.commons.codec;version='[1.10.0,1.10.1)',\
|
|
||||||
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.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\
|
org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\
|
||||||
org.hamcrest;version='[2.2.0,2.2.1)',\
|
org.hamcrest;version='[2.2.0,2.2.1)',\
|
||||||
org.jctools.core;version='[2.1.2,2.1.3)',\
|
org.jctools.core;version='[2.1.2,2.1.3)',\
|
||||||
org.mockito.mockito-core;version='[3.4.6,3.4.7)',\
|
|
||||||
org.openhab.binding.mqtt;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.binding.mqtt.generic;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.binding.mqtt.homeassistant;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.binding.mqtt.homeassistant.tests;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.binding.xml;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.config.core;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.config.discovery;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.config.xml;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.io.console;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.io.transport.mqtt;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.test;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.thing;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.thing.xml;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.transform;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.io.mqttembeddedbroker;version='[3.0.0,3.0.1)',\
|
|
||||||
org.opentest4j;version='[1.2.0,1.2.1)',\
|
org.opentest4j;version='[1.2.0,1.2.1)',\
|
||||||
org.reactivestreams.reactive-streams;version='[1.0.2,1.0.3)',\
|
|
||||||
jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
|
jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
|
||||||
com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\
|
com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\
|
||||||
org.glassfish.hk2.osgi-resource-locator;version='[1.0.1,1.0.2)',\
|
org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\
|
||||||
org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)'
|
com.google.dagger;version='[2.27.0,2.27.1)',\
|
||||||
|
com.google.gson;version='[2.8.9,2.8.10)',\
|
||||||
|
com.hivemq.client.mqtt;version='[1.2.2,1.2.3)',\
|
||||||
|
io.netty.buffer;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.codec;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.codec-http;version='[4.1.59,4.1.60)',\
|
||||||
|
io.netty.codec-socks;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.common;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.handler;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.handler-proxy;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.resolver;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.tcnative-classes;version='[2.0.46,2.0.47)',\
|
||||||
|
io.netty.transport;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.transport-native-epoll;version='[4.1.59,4.1.60)',\
|
||||||
|
io.netty.transport-native-unix-common;version='[4.1.59,4.1.60)',\
|
||||||
|
io.reactivex.rxjava2.rxjava;version='[2.2.19,2.2.20)',\
|
||||||
|
jakarta.annotation-api;version='[2.0.0,2.0.1)',\
|
||||||
|
jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\
|
||||||
|
javax.measure.unit-api;version='[2.1.2,2.1.3)',\
|
||||||
|
junit-jupiter-api;version='[5.8.1,5.8.2)',\
|
||||||
|
junit-jupiter-engine;version='[5.8.1,5.8.2)',\
|
||||||
|
junit-platform-commons;version='[1.8.1,1.8.2)',\
|
||||||
|
junit-platform-engine;version='[1.8.1,1.8.2)',\
|
||||||
|
junit-platform-launcher;version='[1.8.1,1.8.2)',\
|
||||||
|
net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\
|
||||||
|
net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\
|
||||||
|
org.apache.aries.javax.jax.rs-api;version='[1.0.1,1.0.2)',\
|
||||||
|
org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\
|
||||||
|
org.apache.felix.scr;version='[2.1.30,2.1.31)',\
|
||||||
|
org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.server;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\
|
||||||
|
org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\
|
||||||
|
org.jsr-305;version='[3.0.2,3.0.3)',\
|
||||||
|
org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\
|
||||||
|
org.mockito.mockito-core;version='[4.1.0,4.1.1)',\
|
||||||
|
org.objenesis;version='[3.2.0,3.2.1)',\
|
||||||
|
org.openhab.binding.mqtt;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.binding.mqtt.generic;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.binding.mqtt.homeassistant;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.binding.mqtt.homeassistant.tests;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.binding.xml;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.config.core;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.config.discovery;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.config.xml;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.io.console;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.io.transport.mqtt;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.test;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.thing;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.thing.xml;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.transform;version='[3.3.0,3.3.1)',\
|
||||||
|
org.ops4j.pax.logging.pax-logging-api;version='[2.0.14,2.0.15)',\
|
||||||
|
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.util.function;version='[1.2.0,1.2.1)',\
|
||||||
|
org.osgi.util.promise;version='[1.2.0,1.2.1)',\
|
||||||
|
org.reactivestreams.reactive-streams;version='[1.0.3,1.0.4)',\
|
||||||
|
si-units;version='[2.1.0,2.1.1)',\
|
||||||
|
si.uom.si-quantity;version='[2.1.0,2.1.1)',\
|
||||||
|
tech.units.indriya;version='[2.1.2,2.1.3)',\
|
||||||
|
uom-lib-common;version='[2.1.0,2.1.1)',\
|
||||||
|
xstream;version='[1.4.19,1.4.20)',\
|
||||||
|
com.h2database.mvstore;version='[1.4.199,1.4.200)',\
|
||||||
|
com.zaxxer.HikariCP;version='[2.4.7,2.4.8)',\
|
||||||
|
io.dropwizard.metrics.core;version='[3.2.2,3.2.3)',\
|
||||||
|
io.netty.codec-mqtt;version='[4.1.72,4.1.73)',\
|
||||||
|
org.apache.commons.codec;version='[1.10.0,1.10.1)',\
|
||||||
|
biz.aQute.tester.junit-platform;version='[6.2.0,6.2.1)'
|
||||||
|
@ -7,13 +7,17 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.openhab.addons.itests</groupId>
|
<groupId>org.openhab.addons.itests</groupId>
|
||||||
<artifactId>org.openhab.addons.reactor.itests</artifactId>
|
<artifactId>org.openhab.addons.reactor.itests</artifactId>
|
||||||
<version>3.1.0-SNAPSHOT</version>
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>org.openhab.binding.mqtt.homeassistant.tests</artifactId>
|
<artifactId>org.openhab.binding.mqtt.homeassistant.tests</artifactId>
|
||||||
|
|
||||||
<name>openHAB Add-ons :: Integration Tests :: MQTT HomeAssistant Tests</name>
|
<name>openHAB Add-ons :: Integration Tests :: MQTT HomeAssistant Tests</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<mqttbroker.port>1883</mqttbroker.port>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openhab.addons.bundles</groupId>
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
@ -31,52 +35,43 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.j-n-k</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>moquette-broker</artifactId>
|
<artifactId>h2-mvstore</artifactId>
|
||||||
<version>0.13.0.OH2</version>
|
<version>1.4.199</version>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.moquette</groupId>
|
||||||
<artifactId>netty-common</artifactId>
|
<artifactId>moquette-broker</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>0.15</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-buffer</artifactId>
|
<artifactId>netty-buffer</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-transport</artifactId>
|
|
||||||
<version>${netty.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-codec</artifactId>
|
<artifactId>netty-codec</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>h2-mvstore</artifactId>
|
<artifactId>netty-codec-mqtt</artifactId>
|
||||||
<version>1.4.199</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-codec-mqtt</artifactId>
|
<artifactId>netty-common</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-handler</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-handler-proxy</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -86,7 +81,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-handler</artifactId>
|
<artifactId>netty-transport</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@ -98,14 +93,14 @@
|
|||||||
<artifactId>build-helper-maven-plugin</artifactId>
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>reserve-network-port</id>
|
<id>reserve-mqtt-broker-port</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>reserve-network-port</goal>
|
<goal>reserve-network-port</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<phase>process-resources</phase>
|
<phase>process-resources</phase>
|
||||||
<configuration>
|
<configuration>
|
||||||
<portNames>
|
<portNames>
|
||||||
<portName>mqttembeddedbroker.port</portName>
|
<portName>mqttbroker.port</portName>
|
||||||
</portNames>
|
</portNames>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 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.mqtt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT embedded broker constants
|
|
||||||
*
|
|
||||||
* @author David Graeff - Initial contribution
|
|
||||||
*/
|
|
||||||
public class Constants {
|
|
||||||
/**
|
|
||||||
* The broker connection client ID. You can request the embedded broker connection via the MqttService:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* MqttBrokerConnection c = mqttService.getBrokerConnection(Constants.CLIENTID);
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public static final String CLIENTID = "embedded-mqtt-broker";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The broker persistent identifier used for identifying configurations.
|
|
||||||
*/
|
|
||||||
public static final String PID = "org.openhab.core.mqttembeddedbroker";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The configuration key used for configuring the embedded broker port.
|
|
||||||
*/
|
|
||||||
public static final String PORT = "port";
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 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.mqtt;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Dictionary;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttService;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttServiceObserver;
|
|
||||||
import org.osgi.service.cm.Configuration;
|
|
||||||
import org.osgi.service.cm.ConfigurationAdmin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A full implementation test, that starts the embedded MQTT broker and publishes a homeassistant MQTT discovery device
|
|
||||||
* tree.
|
|
||||||
*
|
|
||||||
* @author David Graeff - Initial contribution
|
|
||||||
* @author Wouter Born - Support running MQTT itests in parallel by reconfiguring embedded broker port
|
|
||||||
*/
|
|
||||||
@NonNullByDefault
|
|
||||||
public class EmbeddedBrokerTools {
|
|
||||||
|
|
||||||
private static final int BROKER_PORT = Integer.getInteger("mqttembeddedbroker.port", 1883);
|
|
||||||
|
|
||||||
private final ConfigurationAdmin configurationAdmin;
|
|
||||||
private final MqttService mqttService;
|
|
||||||
|
|
||||||
public @Nullable MqttBrokerConnection embeddedConnection;
|
|
||||||
|
|
||||||
public EmbeddedBrokerTools(ConfigurationAdmin configurationAdmin, MqttService mqttService) {
|
|
||||||
this.configurationAdmin = configurationAdmin;
|
|
||||||
this.mqttService = mqttService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request the embedded broker connection from the {@link MqttService} and wait for a connection to be established.
|
|
||||||
*
|
|
||||||
* @throws InterruptedException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public MqttBrokerConnection waitForConnection() throws InterruptedException, IOException {
|
|
||||||
reconfigurePort();
|
|
||||||
|
|
||||||
embeddedConnection = mqttService.getBrokerConnection(Constants.CLIENTID);
|
|
||||||
if (embeddedConnection == null) {
|
|
||||||
Semaphore semaphore = new Semaphore(1);
|
|
||||||
semaphore.acquire();
|
|
||||||
MqttServiceObserver observer = new MqttServiceObserver() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void brokerAdded(String brokerID, MqttBrokerConnection broker) {
|
|
||||||
if (brokerID.equals(Constants.CLIENTID)) {
|
|
||||||
embeddedConnection = broker;
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void brokerRemoved(String brokerID, MqttBrokerConnection broker) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mqttService.addBrokersListener(observer);
|
|
||||||
assertTrue(semaphore.tryAcquire(5, TimeUnit.SECONDS), "Wait for embedded connection client failed");
|
|
||||||
}
|
|
||||||
MqttBrokerConnection embeddedConnection = this.embeddedConnection;
|
|
||||||
if (embeddedConnection == null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Semaphore semaphore = new Semaphore(1);
|
|
||||||
semaphore.acquire();
|
|
||||||
MqttConnectionObserver mqttConnectionObserver = (state, error) -> {
|
|
||||||
if (state == MqttConnectionState.CONNECTED) {
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
embeddedConnection.addConnectionObserver(mqttConnectionObserver);
|
|
||||||
if (embeddedConnection.connectionState() == MqttConnectionState.CONNECTED) {
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
assertTrue(semaphore.tryAcquire(5, TimeUnit.SECONDS), "Connection " + embeddedConnection.getClientId()
|
|
||||||
+ " failed. State: " + embeddedConnection.connectionState());
|
|
||||||
return embeddedConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reconfigurePort() throws IOException {
|
|
||||||
Configuration configuration = configurationAdmin.getConfiguration(Constants.PID, null);
|
|
||||||
|
|
||||||
Dictionary<String, Object> properties = configuration.getProperties();
|
|
||||||
if (properties == null) {
|
|
||||||
properties = new Hashtable<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer currentPort = (Integer) properties.get(Constants.PORT);
|
|
||||||
if (currentPort == null || currentPort.intValue() != BROKER_PORT) {
|
|
||||||
properties.put(Constants.PORT, BROKER_PORT);
|
|
||||||
configuration.update(properties);
|
|
||||||
// Remove the connection to make sure the test waits for the new connection to become available
|
|
||||||
mqttService.removeBrokerConnection(Constants.CLIENTID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt;
|
package org.openhab.binding.mqtt.homeassistant;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.*;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
@ -37,11 +37,11 @@ import org.mockito.quality.Strictness;
|
|||||||
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
||||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||||
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
|
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.ChannelConfigurationTypeAdapterFactory;
|
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents;
|
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents.ComponentDiscovered;
|
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents.ComponentDiscovered;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.test.java.JavaOSGiTest;
|
import org.openhab.core.test.java.JavaOSGiTest;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ public class DiscoverComponentsTest extends JavaOSGiTest {
|
|||||||
|
|
||||||
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
||||||
|
|
||||||
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.testHomeAssistantThing,
|
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING,
|
||||||
scheduler, channelStateUpdateListener, availabilityTracker, gson, transformationServiceProvider));
|
scheduler, channelStateUpdateListener, availabilityTracker, gson, transformationServiceProvider));
|
||||||
|
|
||||||
HandlerConfiguration config = new HandlerConfiguration("homeassistant",
|
HandlerConfiguration config = new HandlerConfiguration("homeassistant",
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt;
|
package org.openhab.binding.mqtt.homeassistant;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@ -25,11 +25,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
@ -45,22 +43,19 @@ import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
|||||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||||
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
|
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.AbstractComponent;
|
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.ChannelConfigurationTypeAdapterFactory;
|
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.ComponentSwitch;
|
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents;
|
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents.ComponentDiscovered;
|
import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents.ComponentDiscovered;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.component.Switch;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttService;
|
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.test.java.JavaOSGiTest;
|
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
import org.openhab.core.types.UnDefType;
|
import org.openhab.core.types.UnDefType;
|
||||||
import org.openhab.core.util.UIDUtils;
|
import org.openhab.core.util.UIDUtils;
|
||||||
import org.osgi.service.cm.ConfigurationAdmin;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
@ -74,11 +69,9 @@ import com.google.gson.GsonBuilder;
|
|||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
public class HomeAssistantMQTTImplementationTest extends MqttOSGiTest {
|
||||||
private @NonNullByDefault({}) ConfigurationAdmin configurationAdmin;
|
|
||||||
private @NonNullByDefault({}) MqttService mqttService;
|
private @NonNullByDefault({}) MqttBrokerConnection haConnection;
|
||||||
private @NonNullByDefault({}) MqttBrokerConnection embeddedConnection;
|
|
||||||
private @NonNullByDefault({}) MqttBrokerConnection connection;
|
|
||||||
private int registeredTopics = 100;
|
private int registeredTopics = 100;
|
||||||
private @Nullable Throwable failure;
|
private @Nullable Throwable failure;
|
||||||
|
|
||||||
@ -93,24 +86,17 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
private final MqttConnectionObserver failIfChange = (state, error) -> assertThat(state,
|
private final MqttConnectionObserver failIfChange = (state, error) -> assertThat(state,
|
||||||
is(MqttConnectionState.CONNECTED));
|
is(MqttConnectionState.CONNECTED));
|
||||||
private final String testObjectTopic = "homeassistant/switch/node/"
|
private final String testObjectTopic = "homeassistant/switch/node/"
|
||||||
+ ThingChannelConstants.testHomeAssistantThing.getId();
|
+ ThingChannelConstants.TEST_HOME_ASSISTANT_THING.getId();
|
||||||
|
|
||||||
|
@Override
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeEach() throws Exception {
|
public void beforeEach() throws Exception {
|
||||||
registerVolatileStorageService();
|
super.beforeEach();
|
||||||
configurationAdmin = getService(ConfigurationAdmin.class);
|
|
||||||
mqttService = getService(MqttService.class);
|
|
||||||
|
|
||||||
// Wait for the EmbeddedBrokerService internal connection to be connected
|
haConnection = createBrokerConnection("ha_mqtt");
|
||||||
embeddedConnection = new EmbeddedBrokerTools(configurationAdmin, mqttService).waitForConnection();
|
|
||||||
|
|
||||||
connection = new MqttBrokerConnection(embeddedConnection.getHost(), embeddedConnection.getPort(),
|
|
||||||
embeddedConnection.isSecure(), "ha_mqtt");
|
|
||||||
connection.start().get(2, TimeUnit.SECONDS);
|
|
||||||
assertThat(connection.connectionState(), is(MqttConnectionState.CONNECTED));
|
|
||||||
|
|
||||||
// If the connection state changes in between -> fail
|
// If the connection state changes in between -> fail
|
||||||
connection.addConnectionObserver(failIfChange);
|
haConnection.addConnectionObserver(failIfChange);
|
||||||
|
|
||||||
// Create topic string and config for one example HA component (a Switch)
|
// Create topic string and config for one example HA component (a Switch)
|
||||||
final String config = "{'name':'testname','state_topic':'" + testObjectTopic + "/state','command_topic':'"
|
final String config = "{'name':'testname','state_topic':'" + testObjectTopic + "/state','command_topic':'"
|
||||||
@ -118,8 +104,8 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
|
|
||||||
// Publish component configurations and component states to MQTT
|
// Publish component configurations and component states to MQTT
|
||||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||||
futures.add(embeddedConnection.publish(testObjectTopic + "/config", config.getBytes(), 0, true));
|
futures.add(publish(testObjectTopic + "/config", config));
|
||||||
futures.add(embeddedConnection.publish(testObjectTopic + "/state", "ON".getBytes(), 0, true));
|
futures.add(publish(testObjectTopic + "/state", "ON"));
|
||||||
|
|
||||||
registeredTopics = futures.size();
|
registeredTopics = futures.size();
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(2, TimeUnit.SECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(2, TimeUnit.SECONDS);
|
||||||
@ -129,41 +115,42 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
doReturn(null).when(transformationServiceProvider).getTransformationService(any());
|
doReturn(null).when(transformationServiceProvider).getTransformationService(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void afterEach() throws Exception {
|
public void afterEach() throws Exception {
|
||||||
if (connection != null) {
|
if (haConnection != null) {
|
||||||
connection.removeConnectionObserver(failIfChange);
|
haConnection.removeConnectionObserver(failIfChange);
|
||||||
connection.stop().get(2, TimeUnit.SECONDS);
|
haConnection.stop().get(5, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.afterEach();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void reconnectTest() throws InterruptedException, ExecutionException, TimeoutException {
|
public void reconnectTest() throws Exception {
|
||||||
connection.removeConnectionObserver(failIfChange);
|
haConnection.removeConnectionObserver(failIfChange);
|
||||||
connection.stop().get(2, TimeUnit.SECONDS);
|
haConnection.stop().get(5, TimeUnit.SECONDS);
|
||||||
connection = new MqttBrokerConnection(embeddedConnection.getHost(), embeddedConnection.getPort(),
|
haConnection = createBrokerConnection("ha_mqtt");
|
||||||
embeddedConnection.isSecure(), "ha_mqtt");
|
|
||||||
connection.start().get(2, TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void retrieveAllTopics() throws InterruptedException, ExecutionException, TimeoutException {
|
public void retrieveAllTopics() throws Exception {
|
||||||
CountDownLatch c = new CountDownLatch(registeredTopics);
|
CountDownLatch c = new CountDownLatch(registeredTopics);
|
||||||
connection.subscribe("homeassistant/+/+/" + ThingChannelConstants.testHomeAssistantThing.getId() + "/#",
|
haConnection.subscribe("homeassistant/+/+/" + ThingChannelConstants.TEST_HOME_ASSISTANT_THING.getId() + "/#",
|
||||||
(topic, payload) -> c.countDown()).get(2, TimeUnit.SECONDS);
|
(topic, payload) -> c.countDown()).get(5, TimeUnit.SECONDS);
|
||||||
assertTrue(c.await(2, TimeUnit.SECONDS),
|
assertTrue(c.await(2, TimeUnit.SECONDS),
|
||||||
"Connection " + connection.getClientId() + " not retrieving all topics");
|
"Connection " + haConnection.getClientId() + " not retrieving all topics");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseHATree() throws InterruptedException, ExecutionException, TimeoutException {
|
public void parseHATree() throws Exception {
|
||||||
MqttChannelTypeProvider channelTypeProvider = mock(MqttChannelTypeProvider.class);
|
MqttChannelTypeProvider channelTypeProvider = mock(MqttChannelTypeProvider.class);
|
||||||
|
|
||||||
final Map<String, AbstractComponent<?>> haComponents = new HashMap<>();
|
final Map<String, AbstractComponent<?>> haComponents = new HashMap<>();
|
||||||
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
||||||
|
|
||||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
|
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
|
||||||
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.testHomeAssistantThing,
|
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING,
|
||||||
scheduler, channelStateUpdateListener, availabilityTracker, gson, transformationServiceProvider));
|
scheduler, channelStateUpdateListener, availabilityTracker, gson, transformationServiceProvider));
|
||||||
|
|
||||||
// The DiscoverComponents object calls ComponentDiscovered callbacks.
|
// The DiscoverComponents object calls ComponentDiscovered callbacks.
|
||||||
@ -171,15 +158,15 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
// and add the types to the channelTypeProvider, like in the real Thing handler.
|
// and add the types to the channelTypeProvider, like in the real Thing handler.
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
ComponentDiscovered cd = (haID, c) -> {
|
ComponentDiscovered cd = (haID, c) -> {
|
||||||
haComponents.put(c.uid().getId(), c);
|
haComponents.put(c.getGroupUID().getId(), c);
|
||||||
c.addChannelTypes(channelTypeProvider);
|
c.addChannelTypes(channelTypeProvider);
|
||||||
channelTypeProvider.setChannelGroupType(c.groupTypeUID(), c.type());
|
channelTypeProvider.setChannelGroupType(c.getGroupTypeUID(), c.getType());
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start the discovery for 2000ms. Forced timeout after 4000ms.
|
// Start the discovery for 2000ms. Forced timeout after 4000ms.
|
||||||
HaID haID = new HaID(testObjectTopic + "/config");
|
HaID haID = new HaID(testObjectTopic + "/config");
|
||||||
CompletableFuture<Void> future = discover.startDiscovery(connection, 2000, Collections.singleton(haID), cd)
|
CompletableFuture<Void> future = discover.startDiscovery(haConnection, 2000, Collections.singleton(haID), cd)
|
||||||
.thenRun(() -> {
|
.thenRun(() -> {
|
||||||
}).exceptionally(e -> {
|
}).exceptionally(e -> {
|
||||||
failure = e;
|
failure = e;
|
||||||
@ -187,7 +174,7 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(latch.await(4, TimeUnit.SECONDS));
|
assertTrue(latch.await(4, TimeUnit.SECONDS));
|
||||||
future.get(2, TimeUnit.SECONDS);
|
future.get(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
// No failure expected and one discovered result
|
// No failure expected and one discovered result
|
||||||
assertNull(failure);
|
assertNull(failure);
|
||||||
@ -199,13 +186,13 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
verify(channelTypeProvider, times(1)).setChannelType(any(), any());
|
verify(channelTypeProvider, times(1)).setChannelType(any(), any());
|
||||||
|
|
||||||
String channelGroupId = UIDUtils
|
String channelGroupId = UIDUtils
|
||||||
.encode("node_" + ThingChannelConstants.testHomeAssistantThing.getId() + "_switch");
|
.encode("node_" + ThingChannelConstants.TEST_HOME_ASSISTANT_THING.getId() + "_switch");
|
||||||
|
|
||||||
State value = haComponents.get(channelGroupId).channelTypes().get(ComponentSwitch.switchChannelID).getState()
|
State value = haComponents.get(channelGroupId).getChannel(Switch.SWITCH_CHANNEL_ID).getState().getCache()
|
||||||
.getCache().getChannelState();
|
.getChannelState();
|
||||||
assertThat(value, is(UnDefType.UNDEF));
|
assertThat(value, is(UnDefType.UNDEF));
|
||||||
|
|
||||||
haComponents.values().stream().map(e -> e.start(connection, scheduler, 100))
|
haComponents.values().stream().map(e -> e.start(haConnection, scheduler, 100))
|
||||||
.reduce(CompletableFuture.completedFuture(null), (a, v) -> a.thenCompose(b -> v)).exceptionally(e -> {
|
.reduce(CompletableFuture.completedFuture(null), (a, v) -> a.thenCompose(b -> v)).exceptionally(e -> {
|
||||||
failure = e;
|
failure = e;
|
||||||
return null;
|
return null;
|
||||||
@ -215,8 +202,8 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
verify(channelStateUpdateListener, timeout(4000).times(1)).updateChannelState(any(), any());
|
verify(channelStateUpdateListener, timeout(4000).times(1)).updateChannelState(any(), any());
|
||||||
|
|
||||||
// Value should be ON now.
|
// Value should be ON now.
|
||||||
value = haComponents.get(channelGroupId).channelTypes().get(ComponentSwitch.switchChannelID).getState()
|
value = haComponents.get(channelGroupId).getChannel(Switch.SWITCH_CHANNEL_ID).getState().getCache()
|
||||||
.getCache().getChannelState();
|
.getChannelState();
|
||||||
assertThat(value, is(OnOffType.ON));
|
assertThat(value, is(OnOffType.ON));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.mqtt.homeassistant;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
|
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
||||||
|
import org.openhab.core.test.java.JavaOSGiTest;
|
||||||
|
|
||||||
|
import io.moquette.BrokerConstants;
|
||||||
|
import io.moquette.broker.Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Moquette MQTT broker instance and a {@link MqttBrokerConnection} for testing MQTT bindings.
|
||||||
|
*
|
||||||
|
* @author Wouter Born - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class MqttOSGiTest extends JavaOSGiTest {
|
||||||
|
|
||||||
|
private static final String BROKER_ID = "test-broker";
|
||||||
|
private static final int BROKER_PORT = Integer.getInteger("mqttbroker.port", 1883);
|
||||||
|
|
||||||
|
protected @NonNullByDefault({}) MqttBrokerConnection brokerConnection;
|
||||||
|
|
||||||
|
private Server moquetteServer = new Server();
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void beforeEach() throws Exception {
|
||||||
|
registerVolatileStorageService();
|
||||||
|
|
||||||
|
moquetteServer = new Server();
|
||||||
|
moquetteServer.startServer(brokerProperties());
|
||||||
|
|
||||||
|
brokerConnection = createBrokerConnection(BROKER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void afterEach() throws Exception {
|
||||||
|
brokerConnection.stop().get(5, TimeUnit.SECONDS);
|
||||||
|
moquetteServer.stopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties brokerProperties() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.put(BrokerConstants.HOST_PROPERTY_NAME, BrokerConstants.HOST);
|
||||||
|
properties.put(BrokerConstants.PORT_PROPERTY_NAME, String.valueOf(BROKER_PORT));
|
||||||
|
properties.put(BrokerConstants.SSL_PORT_PROPERTY_NAME, BrokerConstants.DISABLED_PORT_BIND);
|
||||||
|
properties.put(BrokerConstants.WEB_SOCKET_PORT_PROPERTY_NAME, BrokerConstants.DISABLED_PORT_BIND);
|
||||||
|
properties.put(BrokerConstants.WSS_PORT_PROPERTY_NAME, BrokerConstants.DISABLED_PORT_BIND);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MqttBrokerConnection createBrokerConnection(String clientId) throws Exception {
|
||||||
|
MqttBrokerConnection connection = new MqttBrokerConnection(BrokerConstants.HOST, BROKER_PORT, false, clientId);
|
||||||
|
connection.setQos(1);
|
||||||
|
connection.start().get(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
waitForAssert(() -> assertThat(connection.connectionState(), is(MqttConnectionState.CONNECTED)));
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CompletableFuture<Boolean> publish(String topic, String message) {
|
||||||
|
return brokerConnection.publish(topic, message.getBytes(StandardCharsets.UTF_8), 1, true);
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt;
|
package org.openhab.binding.mqtt.homeassistant;
|
||||||
|
|
||||||
import static org.openhab.binding.mqtt.homeassistant.generic.internal.MqttBindingConstants.HOMEASSISTANT_MQTT_THING;
|
import static org.openhab.binding.mqtt.homeassistant.generic.internal.MqttBindingConstants.HOMEASSISTANT_MQTT_THING;
|
||||||
|
|
||||||
@ -25,5 +25,5 @@ import org.openhab.core.thing.ThingUID;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class ThingChannelConstants {
|
public class ThingChannelConstants {
|
||||||
// Common ThingUID and ChannelUIDs
|
// Common ThingUID and ChannelUIDs
|
||||||
public static final ThingUID testHomeAssistantThing = new ThingUID(HOMEASSISTANT_MQTT_THING, "device234");
|
public static final ThingUID TEST_HOME_ASSISTANT_THING = new ThingUID(HOMEASSISTANT_MQTT_THING, "device234");
|
||||||
}
|
}
|
@ -3,93 +3,111 @@
|
|||||||
Bundle-SymbolicName: ${project.artifactId}
|
Bundle-SymbolicName: ${project.artifactId}
|
||||||
Fragment-Host: org.openhab.binding.mqtt.homie
|
Fragment-Host: org.openhab.binding.mqtt.homie
|
||||||
|
|
||||||
|
Import-Package: \
|
||||||
|
com.bugsnag.*;resolution:=optional,\
|
||||||
|
com.librato.metrics.reporter.*;resolution:=optional,\
|
||||||
|
*
|
||||||
|
|
||||||
|
-includeresource: \
|
||||||
|
moquette-broker-[0-9.]*.jar;lib:=true
|
||||||
|
|
||||||
-runrequires: \
|
-runrequires: \
|
||||||
bnd.identity;id='org.openhab.binding.mqtt.homie.tests',\
|
bnd.identity;id='org.openhab.binding.mqtt.homie.tests',\
|
||||||
bnd.identity;id='org.openhab.core.binding.xml',\
|
bnd.identity;id='org.openhab.core.binding.xml',\
|
||||||
bnd.identity;id='org.openhab.core.thing.xml',\
|
bnd.identity;id='org.openhab.core.thing.xml'
|
||||||
bnd.identity;id='org.openhab.io.mqttembeddedbroker'
|
|
||||||
|
|
||||||
# We would like to use the "volatile" storage only
|
# We would like to use the "volatile" storage only
|
||||||
-runblacklist: \
|
-runblacklist: \
|
||||||
bnd.identity;id='org.openhab.core.storage.json'
|
bnd.identity;id='org.openhab.core.storage.json'
|
||||||
|
|
||||||
-runvm: \
|
-runvm.mqtt: \
|
||||||
-Dio.netty.noUnsafe=true,\
|
-Dio.netty.noUnsafe=true,\
|
||||||
-Dmqttembeddedbroker.port=${mqttembeddedbroker.port}
|
-Dmqttbroker.port=${mqttbroker.port}
|
||||||
|
|
||||||
#
|
#
|
||||||
# done
|
# done
|
||||||
#
|
#
|
||||||
-runbundles: \
|
-runbundles: \
|
||||||
ch.qos.logback.core;version='[1.2.3,1.2.4)',\
|
|
||||||
com.google.gson;version='[2.8.2,2.8.3)',\
|
|
||||||
javax.measure.unit-api;version='[1.0.0,1.0.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.http.servlet-api;version='[1.1.2,1.1.3)',\
|
org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
|
||||||
org.apache.felix.scr;version='[2.1.10,2.1.11)',\
|
|
||||||
org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\
|
org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\
|
||||||
org.objenesis;version='[2.6.0,2.6.1)',\
|
|
||||||
org.osgi.service.event;version='[1.4.0,1.4.1)',\
|
org.osgi.service.event;version='[1.4.0,1.4.1)',\
|
||||||
slf4j.api;version='[1.7.25,1.7.26)',\
|
|
||||||
org.apache.servicemix.bundles.xstream;version='[1.4.7,1.4.8)',\
|
|
||||||
com.h2database.mvstore;version='[1.4.199,1.4.200)',\
|
|
||||||
io.netty.buffer;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.codec;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.codec-mqtt;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.common;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.handler;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.resolver;version='[4.1.42,4.1.43)',\
|
|
||||||
io.netty.transport;version='[4.1.42,4.1.43)',\
|
|
||||||
tec.uom.lib.uom-lib-common;version='[1.0.3,1.0.4)',\
|
|
||||||
tec.uom.se;version='[1.0.10,1.0.11)',\
|
|
||||||
ch.qos.logback.classic;version='[1.2.3,1.2.4)',\
|
|
||||||
biz.aQute.tester.junit-platform;version='[5.1.2,5.1.3)',\
|
|
||||||
com.google.dagger;version='[2.20.0,2.20.1)',\
|
|
||||||
com.hivemq.client.mqtt;version='[1.1.2,1.1.3)',\
|
|
||||||
io.netty.codec-http;version='[4.1.34,4.1.35)',\
|
|
||||||
io.netty.transport-native-epoll;version='[4.1.34,4.1.35)',\
|
|
||||||
io.netty.transport-native-unix-common;version='[4.1.34,4.1.35)',\
|
|
||||||
io.reactivex.rxjava2.rxjava;version='[2.2.5,2.2.6)',\
|
|
||||||
junit-jupiter-api;version='[5.6.2,5.6.3)',\
|
|
||||||
junit-jupiter-engine;version='[5.6.2,5.6.3)',\
|
|
||||||
junit-platform-commons;version='[1.6.2,1.6.3)',\
|
|
||||||
junit-platform-engine;version='[1.6.2,1.6.3)',\
|
|
||||||
junit-platform-launcher;version='[1.6.2,1.6.3)',\
|
|
||||||
net.bytebuddy.byte-buddy;version='[1.10.13,1.10.14)',\
|
|
||||||
net.bytebuddy.byte-buddy-agent;version='[1.10.13,1.10.14)',\
|
|
||||||
org.apache.aries.javax.jax.rs-api;version='[1.0.0,1.0.1)',\
|
|
||||||
org.apache.commons.codec;version='[1.10.0,1.10.1)',\
|
|
||||||
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.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\
|
org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\
|
||||||
org.hamcrest;version='[2.2.0,2.2.1)',\
|
org.hamcrest;version='[2.2.0,2.2.1)',\
|
||||||
org.jctools.core;version='[2.1.2,2.1.3)',\
|
org.jctools.core;version='[2.1.2,2.1.3)',\
|
||||||
org.mockito.mockito-core;version='[3.4.6,3.4.7)',\
|
|
||||||
org.openhab.binding.mqtt;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.binding.mqtt.generic;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.binding.mqtt.homie;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.binding.mqtt.homie.tests;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.binding.xml;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.config.core;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.config.discovery;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.config.xml;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.io.console;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.io.transport.mqtt;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.test;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.thing;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.thing.xml;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.core.transform;version='[3.0.0,3.0.1)',\
|
|
||||||
org.openhab.io.mqttembeddedbroker;version='[3.0.0,3.0.1)',\
|
|
||||||
org.opentest4j;version='[1.2.0,1.2.1)',\
|
org.opentest4j;version='[1.2.0,1.2.1)',\
|
||||||
org.reactivestreams.reactive-streams;version='[1.0.2,1.0.3)',\
|
|
||||||
jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
|
jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
|
||||||
com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\
|
com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\
|
||||||
org.glassfish.hk2.osgi-resource-locator;version='[1.0.1,1.0.2)',\
|
org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\
|
||||||
org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)'
|
com.google.dagger;version='[2.27.0,2.27.1)',\
|
||||||
|
com.google.gson;version='[2.8.9,2.8.10)',\
|
||||||
|
com.hivemq.client.mqtt;version='[1.2.2,1.2.3)',\
|
||||||
|
io.netty.buffer;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.codec;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.codec-http;version='[4.1.59,4.1.60)',\
|
||||||
|
io.netty.codec-socks;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.common;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.handler;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.handler-proxy;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.resolver;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.tcnative-classes;version='[2.0.46,2.0.47)',\
|
||||||
|
io.netty.transport;version='[4.1.72,4.1.73)',\
|
||||||
|
io.netty.transport-native-epoll;version='[4.1.59,4.1.60)',\
|
||||||
|
io.netty.transport-native-unix-common;version='[4.1.59,4.1.60)',\
|
||||||
|
io.reactivex.rxjava2.rxjava;version='[2.2.19,2.2.20)',\
|
||||||
|
jakarta.annotation-api;version='[2.0.0,2.0.1)',\
|
||||||
|
jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\
|
||||||
|
javax.measure.unit-api;version='[2.1.2,2.1.3)',\
|
||||||
|
junit-jupiter-api;version='[5.8.1,5.8.2)',\
|
||||||
|
junit-jupiter-engine;version='[5.8.1,5.8.2)',\
|
||||||
|
junit-platform-commons;version='[1.8.1,1.8.2)',\
|
||||||
|
junit-platform-engine;version='[1.8.1,1.8.2)',\
|
||||||
|
junit-platform-launcher;version='[1.8.1,1.8.2)',\
|
||||||
|
net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\
|
||||||
|
net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\
|
||||||
|
org.apache.aries.javax.jax.rs-api;version='[1.0.1,1.0.2)',\
|
||||||
|
org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\
|
||||||
|
org.apache.felix.scr;version='[2.1.30,2.1.31)',\
|
||||||
|
org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.server;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\
|
||||||
|
org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\
|
||||||
|
org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\
|
||||||
|
org.jsr-305;version='[3.0.2,3.0.3)',\
|
||||||
|
org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\
|
||||||
|
org.mockito.mockito-core;version='[4.1.0,4.1.1)',\
|
||||||
|
org.objenesis;version='[3.2.0,3.2.1)',\
|
||||||
|
org.openhab.binding.mqtt;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.binding.mqtt.generic;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.binding.mqtt.homie;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.binding.mqtt.homie.tests;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.binding.xml;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.config.core;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.config.discovery;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.config.xml;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.io.console;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.io.transport.mqtt;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.test;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.thing;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.thing.xml;version='[3.3.0,3.3.1)',\
|
||||||
|
org.openhab.core.transform;version='[3.3.0,3.3.1)',\
|
||||||
|
org.ops4j.pax.logging.pax-logging-api;version='[2.0.14,2.0.15)',\
|
||||||
|
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||||
|
org.osgi.util.function;version='[1.2.0,1.2.1)',\
|
||||||
|
org.osgi.util.promise;version='[1.2.0,1.2.1)',\
|
||||||
|
org.reactivestreams.reactive-streams;version='[1.0.3,1.0.4)',\
|
||||||
|
si-units;version='[2.1.0,2.1.1)',\
|
||||||
|
si.uom.si-quantity;version='[2.1.0,2.1.1)',\
|
||||||
|
tech.units.indriya;version='[2.1.2,2.1.3)',\
|
||||||
|
uom-lib-common;version='[2.1.0,2.1.1)',\
|
||||||
|
xstream;version='[1.4.19,1.4.20)',\
|
||||||
|
com.h2database.mvstore;version='[1.4.199,1.4.200)',\
|
||||||
|
com.zaxxer.HikariCP;version='[2.4.7,2.4.8)',\
|
||||||
|
io.dropwizard.metrics.core;version='[3.2.2,3.2.3)',\
|
||||||
|
io.netty.codec-mqtt;version='[4.1.72,4.1.73)',\
|
||||||
|
org.apache.commons.codec;version='[1.10.0,1.10.1)',\
|
||||||
|
biz.aQute.tester.junit-platform;version='[6.2.0,6.2.1)'
|
||||||
|
|
||||||
|
@ -7,13 +7,17 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.openhab.addons.itests</groupId>
|
<groupId>org.openhab.addons.itests</groupId>
|
||||||
<artifactId>org.openhab.addons.reactor.itests</artifactId>
|
<artifactId>org.openhab.addons.reactor.itests</artifactId>
|
||||||
<version>3.1.0-SNAPSHOT</version>
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>org.openhab.binding.mqtt.homie.tests</artifactId>
|
<artifactId>org.openhab.binding.mqtt.homie.tests</artifactId>
|
||||||
|
|
||||||
<name>openHAB Add-ons :: Integration Tests :: MQTT Homie Tests</name>
|
<name>openHAB Add-ons :: Integration Tests :: MQTT Homie Tests</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<mqttbroker.port>1883</mqttbroker.port>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openhab.addons.bundles</groupId>
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
@ -31,52 +35,43 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.j-n-k</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>moquette-broker</artifactId>
|
<artifactId>h2-mvstore</artifactId>
|
||||||
<version>0.13.0.OH2</version>
|
<version>1.4.199</version>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.moquette</groupId>
|
||||||
<artifactId>netty-common</artifactId>
|
<artifactId>moquette-broker</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>0.15</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-buffer</artifactId>
|
<artifactId>netty-buffer</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-transport</artifactId>
|
|
||||||
<version>${netty.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-codec</artifactId>
|
<artifactId>netty-codec</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>h2-mvstore</artifactId>
|
<artifactId>netty-codec-mqtt</artifactId>
|
||||||
<version>1.4.199</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-codec-mqtt</artifactId>
|
<artifactId>netty-common</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-handler</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-handler-proxy</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -86,7 +81,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-handler</artifactId>
|
<artifactId>netty-transport</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@ -98,14 +93,14 @@
|
|||||||
<artifactId>build-helper-maven-plugin</artifactId>
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>reserve-network-port</id>
|
<id>reserve-mqtt-broker-port</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>reserve-network-port</goal>
|
<goal>reserve-network-port</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<phase>process-resources</phase>
|
<phase>process-resources</phase>
|
||||||
<configuration>
|
<configuration>
|
||||||
<portNames>
|
<portNames>
|
||||||
<portName>mqttembeddedbroker.port</portName>
|
<portName>mqttbroker.port</portName>
|
||||||
</portNames>
|
</portNames>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 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.mqtt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT embedded broker constants
|
|
||||||
*
|
|
||||||
* @author David Graeff - Initial contribution
|
|
||||||
*/
|
|
||||||
public class Constants {
|
|
||||||
/**
|
|
||||||
* The broker connection client ID. You can request the embedded broker connection via the MqttService:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* MqttBrokerConnection c = mqttService.getBrokerConnection(Constants.CLIENTID);
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public static final String CLIENTID = "embedded-mqtt-broker";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The broker persistent identifier used for identifying configurations.
|
|
||||||
*/
|
|
||||||
public static final String PID = "org.openhab.core.mqttembeddedbroker";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The configuration key used for configuring the embedded broker port.
|
|
||||||
*/
|
|
||||||
public static final String PORT = "port";
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 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.mqtt;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Dictionary;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttService;
|
|
||||||
import org.openhab.core.io.transport.mqtt.MqttServiceObserver;
|
|
||||||
import org.osgi.service.cm.Configuration;
|
|
||||||
import org.osgi.service.cm.ConfigurationAdmin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A full implementation test, that starts the embedded MQTT broker and publishes a homeassistant MQTT discovery device
|
|
||||||
* tree.
|
|
||||||
*
|
|
||||||
* @author David Graeff - Initial contribution
|
|
||||||
* @author Wouter Born - Support running MQTT itests in parallel by reconfiguring embedded broker port
|
|
||||||
*/
|
|
||||||
@NonNullByDefault
|
|
||||||
public class EmbeddedBrokerTools {
|
|
||||||
|
|
||||||
private static final int BROKER_PORT = Integer.getInteger("mqttembeddedbroker.port", 1883);
|
|
||||||
|
|
||||||
private final ConfigurationAdmin configurationAdmin;
|
|
||||||
private final MqttService mqttService;
|
|
||||||
|
|
||||||
public @Nullable MqttBrokerConnection embeddedConnection;
|
|
||||||
|
|
||||||
public EmbeddedBrokerTools(ConfigurationAdmin configurationAdmin, MqttService mqttService) {
|
|
||||||
this.configurationAdmin = configurationAdmin;
|
|
||||||
this.mqttService = mqttService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request the embedded broker connection from the {@link MqttService} and wait for a connection to be established.
|
|
||||||
*
|
|
||||||
* @throws InterruptedException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public MqttBrokerConnection waitForConnection() throws InterruptedException, IOException {
|
|
||||||
reconfigurePort();
|
|
||||||
|
|
||||||
embeddedConnection = mqttService.getBrokerConnection(Constants.CLIENTID);
|
|
||||||
if (embeddedConnection == null) {
|
|
||||||
Semaphore semaphore = new Semaphore(1);
|
|
||||||
semaphore.acquire();
|
|
||||||
MqttServiceObserver observer = new MqttServiceObserver() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void brokerAdded(String brokerID, MqttBrokerConnection broker) {
|
|
||||||
if (brokerID.equals(Constants.CLIENTID)) {
|
|
||||||
embeddedConnection = broker;
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void brokerRemoved(String brokerID, MqttBrokerConnection broker) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mqttService.addBrokersListener(observer);
|
|
||||||
assertTrue(semaphore.tryAcquire(5, TimeUnit.SECONDS), "Wait for embedded connection client failed");
|
|
||||||
}
|
|
||||||
MqttBrokerConnection embeddedConnection = this.embeddedConnection;
|
|
||||||
if (embeddedConnection == null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Semaphore semaphore = new Semaphore(1);
|
|
||||||
semaphore.acquire();
|
|
||||||
MqttConnectionObserver mqttConnectionObserver = (state, error) -> {
|
|
||||||
if (state == MqttConnectionState.CONNECTED) {
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
embeddedConnection.addConnectionObserver(mqttConnectionObserver);
|
|
||||||
if (embeddedConnection.connectionState() == MqttConnectionState.CONNECTED) {
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
assertTrue(semaphore.tryAcquire(5, TimeUnit.SECONDS), "Connection " + embeddedConnection.getClientId()
|
|
||||||
+ " failed. State: " + embeddedConnection.connectionState());
|
|
||||||
return embeddedConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reconfigurePort() throws IOException {
|
|
||||||
Configuration configuration = configurationAdmin.getConfiguration(Constants.PID, null);
|
|
||||||
|
|
||||||
Dictionary<String, Object> properties = configuration.getProperties();
|
|
||||||
if (properties == null) {
|
|
||||||
properties = new Hashtable<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer currentPort = (Integer) properties.get(Constants.PORT);
|
|
||||||
if (currentPort == null || currentPort.intValue() != BROKER_PORT) {
|
|
||||||
properties.put(Constants.PORT, BROKER_PORT);
|
|
||||||
configuration.update(properties);
|
|
||||||
// Remove the connection to make sure the test waits for the new connection to become available
|
|
||||||
mqttService.removeBrokerConnection(Constants.CLIENTID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt;
|
package org.openhab.binding.mqtt.homie;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@ -18,17 +18,14 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
import static org.mockito.ArgumentMatchers.*;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@ -57,12 +54,10 @@ import org.openhab.binding.mqtt.homie.internal.homie300.PropertyHelper;
|
|||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttService;
|
|
||||||
import org.openhab.core.library.types.DecimalType;
|
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.test.java.JavaOSGiTest;
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
import org.openhab.core.library.unit.SIUnits;
|
||||||
import org.openhab.core.types.UnDefType;
|
import org.openhab.core.types.UnDefType;
|
||||||
import org.osgi.service.cm.ConfigurationAdmin;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A full implementation test, that starts the embedded MQTT broker and publishes a homie device tree.
|
* A full implementation test, that starts the embedded MQTT broker and publishes a homie device tree.
|
||||||
@ -72,15 +67,12 @@ import org.osgi.service.cm.ConfigurationAdmin;
|
|||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class HomieImplementationTest extends JavaOSGiTest {
|
public class HomieImplementationTest extends MqttOSGiTest {
|
||||||
private static final String BASE_TOPIC = "homie";
|
private static final String BASE_TOPIC = "homie";
|
||||||
private static final String DEVICE_ID = ThingChannelConstants.testHomieThing.getId();
|
private static final String DEVICE_ID = ThingChannelConstants.TEST_HOME_THING.getId();
|
||||||
private static final String DEVICE_TOPIC = BASE_TOPIC + "/" + DEVICE_ID;
|
private static final String DEVICE_TOPIC = BASE_TOPIC + "/" + DEVICE_ID;
|
||||||
|
|
||||||
private @NonNullByDefault({}) ConfigurationAdmin configurationAdmin;
|
private @NonNullByDefault({}) MqttBrokerConnection homieConnection;
|
||||||
private @NonNullByDefault({}) MqttService mqttService;
|
|
||||||
private @NonNullByDefault({}) MqttBrokerConnection embeddedConnection;
|
|
||||||
private @NonNullByDefault({}) MqttBrokerConnection connection;
|
|
||||||
private int registeredTopics = 100;
|
private int registeredTopics = 100;
|
||||||
|
|
||||||
// The handler is not tested here, so just mock the callback
|
// The handler is not tested here, so just mock the callback
|
||||||
@ -100,23 +92,15 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
|
|
||||||
private String propertyTestTopic = "";
|
private String propertyTestTopic = "";
|
||||||
|
|
||||||
|
@Override
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeEach() throws Exception {
|
public void beforeEach() throws Exception {
|
||||||
registerVolatileStorageService();
|
super.beforeEach();
|
||||||
configurationAdmin = getService(ConfigurationAdmin.class);
|
|
||||||
mqttService = getService(MqttService.class);
|
|
||||||
|
|
||||||
// Wait for the EmbeddedBrokerService internal connection to be connected
|
homieConnection = createBrokerConnection("homie");
|
||||||
embeddedConnection = new EmbeddedBrokerTools(configurationAdmin, mqttService).waitForConnection();
|
|
||||||
embeddedConnection.setQos(1);
|
|
||||||
|
|
||||||
connection = new MqttBrokerConnection(embeddedConnection.getHost(), embeddedConnection.getPort(),
|
|
||||||
embeddedConnection.isSecure(), "homie");
|
|
||||||
connection.setQos(1);
|
|
||||||
connection.start().get(5, TimeUnit.SECONDS);
|
|
||||||
assertThat(connection.connectionState(), is(MqttConnectionState.CONNECTED));
|
|
||||||
// If the connection state changes in between -> fail
|
// If the connection state changes in between -> fail
|
||||||
connection.addConnectionObserver(failIfChange);
|
homieConnection.addConnectionObserver(failIfChange);
|
||||||
|
|
||||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||||
futures.add(publish(DEVICE_TOPIC + "/$homie", "3.0"));
|
futures.add(publish(DEVICE_TOPIC + "/$homie", "3.0"));
|
||||||
@ -152,47 +136,46 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
futures.add(publish(propertyTestTopic + "/$datatype", "boolean"));
|
futures.add(publish(propertyTestTopic + "/$datatype", "boolean"));
|
||||||
|
|
||||||
registeredTopics = futures.size();
|
registeredTopics = futures.size();
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(2, TimeUnit.SECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
scheduler = new ScheduledThreadPoolExecutor(6);
|
scheduler = new ScheduledThreadPoolExecutor(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Boolean> publish(String topic, String message) {
|
@Override
|
||||||
return embeddedConnection.publish(topic, message.getBytes(StandardCharsets.UTF_8), 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void afterEach() throws Exception {
|
public void afterEach() throws Exception {
|
||||||
if (connection != null) {
|
if (homieConnection != null) {
|
||||||
connection.removeConnectionObserver(failIfChange);
|
homieConnection.removeConnectionObserver(failIfChange);
|
||||||
connection.stop().get(2, TimeUnit.SECONDS);
|
homieConnection.stop().get(5, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
if (scheduler != null) {
|
if (scheduler != null) {
|
||||||
scheduler.shutdownNow();
|
scheduler.shutdownNow();
|
||||||
}
|
}
|
||||||
|
super.afterEach();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void retrieveAllTopics() throws InterruptedException, ExecutionException, TimeoutException {
|
public void retrieveAllTopics() throws Exception {
|
||||||
// four topics are not under /testnode !
|
// four topics are not under /testnode !
|
||||||
CountDownLatch c = new CountDownLatch(registeredTopics - 4);
|
CountDownLatch c = new CountDownLatch(registeredTopics - 4);
|
||||||
connection.subscribe(DEVICE_TOPIC + "/testnode/#", (topic, payload) -> c.countDown()).get(5, TimeUnit.SECONDS);
|
homieConnection.subscribe(DEVICE_TOPIC + "/testnode/#", (topic, payload) -> c.countDown()).get(5,
|
||||||
|
TimeUnit.SECONDS);
|
||||||
assertTrue(c.await(5, TimeUnit.SECONDS),
|
assertTrue(c.await(5, TimeUnit.SECONDS),
|
||||||
"Connection " + connection.getClientId() + " not retrieving all topics ");
|
"Connection " + homieConnection.getClientId() + " not retrieving all topics ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void retrieveOneAttribute() throws InterruptedException, ExecutionException {
|
public void retrieveOneAttribute() throws Exception {
|
||||||
WaitForTopicValue watcher = new WaitForTopicValue(connection, DEVICE_TOPIC + "/$homie");
|
WaitForTopicValue watcher = new WaitForTopicValue(homieConnection, DEVICE_TOPIC + "/$homie");
|
||||||
assertThat(watcher.waitForTopicValue(1000), is("3.0"));
|
assertThat(watcher.waitForTopicValue(1000), is("3.0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
@Test
|
@Test
|
||||||
public void retrieveAttributes() throws InterruptedException, ExecutionException {
|
public void retrieveAttributes() throws Exception {
|
||||||
assertThat(connection.hasSubscribers(), is(false));
|
assertThat(homieConnection.hasSubscribers(), is(false));
|
||||||
|
|
||||||
Node node = new Node(DEVICE_TOPIC, "testnode", ThingChannelConstants.testHomieThing, callback,
|
Node node = new Node(DEVICE_TOPIC, "testnode", ThingChannelConstants.TEST_HOME_THING, callback,
|
||||||
new NodeAttributes());
|
new NodeAttributes());
|
||||||
Property property = spy(
|
Property property = spy(
|
||||||
new Property(DEVICE_TOPIC + "/testnode", node, "temperature", callback, new PropertyAttributes()));
|
new Property(DEVICE_TOPIC + "/testnode", node, "temperature", callback, new PropertyAttributes()));
|
||||||
@ -200,7 +183,7 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
// Create a scheduler
|
// Create a scheduler
|
||||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
|
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
|
||||||
|
|
||||||
property.subscribe(connection, scheduler, 500).get();
|
property.subscribe(homieConnection, scheduler, 500).get();
|
||||||
|
|
||||||
assertThat(property.attributes.settable, is(true));
|
assertThat(property.attributes.settable, is(true));
|
||||||
assertThat(property.attributes.retained, is(true));
|
assertThat(property.attributes.retained, is(true));
|
||||||
@ -214,15 +197,16 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
ChannelState channelState = spy(property.getChannelState());
|
ChannelState channelState = spy(property.getChannelState());
|
||||||
PropertyHelper.setChannelState(property, channelState);
|
PropertyHelper.setChannelState(property, channelState);
|
||||||
|
|
||||||
property.startChannel(connection, scheduler, 500).get();
|
property.startChannel(homieConnection, scheduler, 500).get();
|
||||||
verify(channelState).start(any(), any(), anyInt());
|
verify(channelState).start(any(), any(), anyInt());
|
||||||
verify(channelState, timeout(500)).processMessage(any(), any());
|
verify(channelState, timeout(500)).processMessage(any(), any());
|
||||||
verify(callback).updateChannelState(any(), any());
|
verify(callback).updateChannelState(any(), any());
|
||||||
|
|
||||||
assertThat(property.getChannelState().getCache().getChannelState(), is(new DecimalType(10)));
|
assertThat(property.getChannelState().getCache().getChannelState(),
|
||||||
|
is(new QuantityType<>(10, SIUnits.CELSIUS)));
|
||||||
|
|
||||||
property.stop().get();
|
property.stop().get();
|
||||||
assertThat(connection.hasSubscribers(), is(false));
|
assertThat(homieConnection.hasSubscribers(), is(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject a spy'ed property
|
// Inject a spy'ed property
|
||||||
@ -245,19 +229,19 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
|
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
@Test
|
@Test
|
||||||
public void parseHomieTree() throws InterruptedException, ExecutionException, TimeoutException {
|
public void parseHomieTree() throws Exception {
|
||||||
// Create a Homie Device object. Because spied Nodes are required for call verification,
|
// Create a Homie Device object. Because spied Nodes are required for call verification,
|
||||||
// the full Device constructor need to be used and a ChildMap object need to be created manually.
|
// the full Device constructor need to be used and a ChildMap object need to be created manually.
|
||||||
ChildMap<Node> nodeMap = new ChildMap<>();
|
ChildMap<Node> nodeMap = new ChildMap<>();
|
||||||
Device device = spy(
|
Device device = spy(
|
||||||
new Device(ThingChannelConstants.testHomieThing, callback, new DeviceAttributes(), nodeMap));
|
new Device(ThingChannelConstants.TEST_HOME_THING, callback, new DeviceAttributes(), nodeMap));
|
||||||
|
|
||||||
// Intercept creating a node in initialize()->start() and inject a spy'ed node.
|
// Intercept creating a node in initialize()->start() and inject a spy'ed node.
|
||||||
doAnswer(this::createSpyNode).when(device).createNode(any());
|
doAnswer(this::createSpyNode).when(device).createNode(any());
|
||||||
|
|
||||||
// initialize the device, subscribe and wait.
|
// initialize the device, subscribe and wait.
|
||||||
device.initialize(BASE_TOPIC, DEVICE_ID, Collections.emptyList());
|
device.initialize(BASE_TOPIC, DEVICE_ID, Collections.emptyList());
|
||||||
device.subscribe(connection, scheduler, 1500).get();
|
device.subscribe(homieConnection, scheduler, 1500).get();
|
||||||
|
|
||||||
assertThat(device.isInitialized(), is(true));
|
assertThat(device.isInitialized(), is(true));
|
||||||
|
|
||||||
@ -306,22 +290,23 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
assertThat(propertyBell.attributes.datatype, is(DataTypeEnum.boolean_));
|
assertThat(propertyBell.attributes.datatype, is(DataTypeEnum.boolean_));
|
||||||
|
|
||||||
// The device->node->property tree is ready. Now subscribe to property values.
|
// The device->node->property tree is ready. Now subscribe to property values.
|
||||||
device.startChannels(connection, scheduler, 50, handler).get();
|
device.startChannels(homieConnection, scheduler, 50, handler).get();
|
||||||
assertThat(propertyBell.getChannelState().isStateful(), is(false));
|
assertThat(propertyBell.getChannelState().isStateful(), is(false));
|
||||||
assertThat(propertyBell.getChannelState().getCache().getChannelState(), is(UnDefType.UNDEF));
|
assertThat(propertyBell.getChannelState().getCache().getChannelState(), is(UnDefType.UNDEF));
|
||||||
assertThat(property.getChannelState().getCache().getChannelState(), is(new DecimalType(10)));
|
assertThat(property.getChannelState().getCache().getChannelState(),
|
||||||
|
is(new QuantityType<>(10, SIUnits.CELSIUS)));
|
||||||
|
|
||||||
property = node.properties.get("testRetain");
|
property = node.properties.get("testRetain");
|
||||||
WaitForTopicValue watcher = new WaitForTopicValue(embeddedConnection, propertyTestTopic + "/set");
|
WaitForTopicValue watcher = new WaitForTopicValue(brokerConnection, propertyTestTopic + "/set");
|
||||||
// Watch the topic. Publish a retain=false value to MQTT
|
// Watch the topic. Publish a retain=false value to MQTT
|
||||||
property.getChannelState().publishValue(OnOffType.OFF).get();
|
property.getChannelState().publishValue(OnOffType.OFF).get();
|
||||||
assertThat(watcher.waitForTopicValue(1000), is("false"));
|
assertThat(watcher.waitForTopicValue(10000), is("false"));
|
||||||
|
|
||||||
// Publish a retain=false value to MQTT.
|
// Publish a retain=false value to MQTT.
|
||||||
property.getChannelState().publishValue(OnOffType.ON).get();
|
property.getChannelState().publishValue(OnOffType.ON).get();
|
||||||
// No value is expected to be retained on this MQTT topic
|
// No value is expected to be retained on this MQTT topic
|
||||||
waitForAssert(() -> {
|
waitForAssert(() -> {
|
||||||
WaitForTopicValue w = new WaitForTopicValue(embeddedConnection, propertyTestTopic + "/set");
|
WaitForTopicValue w = new WaitForTopicValue(brokerConnection, propertyTestTopic + "/set");
|
||||||
assertNull(w.waitForTopicValue(50));
|
assertNull(w.waitForTopicValue(50));
|
||||||
}, 500, 100);
|
}, 500, 100);
|
||||||
}
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.mqtt.homie;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
|
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
||||||
|
import org.openhab.core.test.java.JavaOSGiTest;
|
||||||
|
|
||||||
|
import io.moquette.BrokerConstants;
|
||||||
|
import io.moquette.broker.Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Moquette MQTT broker instance and a {@link MqttBrokerConnection} for testing MQTT bindings.
|
||||||
|
*
|
||||||
|
* @author Wouter Born - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class MqttOSGiTest extends JavaOSGiTest {
|
||||||
|
|
||||||
|
private static final String BROKER_ID = "test-broker";
|
||||||
|
private static final int BROKER_PORT = Integer.getInteger("mqttbroker.port", 1883);
|
||||||
|
|
||||||
|
protected @NonNullByDefault({}) MqttBrokerConnection brokerConnection;
|
||||||
|
|
||||||
|
private Server moquetteServer = new Server();
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void beforeEach() throws Exception {
|
||||||
|
registerVolatileStorageService();
|
||||||
|
|
||||||
|
moquetteServer = new Server();
|
||||||
|
moquetteServer.startServer(brokerProperties());
|
||||||
|
|
||||||
|
brokerConnection = createBrokerConnection(BROKER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void afterEach() throws Exception {
|
||||||
|
brokerConnection.stop().get(5, TimeUnit.SECONDS);
|
||||||
|
moquetteServer.stopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties brokerProperties() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.put(BrokerConstants.HOST_PROPERTY_NAME, BrokerConstants.HOST);
|
||||||
|
properties.put(BrokerConstants.PORT_PROPERTY_NAME, String.valueOf(BROKER_PORT));
|
||||||
|
properties.put(BrokerConstants.SSL_PORT_PROPERTY_NAME, BrokerConstants.DISABLED_PORT_BIND);
|
||||||
|
properties.put(BrokerConstants.WEB_SOCKET_PORT_PROPERTY_NAME, BrokerConstants.DISABLED_PORT_BIND);
|
||||||
|
properties.put(BrokerConstants.WSS_PORT_PROPERTY_NAME, BrokerConstants.DISABLED_PORT_BIND);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MqttBrokerConnection createBrokerConnection(String clientId) throws Exception {
|
||||||
|
MqttBrokerConnection connection = new MqttBrokerConnection(BrokerConstants.HOST, BROKER_PORT, false, clientId);
|
||||||
|
connection.setQos(1);
|
||||||
|
connection.start().get(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
waitForAssert(() -> assertThat(connection.connectionState(), is(MqttConnectionState.CONNECTED)));
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CompletableFuture<Boolean> publish(String topic, String message) {
|
||||||
|
return brokerConnection.publish(topic, message.getBytes(StandardCharsets.UTF_8), 1, true);
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt;
|
package org.openhab.binding.mqtt.homie;
|
||||||
|
|
||||||
import static org.openhab.binding.mqtt.homie.generic.internal.MqttBindingConstants.HOMIE300_MQTT_THING;
|
import static org.openhab.binding.mqtt.homie.generic.internal.MqttBindingConstants.HOMIE300_MQTT_THING;
|
||||||
|
|
||||||
@ -25,5 +25,5 @@ import org.openhab.core.thing.ThingUID;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class ThingChannelConstants {
|
public class ThingChannelConstants {
|
||||||
// Common ThingUID and ChannelUIDs
|
// Common ThingUID and ChannelUIDs
|
||||||
public final static ThingUID testHomieThing = new ThingUID(HOMIE300_MQTT_THING, "device123");
|
public static final ThingUID TEST_HOME_THING = new ThingUID(HOMIE300_MQTT_THING, "device123");
|
||||||
}
|
}
|
@ -24,10 +24,8 @@
|
|||||||
<module>org.openhab.binding.max.tests</module>
|
<module>org.openhab.binding.max.tests</module>
|
||||||
<module>org.openhab.binding.mielecloud.tests</module>
|
<module>org.openhab.binding.mielecloud.tests</module>
|
||||||
<module>org.openhab.binding.modbus.tests</module>
|
<module>org.openhab.binding.modbus.tests</module>
|
||||||
<!-- MQTT tests need to be refactored to not use the embedded broker bundle anymore
|
<module>org.openhab.binding.mqtt.homeassistant.tests</module>
|
||||||
<module>org.openhab.binding.mqtt.homeassistant.tests</module>
|
<module>org.openhab.binding.mqtt.homie.tests</module>
|
||||||
<module>org.openhab.binding.mqtt.homie.tests</module>
|
|
||||||
-->
|
|
||||||
<module>org.openhab.binding.nest.tests</module>
|
<module>org.openhab.binding.nest.tests</module>
|
||||||
<module>org.openhab.binding.ntp.tests</module>
|
<module>org.openhab.binding.ntp.tests</module>
|
||||||
<module>org.openhab.binding.systeminfo.tests</module>
|
<module>org.openhab.binding.systeminfo.tests</module>
|
||||||
|
Loading…
Reference in New Issue
Block a user