added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
itests/org.openhab.binding.mqtt.homeassistant.tests/.project
Normal file
23
itests/org.openhab.binding.mqtt.homeassistant.tests/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.mqtt.homeassistant.tests</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
itests/org.openhab.binding.mqtt.homeassistant.tests/NOTICE
Normal file
13
itests/org.openhab.binding.mqtt.homeassistant.tests/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
@@ -0,0 +1,74 @@
|
||||
-include: ../itest-common.bndrun
|
||||
|
||||
Bundle-SymbolicName: ${project.artifactId}
|
||||
Fragment-Host: org.openhab.binding.mqtt.homeassistant
|
||||
|
||||
-runrequires: \
|
||||
bnd.identity;id='org.openhab.binding.mqtt.homeassistant.tests',\
|
||||
bnd.identity;id='org.openhab.core.binding.xml',\
|
||||
bnd.identity;id='org.openhab.core.thing.xml',\
|
||||
bnd.identity;id='org.openhab.io.mqttembeddedbroker'
|
||||
|
||||
#
|
||||
# done
|
||||
#
|
||||
-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.collections;version='[3.2.1,3.2.2)',\
|
||||
org.apache.commons.io;version='[2.2.0,2.2.1)',\
|
||||
org.apache.commons.lang;version='[2.6.0,2.6.1)',\
|
||||
org.apache.felix.configadmin;version='[1.9.8,1.9.9)',\
|
||||
org.apache.felix.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.apache.servicemix.specs.activation-api-1.1;version='[2.9.0,2.9.1)',\
|
||||
org.apache.servicemix.specs.jaxb-api-2.2;version='[2.9.0,2.9.1)',\
|
||||
org.apache.servicemix.specs.stax-api-1.2;version='[2.9.0,2.9.1)',\
|
||||
org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\
|
||||
org.eclipse.jetty.http;version='[9.4.11,9.4.12)',\
|
||||
org.eclipse.jetty.io;version='[9.4.11,9.4.12)',\
|
||||
org.eclipse.jetty.security;version='[9.4.11,9.4.12)',\
|
||||
org.eclipse.jetty.server;version='[9.4.11,9.4.12)',\
|
||||
org.eclipse.jetty.servlet;version='[9.4.11,9.4.12)',\
|
||||
org.eclipse.jetty.util;version='[9.4.11,9.4.12)',\
|
||||
org.eclipse.paho.client.mqttv3;version='[1.2.1,1.2.2)',\
|
||||
org.objenesis;version='[2.6.0,2.6.1)',\
|
||||
org.openhab.binding.mqtt;version='[2.5.2,2.5.3)',\
|
||||
org.openhab.binding.mqtt.generic;version='[2.5.2,2.5.3)',\
|
||||
org.openhab.binding.mqtt.homeassistant;version='[2.5.2,2.5.3)',\
|
||||
org.openhab.binding.mqtt.homeassistant.tests;version='[2.5.2,2.5.3)',\
|
||||
org.openhab.core;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.binding.xml;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.config.core;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.config.discovery;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.config.xml;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.io.console;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.io.transport.mqtt;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.test;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.thing;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.thing.xml;version='[2.5.0,2.5.1)',\
|
||||
org.openhab.core.transform;version='[2.5.0,2.5.1)',\
|
||||
org.osgi.service.event;version='[1.4.0,1.4.1)',\
|
||||
osgi.enroute.hamcrest.wrapper;version='[1.3.0,1.3.1)',\
|
||||
osgi.enroute.junit.wrapper;version='[4.12.0,4.12.1)',\
|
||||
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)',\
|
||||
org.openhab.io.mqttembeddedbroker;version='[2.5.0,2.5.1)',\
|
||||
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)',\
|
||||
org.apache.servicemix.bundles.jaxb-impl;version='[2.2.11,2.2.12)',\
|
||||
net.bytebuddy.byte-buddy;version='[1.9.10,1.9.11)',\
|
||||
net.bytebuddy.byte-buddy-agent;version='[1.9.10,1.9.11)',\
|
||||
org.mockito.mockito-core;version='[3.1.0,3.1.1)'
|
||||
|
||||
-runvm: -Dio.netty.noUnsafe=true
|
||||
104
itests/org.openhab.binding.mqtt.homeassistant.tests/pom.xml
Normal file
104
itests/org.openhab.binding.mqtt.homeassistant.tests/pom.xml
Normal file
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.itests</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.itests</artifactId>
|
||||
<version>2.5.9-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.mqtt.homeassistant.tests</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Integration Tests :: MQTT HomeAssistant Tests</name>
|
||||
|
||||
<properties>
|
||||
<netty.version>4.1.42.Final</netty.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.mqtt</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.mqtt.generic</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.mqtt.homeassistant</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.io.mqttembeddedbroker</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.j-n-k</groupId>
|
||||
<artifactId>moquette-broker</artifactId>
|
||||
<version>0.13.0.OH2</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>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-common</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-buffer</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2-mvstore</artifactId>
|
||||
<version>1.4.199</version>
|
||||
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec-mqtt</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-resolver</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mqtt;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||
import org.openhab.core.test.java.JavaOSGiTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||
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.ComponentDiscovered;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* Tests the {@link DiscoverComponents} class.
|
||||
*
|
||||
* @author David Graeff - Initial contribution
|
||||
*/
|
||||
public class DiscoverComponentsTest extends JavaOSGiTest {
|
||||
@Mock
|
||||
MqttBrokerConnection connection;
|
||||
|
||||
@Mock
|
||||
ComponentDiscovered discovered;
|
||||
|
||||
@Mock
|
||||
TransformationServiceProvider transformationServiceProvider;
|
||||
|
||||
@Mock
|
||||
ChannelStateUpdateListener channelStateUpdateListener;
|
||||
|
||||
@Mock
|
||||
AvailabilityTracker availabilityTracker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
initMocks(this);
|
||||
CompletableFuture<Void> voidFutureComplete = new CompletableFuture<>();
|
||||
voidFutureComplete.complete(null);
|
||||
doReturn(voidFutureComplete).when(connection).unsubscribeAll();
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).publish(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).publish(any(), any(), anyInt(),
|
||||
anyBoolean());
|
||||
doReturn(null).when(transformationServiceProvider).getTransformationService(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoveryTimeTest() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
// Create a scheduler
|
||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
||||
|
||||
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.testHomeAssistantThing,
|
||||
scheduler, channelStateUpdateListener, availabilityTracker, gson, transformationServiceProvider));
|
||||
|
||||
HandlerConfiguration config = new HandlerConfiguration("homeassistant",
|
||||
Collections.singletonList("switch/object"));
|
||||
|
||||
Set<HaID> discoveryIds = new HashSet<>();
|
||||
discoveryIds.addAll(HaID.fromConfig(config));
|
||||
|
||||
discover.startDiscovery(connection, 50, discoveryIds, discovered).get(100, TimeUnit.MILLISECONDS);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mqtt;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
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.openhab.io.mqttembeddedbroker.Constants;
|
||||
|
||||
/**
|
||||
* A full implementation test, that starts the embedded MQTT broker and publishes a homeassistant MQTT discovery device
|
||||
* tree.
|
||||
*
|
||||
* @author David Graeff - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EmbeddedBrokerTools {
|
||||
public @Nullable MqttBrokerConnection embeddedConnection = null;
|
||||
|
||||
/**
|
||||
* Request the embedded broker connection from the {@link MqttService} and wait for a connection to be established.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public MqttBrokerConnection waitForConnection(MqttService mqttService) throws InterruptedException {
|
||||
embeddedConnection = mqttService.getBrokerConnection(Constants.CLIENTID);
|
||||
if (embeddedConnection == null) {
|
||||
Semaphore semaphore = new Semaphore(1);
|
||||
semaphore.acquire();
|
||||
MqttServiceObserver observer = new MqttServiceObserver() {
|
||||
|
||||
@Override
|
||||
public void brokerAdded(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
||||
if (brokerID.equals(Constants.CLIENTID)) {
|
||||
embeddedConnection = broker;
|
||||
semaphore.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void brokerRemoved(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
||||
}
|
||||
|
||||
};
|
||||
mqttService.addBrokersListener(observer);
|
||||
assertTrue("Wait for embedded connection client failed", semaphore.tryAcquire(1000, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
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("Connection " + embeddedConnection.getClientId() + " failed. State: "
|
||||
+ embeddedConnection.connectionState(), semaphore.tryAcquire(500, TimeUnit.MILLISECONDS));
|
||||
return embeddedConnection;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mqtt;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.openhab.core.util.UIDUtils;
|
||||
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.test.java.JavaOSGiTest;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||
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.ComponentDiscovered;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* A full implementation test, that starts the embedded MQTT broker and publishes a homeassistant MQTT discovery device
|
||||
* tree.
|
||||
*
|
||||
* @author David Graeff - Initial contribution
|
||||
*/
|
||||
public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
||||
private MqttService mqttService;
|
||||
private MqttBrokerConnection embeddedConnection;
|
||||
private MqttBrokerConnection connection;
|
||||
private int registeredTopics = 100;
|
||||
private Throwable failure = null;
|
||||
|
||||
@Mock
|
||||
ChannelStateUpdateListener channelStateUpdateListener;
|
||||
|
||||
@Mock
|
||||
AvailabilityTracker availabilityTracker;
|
||||
|
||||
@Mock
|
||||
TransformationServiceProvider transformationServiceProvider;
|
||||
|
||||
/**
|
||||
* Create an observer that fails the test as soon as the broker client connection changes its connection state
|
||||
* to something else then CONNECTED.
|
||||
*/
|
||||
private MqttConnectionObserver failIfChange = (state, error) -> assertThat(state,
|
||||
is(MqttConnectionState.CONNECTED));
|
||||
private String testObjectTopic;
|
||||
|
||||
@Before
|
||||
public void setUp() throws InterruptedException, ExecutionException, TimeoutException, IOException {
|
||||
registerVolatileStorageService();
|
||||
initMocks(this);
|
||||
mqttService = getService(MqttService.class);
|
||||
|
||||
// Wait for the EmbeddedBrokerService internal connection to be connected
|
||||
embeddedConnection = new EmbeddedBrokerTools().waitForConnection(mqttService);
|
||||
|
||||
connection = new MqttBrokerConnection(embeddedConnection.getHost(), embeddedConnection.getPort(),
|
||||
embeddedConnection.isSecure(), "ha_mqtt");
|
||||
connection.start().get(1000, TimeUnit.MILLISECONDS);
|
||||
assertThat(connection.connectionState(), is(MqttConnectionState.CONNECTED));
|
||||
|
||||
// If the connection state changes in between -> fail
|
||||
connection.addConnectionObserver(failIfChange);
|
||||
|
||||
// Create topic string and config for one example HA component (a Switch)
|
||||
testObjectTopic = "homeassistant/switch/node/" + ThingChannelConstants.testHomeAssistantThing.getId();
|
||||
final String config = "{'name':'testname','state_topic':'" + testObjectTopic + "/state','command_topic':'"
|
||||
+ testObjectTopic + "/set'}";
|
||||
|
||||
// Publish component configurations and component states to MQTT
|
||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||
futures.add(embeddedConnection.publish(testObjectTopic + "/config", config.getBytes()));
|
||||
futures.add(embeddedConnection.publish(testObjectTopic + "/state", "true".getBytes()));
|
||||
|
||||
registeredTopics = futures.size();
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
failure = null;
|
||||
|
||||
doReturn(null).when(transformationServiceProvider).getTransformationService(any());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (connection != null) {
|
||||
connection.removeConnectionObserver(failIfChange);
|
||||
connection.stop().get(1000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reconnectTest() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
connection.removeConnectionObserver(failIfChange);
|
||||
connection.stop().get(2000, TimeUnit.MILLISECONDS);
|
||||
connection = new MqttBrokerConnection(embeddedConnection.getHost(), embeddedConnection.getPort(),
|
||||
embeddedConnection.isSecure(), "ha_mqtt");
|
||||
connection.start().get(2000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveAllTopics() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
CountDownLatch c = new CountDownLatch(registeredTopics);
|
||||
connection.subscribe("homeassistant/+/+/" + ThingChannelConstants.testHomeAssistantThing.getId() + "/#",
|
||||
(topic, payload) -> c.countDown()).get(1000, TimeUnit.MILLISECONDS);
|
||||
assertTrue("Connection " + connection.getClientId() + " not retrieving all topics",
|
||||
c.await(1000, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHATree() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
MqttChannelTypeProvider channelTypeProvider = mock(MqttChannelTypeProvider.class);
|
||||
|
||||
final Map<String, AbstractComponent<?>> haComponents = new HashMap<>();
|
||||
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
||||
|
||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
|
||||
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.testHomeAssistantThing,
|
||||
scheduler, channelStateUpdateListener, availabilityTracker, gson, transformationServiceProvider));
|
||||
|
||||
// The DiscoverComponents object calls ComponentDiscovered callbacks.
|
||||
// In the following implementation we add the found component to the `haComponents` map
|
||||
// and add the types to the channelTypeProvider, like in the real Thing handler.
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ComponentDiscovered cd = (haID, c) -> {
|
||||
haComponents.put(c.uid().getId(), c);
|
||||
c.addChannelTypes(channelTypeProvider);
|
||||
channelTypeProvider.setChannelGroupType(c.groupTypeUID(), c.type());
|
||||
latch.countDown();
|
||||
};
|
||||
|
||||
// Start the discovery for 500ms. Forced timeout after 1500ms.
|
||||
HaID haID = new HaID(testObjectTopic + "/config");
|
||||
CompletableFuture<Void> future = discover.startDiscovery(connection, 1000, Collections.singleton(haID), cd)
|
||||
.thenRun(() -> {
|
||||
}).exceptionally(e -> {
|
||||
failure = e;
|
||||
return null;
|
||||
});
|
||||
|
||||
assertTrue(latch.await(1500, TimeUnit.MILLISECONDS));
|
||||
future.get(800, TimeUnit.MILLISECONDS);
|
||||
|
||||
// No failure expected and one discovered result
|
||||
assertNull(failure);
|
||||
assertThat(haComponents.size(), is(1));
|
||||
|
||||
// For the switch component we should have one channel group type and one channel type
|
||||
// setChannelGroupType is called once above
|
||||
verify(channelTypeProvider, times(2)).setChannelGroupType(any(), any());
|
||||
verify(channelTypeProvider, times(1)).setChannelType(any(), any());
|
||||
|
||||
String channelGroupId = UIDUtils
|
||||
.encode("node_" + ThingChannelConstants.testHomeAssistantThing.getId() + "_switch");
|
||||
|
||||
State value = haComponents.get(channelGroupId).channelTypes().get(ComponentSwitch.switchChannelID).getState()
|
||||
.getCache().getChannelState();
|
||||
assertThat(value, is(UnDefType.UNDEF));
|
||||
|
||||
haComponents.values().stream().map(e -> e.start(connection, scheduler, 100))
|
||||
.reduce(CompletableFuture.completedFuture(null), (a, v) -> a.thenCompose(b -> v)).exceptionally(e -> {
|
||||
failure = e;
|
||||
return null;
|
||||
}).get();
|
||||
|
||||
// We should have received the retained value, while subscribing to the channels MQTT state topic.
|
||||
verify(channelStateUpdateListener, timeout(1000).times(1)).updateChannelState(any(), any());
|
||||
|
||||
// Value should be ON now.
|
||||
value = haComponents.get(channelGroupId).channelTypes().get(ComponentSwitch.switchChannelID).getState()
|
||||
.getCache().getChannelState();
|
||||
assertThat(value, is(OnOffType.ON));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mqtt;
|
||||
|
||||
import static org.openhab.binding.mqtt.homeassistant.generic.internal.MqttBindingConstants.HOMEASSISTANT_MQTT_THING;
|
||||
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
/**
|
||||
* Static test definitions, like thing, bridge and channel definitions
|
||||
*
|
||||
* @author David Graeff - Initial contribution
|
||||
*/
|
||||
public class ThingChannelConstants {
|
||||
// Common ThingUID and ChannelUIDs
|
||||
public static final ThingUID testHomeAssistantThing = new ThingUID(HOMEASSISTANT_MQTT_THING, "device234");
|
||||
}
|
||||
Reference in New Issue
Block a user