Fix disabled integration tests (#8609)
* Fix disabled integration tests Fixes and enables: * org.openhab.binding.mqtt.homeassistant.tests * org.openhab.binding.mqtt.homie.tests * org.openhab.io.mqttembeddedbroker.tests Fixes #8537 * Address review comment Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
parent
831eaeb026
commit
d72a077ba9
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homie.internal.handler;
|
package org.openhab.binding.mqtt.homie.internal.handler;
|
||||||
|
|
||||||
|
import static org.eclipse.jdt.annotation.Checks.requireNonNull;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
@ -249,7 +250,7 @@ public class HomieThingHandlerTests {
|
|||||||
node.properties.put(property.propertyID, property);
|
node.properties.put(property.propertyID, property);
|
||||||
thingHandler.device.nodes.put(node.nodeID, node);
|
thingHandler.device.nodes.put(node.nodeID, node);
|
||||||
|
|
||||||
ChannelState channelState = property.getChannelState();
|
ChannelState channelState = requireNonNull(property.getChannelState());
|
||||||
assertNotNull(channelState);
|
assertNotNull(channelState);
|
||||||
ChannelStateHelper.setConnection(channelState, connection);// Pretend we called start()
|
ChannelStateHelper.setConnection(channelState, connection);// Pretend we called start()
|
||||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
ThingHandlerHelper.setConnection(thingHandler, connection);
|
||||||
|
|||||||
@ -9,6 +9,10 @@ Fragment-Host: org.openhab.binding.mqtt.homeassistant
|
|||||||
bnd.identity;id='org.openhab.core.thing.xml',\
|
bnd.identity;id='org.openhab.core.thing.xml',\
|
||||||
bnd.identity;id='org.openhab.io.mqttembeddedbroker'
|
bnd.identity;id='org.openhab.io.mqttembeddedbroker'
|
||||||
|
|
||||||
|
# We would like to use the "volatile" storage only
|
||||||
|
-runblacklist: \
|
||||||
|
bnd.identity;id='org.openhab.core.storage.json'
|
||||||
|
|
||||||
#
|
#
|
||||||
# done
|
# done
|
||||||
#
|
#
|
||||||
@ -83,6 +87,7 @@ Fragment-Host: org.openhab.binding.mqtt.homeassistant
|
|||||||
org.openhab.core.transform;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.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)'
|
org.reactivestreams.reactive-streams;version='[1.0.2,1.0.3)',\
|
||||||
|
moquette-broker;version='[0.13.0,0.13.1)'
|
||||||
|
|
||||||
-runvm: -Dio.netty.noUnsafe=true
|
-runvm: -Dio.netty.noUnsafe=true
|
||||||
|
|||||||
@ -82,7 +82,6 @@
|
|||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2-mvstore</artifactId>
|
<artifactId>h2-mvstore</artifactId>
|
||||||
<version>1.4.199</version>
|
<version>1.4.199</version>
|
||||||
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
@ -99,7 +98,6 @@
|
|||||||
<artifactId>netty-handler</artifactId>
|
<artifactId>netty-handler</artifactId>
|
||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -26,6 +26,8 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -49,26 +51,26 @@ import com.google.gson.GsonBuilder;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class DiscoverComponentsTest extends JavaOSGiTest {
|
public class DiscoverComponentsTest extends JavaOSGiTest {
|
||||||
|
|
||||||
private AutoCloseable mocksCloseable;
|
private @NonNullByDefault({}) AutoCloseable mocksCloseable;
|
||||||
|
|
||||||
private @Mock MqttBrokerConnection connection;
|
private @Mock @NonNullByDefault({}) MqttBrokerConnection connection;
|
||||||
private @Mock ComponentDiscovered discovered;
|
private @Mock @NonNullByDefault({}) ComponentDiscovered discovered;
|
||||||
private @Mock TransformationServiceProvider transformationServiceProvider;
|
private @Mock @NonNullByDefault({}) TransformationServiceProvider transformationServiceProvider;
|
||||||
private @Mock ChannelStateUpdateListener channelStateUpdateListener;
|
private @Mock @NonNullByDefault({}) ChannelStateUpdateListener channelStateUpdateListener;
|
||||||
private @Mock AvailabilityTracker availabilityTracker;
|
private @Mock @NonNullByDefault({}) AvailabilityTracker availabilityTracker;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeEach() {
|
public void beforeEach() {
|
||||||
mocksCloseable = openMocks(this);
|
mocksCloseable = openMocks(this);
|
||||||
|
|
||||||
CompletableFuture<Void> voidFutureComplete = new CompletableFuture<>();
|
CompletableFuture<@Nullable Void> voidFutureComplete = new CompletableFuture<>();
|
||||||
voidFutureComplete.complete(null);
|
voidFutureComplete.complete(null);
|
||||||
doReturn(voidFutureComplete).when(connection).unsubscribeAll();
|
doReturn(voidFutureComplete).when(connection).unsubscribeAll();
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(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(),
|
doReturn(CompletableFuture.completedFuture(true)).when(connection).publish(any(), any(), anyInt(),
|
||||||
anyBoolean());
|
anyBoolean());
|
||||||
doReturn(null).when(transformationServiceProvider).getTransformationService(any());
|
doReturn(null).when(transformationServiceProvider).getTransformationService(any());
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
@ -50,7 +49,7 @@ public class EmbeddedBrokerTools {
|
|||||||
MqttServiceObserver observer = new MqttServiceObserver() {
|
MqttServiceObserver observer = new MqttServiceObserver() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void brokerAdded(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
public void brokerAdded(String brokerID, MqttBrokerConnection broker) {
|
||||||
if (brokerID.equals(Constants.CLIENTID)) {
|
if (brokerID.equals(Constants.CLIENTID)) {
|
||||||
embeddedConnection = broker;
|
embeddedConnection = broker;
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
@ -58,7 +57,7 @@ public class EmbeddedBrokerTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void brokerRemoved(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
public void brokerRemoved(String brokerID, MqttBrokerConnection broker) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mqttService.addBrokersListener(observer);
|
mqttService.addBrokersListener(observer);
|
||||||
|
|||||||
@ -32,6 +32,8 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -65,26 +67,28 @@ import com.google.gson.GsonBuilder;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
||||||
private MqttService mqttService;
|
private @NonNullByDefault({}) MqttService mqttService;
|
||||||
private MqttBrokerConnection embeddedConnection;
|
private @NonNullByDefault({}) MqttBrokerConnection embeddedConnection;
|
||||||
private MqttBrokerConnection connection;
|
private @NonNullByDefault({}) MqttBrokerConnection connection;
|
||||||
private int registeredTopics = 100;
|
private int registeredTopics = 100;
|
||||||
private Throwable failure = null;
|
private @Nullable Throwable failure;
|
||||||
|
|
||||||
private AutoCloseable mocksCloseable;
|
private @NonNullByDefault({}) AutoCloseable mocksCloseable;
|
||||||
|
|
||||||
private @Mock ChannelStateUpdateListener channelStateUpdateListener;
|
private @Mock @NonNullByDefault({}) ChannelStateUpdateListener channelStateUpdateListener;
|
||||||
private @Mock AvailabilityTracker availabilityTracker;
|
private @Mock @NonNullByDefault({}) AvailabilityTracker availabilityTracker;
|
||||||
private @Mock TransformationServiceProvider transformationServiceProvider;
|
private @Mock @NonNullByDefault({}) TransformationServiceProvider transformationServiceProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an observer that fails the test as soon as the broker client connection changes its connection state
|
* Create an observer that fails the test as soon as the broker client connection changes its connection state
|
||||||
* to something else then CONNECTED.
|
* to something else then CONNECTED.
|
||||||
*/
|
*/
|
||||||
private MqttConnectionObserver failIfChange = (state, error) -> assertThat(state,
|
private final MqttConnectionObserver failIfChange = (state, error) -> assertThat(state,
|
||||||
is(MqttConnectionState.CONNECTED));
|
is(MqttConnectionState.CONNECTED));
|
||||||
private String testObjectTopic;
|
private final String testObjectTopic = "homeassistant/switch/node/"
|
||||||
|
+ ThingChannelConstants.testHomeAssistantThing.getId();
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeEach() throws Exception {
|
public void beforeEach() throws Exception {
|
||||||
@ -104,14 +108,13 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
connection.addConnectionObserver(failIfChange);
|
connection.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)
|
||||||
testObjectTopic = "homeassistant/switch/node/" + ThingChannelConstants.testHomeAssistantThing.getId();
|
|
||||||
final String config = "{'name':'testname','state_topic':'" + testObjectTopic + "/state','command_topic':'"
|
final String config = "{'name':'testname','state_topic':'" + testObjectTopic + "/state','command_topic':'"
|
||||||
+ testObjectTopic + "/set'}";
|
+ testObjectTopic + "/set'}";
|
||||||
|
|
||||||
// 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()));
|
futures.add(embeddedConnection.publish(testObjectTopic + "/config", config.getBytes(), 0, true));
|
||||||
futures.add(embeddedConnection.publish(testObjectTopic + "/state", "true".getBytes()));
|
futures.add(embeddedConnection.publish(testObjectTopic + "/state", "ON".getBytes(), 0, true));
|
||||||
|
|
||||||
registeredTopics = futures.size();
|
registeredTopics = futures.size();
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
||||||
@ -171,17 +174,17 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
latch.countDown();
|
latch.countDown();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start the discovery for 500ms. Forced timeout after 1500ms.
|
// 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, 1000, Collections.singleton(haID), cd)
|
CompletableFuture<Void> future = discover.startDiscovery(connection, 2000, Collections.singleton(haID), cd)
|
||||||
.thenRun(() -> {
|
.thenRun(() -> {
|
||||||
}).exceptionally(e -> {
|
}).exceptionally(e -> {
|
||||||
failure = e;
|
failure = e;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(latch.await(1500, TimeUnit.MILLISECONDS));
|
assertTrue(latch.await(4000, TimeUnit.MILLISECONDS));
|
||||||
future.get(800, TimeUnit.MILLISECONDS);
|
future.get(2000, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
// No failure expected and one discovered result
|
// No failure expected and one discovered result
|
||||||
assertNull(failure);
|
assertNull(failure);
|
||||||
@ -206,7 +209,7 @@ public class HomeAssistantMQTTImplementationTest extends JavaOSGiTest {
|
|||||||
}).get();
|
}).get();
|
||||||
|
|
||||||
// We should have received the retained value, while subscribing to the channels MQTT state topic.
|
// We should have received the retained value, while subscribing to the channels MQTT state topic.
|
||||||
verify(channelStateUpdateListener, timeout(1000).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).channelTypes().get(ComponentSwitch.switchChannelID).getState()
|
||||||
|
|||||||
@ -14,6 +14,7 @@ package org.openhab.binding.mqtt;
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,6 +22,7 @@ import org.openhab.core.thing.ThingUID;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@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 testHomeAssistantThing = new ThingUID(HOMEASSISTANT_MQTT_THING, "device234");
|
||||||
|
|||||||
@ -9,6 +9,10 @@ Fragment-Host: org.openhab.binding.mqtt.homie
|
|||||||
bnd.identity;id='org.openhab.core.thing.xml',\
|
bnd.identity;id='org.openhab.core.thing.xml',\
|
||||||
bnd.identity;id='org.openhab.io.mqttembeddedbroker'
|
bnd.identity;id='org.openhab.io.mqttembeddedbroker'
|
||||||
|
|
||||||
|
# We would like to use the "volatile" storage only
|
||||||
|
-runblacklist: \
|
||||||
|
bnd.identity;id='org.openhab.core.storage.json'
|
||||||
|
|
||||||
#
|
#
|
||||||
# done
|
# done
|
||||||
#
|
#
|
||||||
@ -83,5 +87,6 @@ Fragment-Host: org.openhab.binding.mqtt.homie
|
|||||||
org.openhab.core.transform;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.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)'
|
org.reactivestreams.reactive-streams;version='[1.0.2,1.0.3)',\
|
||||||
|
moquette-broker;version='[0.13.0,0.13.1)'
|
||||||
-runvm: -Dio.netty.noUnsafe=true
|
-runvm: -Dio.netty.noUnsafe=true
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
@ -53,7 +52,7 @@ public class EmbeddedBrokerTools {
|
|||||||
MqttServiceObserver observer = new MqttServiceObserver() {
|
MqttServiceObserver observer = new MqttServiceObserver() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void brokerAdded(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
public void brokerAdded(String brokerID, MqttBrokerConnection broker) {
|
||||||
if (brokerID.equals(Constants.CLIENTID)) {
|
if (brokerID.equals(Constants.CLIENTID)) {
|
||||||
embeddedConnection = broker;
|
embeddedConnection = broker;
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
@ -61,7 +60,7 @@ public class EmbeddedBrokerTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void brokerRemoved(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
public void brokerRemoved(String brokerID, MqttBrokerConnection broker) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mqttService.addBrokersListener(observer);
|
mqttService.addBrokersListener(observer);
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import static org.mockito.Mockito.*;
|
|||||||
import static org.mockito.MockitoAnnotations.openMocks;
|
import static org.mockito.MockitoAnnotations.openMocks;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -32,6 +31,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -65,25 +65,26 @@ import org.openhab.core.types.UnDefType;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HomieImplementationTest extends JavaOSGiTest {
|
public class HomieImplementationTest extends JavaOSGiTest {
|
||||||
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.testHomieThing.getId();
|
||||||
private static final String DEVICE_TOPIC = BASE_TOPIC + "/" + DEVICE_ID;
|
private static final String DEVICE_TOPIC = BASE_TOPIC + "/" + DEVICE_ID;
|
||||||
|
|
||||||
private MqttService mqttService;
|
private @NonNullByDefault({}) MqttService mqttService;
|
||||||
private MqttBrokerConnection embeddedConnection;
|
private @NonNullByDefault({}) MqttBrokerConnection embeddedConnection;
|
||||||
private MqttBrokerConnection connection;
|
private @NonNullByDefault({}) MqttBrokerConnection connection;
|
||||||
private int registeredTopics = 100;
|
private int registeredTopics = 100;
|
||||||
|
|
||||||
private AutoCloseable mocksCloseable;
|
private @NonNullByDefault({}) AutoCloseable mocksCloseable;
|
||||||
|
|
||||||
// The handler is not tested here, so just mock the callback
|
// The handler is not tested here, so just mock the callback
|
||||||
private @Mock DeviceCallback callback;
|
private @Mock @NonNullByDefault({}) DeviceCallback callback;
|
||||||
|
|
||||||
// A handler mock is required to verify that channel value changes have been received
|
// A handler mock is required to verify that channel value changes have been received
|
||||||
private @Mock HomieThingHandler handler;
|
private @Mock @NonNullByDefault({}) HomieThingHandler handler;
|
||||||
|
|
||||||
private ScheduledExecutorService scheduler;
|
private @NonNullByDefault({}) ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an observer that fails the test as soon as the broker client connection changes its connection state
|
* Create an observer that fails the test as soon as the broker client connection changes its connection state
|
||||||
@ -92,7 +93,7 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
private MqttConnectionObserver failIfChange = (state, error) -> assertThat(state,
|
private MqttConnectionObserver failIfChange = (state, error) -> assertThat(state,
|
||||||
is(MqttConnectionState.CONNECTED));
|
is(MqttConnectionState.CONNECTED));
|
||||||
|
|
||||||
private String propertyTestTopic;
|
private String propertyTestTopic = "";
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeEach() throws Exception {
|
public void beforeEach() throws Exception {
|
||||||
@ -102,50 +103,47 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
|
|
||||||
embeddedConnection = new EmbeddedBrokerTools().waitForConnection(mqttService);
|
embeddedConnection = new EmbeddedBrokerTools().waitForConnection(mqttService);
|
||||||
embeddedConnection.setQos(1);
|
embeddedConnection.setQos(1);
|
||||||
embeddedConnection.setRetain(true);
|
|
||||||
|
|
||||||
connection = new MqttBrokerConnection(embeddedConnection.getHost(), embeddedConnection.getPort(),
|
connection = new MqttBrokerConnection(embeddedConnection.getHost(), embeddedConnection.getPort(),
|
||||||
embeddedConnection.isSecure(), "homie");
|
embeddedConnection.isSecure(), "homie");
|
||||||
connection.setQos(1);
|
connection.setQos(1);
|
||||||
connection.setPersistencePath(Paths.get("subconn"));
|
|
||||||
connection.start().get(500, TimeUnit.MILLISECONDS);
|
connection.start().get(500, TimeUnit.MILLISECONDS);
|
||||||
assertThat(connection.connectionState(), is(MqttConnectionState.CONNECTED));
|
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);
|
connection.addConnectionObserver(failIfChange);
|
||||||
|
|
||||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||||
futures.add(embeddedConnection.publish(DEVICE_TOPIC + "/$homie", "3.0".getBytes()));
|
futures.add(publish(DEVICE_TOPIC + "/$homie", "3.0"));
|
||||||
futures.add(embeddedConnection.publish(DEVICE_TOPIC + "/$name", "Name".getBytes()));
|
futures.add(publish(DEVICE_TOPIC + "/$name", "Name"));
|
||||||
futures.add(embeddedConnection.publish(DEVICE_TOPIC + "/$state", "ready".getBytes()));
|
futures.add(publish(DEVICE_TOPIC + "/$state", "ready"));
|
||||||
futures.add(embeddedConnection.publish(DEVICE_TOPIC + "/$nodes", "testnode".getBytes()));
|
futures.add(publish(DEVICE_TOPIC + "/$nodes", "testnode"));
|
||||||
|
|
||||||
// Add homie node topics
|
// Add homie node topics
|
||||||
final String testNode = DEVICE_TOPIC + "/testnode";
|
final String testNode = DEVICE_TOPIC + "/testnode";
|
||||||
futures.add(embeddedConnection.publish(testNode + "/$name", "Testnode".getBytes()));
|
futures.add(publish(testNode + "/$name", "Testnode"));
|
||||||
futures.add(embeddedConnection.publish(testNode + "/$type", "Type".getBytes()));
|
futures.add(publish(testNode + "/$type", "Type"));
|
||||||
futures.add(
|
futures.add(publish(testNode + "/$properties", "temperature,doorbell,testRetain"));
|
||||||
embeddedConnection.publish(testNode + "/$properties", "temperature,doorbell,testRetain".getBytes()));
|
|
||||||
|
|
||||||
// Add homie property topics
|
// Add homie property topics
|
||||||
final String property = testNode + "/temperature";
|
final String property = testNode + "/temperature";
|
||||||
futures.add(embeddedConnection.publish(property, "10".getBytes()));
|
futures.add(publish(property, "10"));
|
||||||
futures.add(embeddedConnection.publish(property + "/$name", "Testprop".getBytes()));
|
futures.add(publish(property + "/$name", "Testprop"));
|
||||||
futures.add(embeddedConnection.publish(property + "/$settable", "true".getBytes()));
|
futures.add(publish(property + "/$settable", "true"));
|
||||||
futures.add(embeddedConnection.publish(property + "/$unit", "°C".getBytes(StandardCharsets.UTF_8)));
|
futures.add(publish(property + "/$unit", "°C"));
|
||||||
futures.add(embeddedConnection.publish(property + "/$datatype", "float".getBytes()));
|
futures.add(publish(property + "/$datatype", "float"));
|
||||||
futures.add(embeddedConnection.publish(property + "/$format", "-100:100".getBytes()));
|
futures.add(publish(property + "/$format", "-100:100"));
|
||||||
|
|
||||||
final String propertyBellTopic = testNode + "/doorbell";
|
final String propertyBellTopic = testNode + "/doorbell";
|
||||||
futures.add(embeddedConnection.publish(propertyBellTopic + "/$name", "Doorbell".getBytes()));
|
futures.add(publish(propertyBellTopic + "/$name", "Doorbell"));
|
||||||
futures.add(embeddedConnection.publish(propertyBellTopic + "/$settable", "false".getBytes()));
|
futures.add(publish(propertyBellTopic + "/$settable", "false"));
|
||||||
futures.add(embeddedConnection.publish(propertyBellTopic + "/$retained", "false".getBytes()));
|
futures.add(publish(propertyBellTopic + "/$retained", "false"));
|
||||||
futures.add(embeddedConnection.publish(propertyBellTopic + "/$datatype", "boolean".getBytes()));
|
futures.add(publish(propertyBellTopic + "/$datatype", "boolean"));
|
||||||
|
|
||||||
this.propertyTestTopic = testNode + "/testRetain";
|
this.propertyTestTopic = testNode + "/testRetain";
|
||||||
futures.add(embeddedConnection.publish(propertyTestTopic + "/$name", "Test".getBytes()));
|
futures.add(publish(propertyTestTopic + "/$name", "Test"));
|
||||||
futures.add(embeddedConnection.publish(propertyTestTopic + "/$settable", "true".getBytes()));
|
futures.add(publish(propertyTestTopic + "/$settable", "true"));
|
||||||
futures.add(embeddedConnection.publish(propertyTestTopic + "/$retained", "false".getBytes()));
|
futures.add(publish(propertyTestTopic + "/$retained", "false"));
|
||||||
futures.add(embeddedConnection.publish(propertyTestTopic + "/$datatype", "boolean".getBytes()));
|
futures.add(publish(propertyTestTopic + "/$datatype", "boolean"));
|
||||||
|
|
||||||
registeredTopics = futures.size();
|
registeredTopics = futures.size();
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
||||||
@ -153,6 +151,10 @@ public class HomieImplementationTest extends JavaOSGiTest {
|
|||||||
scheduler = new ScheduledThreadPoolExecutor(6);
|
scheduler = new ScheduledThreadPoolExecutor(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Boolean> publish(String topic, String message) {
|
||||||
|
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 (connection != null) {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ package org.openhab.binding.mqtt;
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,6 +22,7 @@ import org.openhab.core.thing.ThingUID;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@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 final static ThingUID testHomieThing = new ThingUID(HOMIE300_MQTT_THING, "device123");
|
||||||
|
|||||||
@ -4,7 +4,11 @@ Bundle-SymbolicName: ${project.artifactId}
|
|||||||
Fragment-Host: org.openhab.io.mqttembeddedbroker
|
Fragment-Host: org.openhab.io.mqttembeddedbroker
|
||||||
|
|
||||||
-runrequires: \
|
-runrequires: \
|
||||||
bnd.identity;id='org.openhab.io.mqttembeddedbroker.tests'
|
bnd.identity;id='org.openhab.io.mqttembeddedbroker.tests'
|
||||||
|
|
||||||
|
# We would like to use the "volatile" storage only
|
||||||
|
-runblacklist: \
|
||||||
|
bnd.identity;id='org.openhab.core.storage.json'
|
||||||
|
|
||||||
#
|
#
|
||||||
# done
|
# done
|
||||||
@ -67,5 +71,6 @@ Fragment-Host: org.openhab.io.mqttembeddedbroker
|
|||||||
org.openhab.io.mqttembeddedbroker;version='[3.0.0,3.0.1)',\
|
org.openhab.io.mqttembeddedbroker;version='[3.0.0,3.0.1)',\
|
||||||
org.openhab.io.mqttembeddedbroker.tests;version='[3.0.0,3.0.1)',\
|
org.openhab.io.mqttembeddedbroker.tests;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)'
|
org.reactivestreams.reactive-streams;version='[1.0.2,1.0.3)',\
|
||||||
|
moquette-broker;version='[0.13.0,0.13.1)'
|
||||||
-runvm: -Dio.netty.noUnsafe=true
|
-runvm: -Dio.netty.noUnsafe=true
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
@ -52,7 +51,7 @@ public class EmbeddedBrokerTools {
|
|||||||
MqttServiceObserver observer = new MqttServiceObserver() {
|
MqttServiceObserver observer = new MqttServiceObserver() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void brokerAdded(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
public void brokerAdded(String brokerID, MqttBrokerConnection broker) {
|
||||||
if (brokerID.equals(Constants.CLIENTID)) {
|
if (brokerID.equals(Constants.CLIENTID)) {
|
||||||
embeddedConnection = broker;
|
embeddedConnection = broker;
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
@ -60,7 +59,7 @@ public class EmbeddedBrokerTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void brokerRemoved(@NonNull String brokerID, @NonNull MqttBrokerConnection broker) {
|
public void brokerRemoved(String brokerID, MqttBrokerConnection broker) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mqttService.addBrokersListener(observer);
|
mqttService.addBrokersListener(observer);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -40,14 +41,15 @@ import org.openhab.core.test.java.JavaOSGiTest;
|
|||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class MoquetteTest extends JavaOSGiTest {
|
public class MoquetteTest extends JavaOSGiTest {
|
||||||
private static final String TEST_TOPIC = "testtopic";
|
private static final String TEST_TOPIC = "testtopic";
|
||||||
|
|
||||||
private AutoCloseable mocksCloseable;
|
private @NonNullByDefault({}) AutoCloseable mocksCloseable;
|
||||||
|
|
||||||
private MqttService mqttService;
|
private @NonNullByDefault({}) MqttService mqttService;
|
||||||
private MqttBrokerConnection embeddedConnection;
|
private @NonNullByDefault({}) MqttBrokerConnection embeddedConnection;
|
||||||
private MqttBrokerConnection clientConnection;
|
private @NonNullByDefault({}) MqttBrokerConnection clientConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an observer that fails the test as soon as the broker client connection changes its connection state
|
* Create an observer that fails the test as soon as the broker client connection changes its connection state
|
||||||
@ -84,11 +86,15 @@ public class MoquetteTest extends JavaOSGiTest {
|
|||||||
mocksCloseable.close();
|
mocksCloseable.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Boolean> publish(String topic, String message) {
|
||||||
|
return embeddedConnection.publish(topic, message.getBytes(StandardCharsets.UTF_8), 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singleTopic() throws InterruptedException, ExecutionException, TimeoutException {
|
public void singleTopic() throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||||
|
|
||||||
futures.add(embeddedConnection.publish(TEST_TOPIC, "testPayload".getBytes(StandardCharsets.UTF_8), 1, true));
|
futures.add(publish(TEST_TOPIC, "testPayload"));
|
||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
@ -105,10 +111,8 @@ public class MoquetteTest extends JavaOSGiTest {
|
|||||||
throws InterruptedException, ExecutionException, TimeoutException {
|
throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||||
|
|
||||||
futures.add(embeddedConnection.publish(TEST_TOPIC + "/1", "testPayload1".getBytes(StandardCharsets.UTF_8), 1,
|
futures.add(publish(TEST_TOPIC + "/1", "testPayload1"));
|
||||||
true));
|
futures.add(publish(TEST_TOPIC + "/2", "testPayload2"));
|
||||||
futures.add(embeddedConnection.publish(TEST_TOPIC + "/2", "testPayload2".getBytes(StandardCharsets.UTF_8), 1,
|
|
||||||
true));
|
|
||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
@ -126,10 +130,8 @@ public class MoquetteTest extends JavaOSGiTest {
|
|||||||
throws InterruptedException, ExecutionException, TimeoutException {
|
throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||||
|
|
||||||
futures.add(embeddedConnection.publish(TEST_TOPIC + "/1", "testPayload1".getBytes(StandardCharsets.UTF_8), 1,
|
futures.add(publish(TEST_TOPIC + "/1", "testPayload1"));
|
||||||
true));
|
futures.add(publish(TEST_TOPIC + "/2", "testPayload2"));
|
||||||
futures.add(embeddedConnection.publish(TEST_TOPIC + "/2", "testPayload2".getBytes(StandardCharsets.UTF_8), 1,
|
|
||||||
true));
|
|
||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
@ -146,10 +148,8 @@ public class MoquetteTest extends JavaOSGiTest {
|
|||||||
throws InterruptedException, ExecutionException, TimeoutException {
|
throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
|
||||||
|
|
||||||
futures.add(embeddedConnection.publish(TEST_TOPIC + "/1", "testPayload1".getBytes(StandardCharsets.UTF_8), 1,
|
futures.add(publish(TEST_TOPIC + "/1", "testPayload1"));
|
||||||
true));
|
futures.add(publish(TEST_TOPIC + "/2", "testPayload2"));
|
||||||
futures.add(embeddedConnection.publish(TEST_TOPIC + "/2", "testPayload2".getBytes(StandardCharsets.UTF_8), 1,
|
|
||||||
true));
|
|
||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(1000, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
|||||||
@ -23,11 +23,14 @@
|
|||||||
<module>org.openhab.binding.hue.tests</module>
|
<module>org.openhab.binding.hue.tests</module>
|
||||||
<module>org.openhab.binding.max.tests</module>
|
<module>org.openhab.binding.max.tests</module>
|
||||||
<module>org.openhab.binding.modbus.tests</module>
|
<module>org.openhab.binding.modbus.tests</module>
|
||||||
|
<module>org.openhab.binding.mqtt.homeassistant.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>
|
||||||
<module>org.openhab.binding.tradfri.tests</module>
|
<module>org.openhab.binding.tradfri.tests</module>
|
||||||
<module>org.openhab.binding.wemo.tests</module>
|
<module>org.openhab.binding.wemo.tests</module>
|
||||||
|
<module>org.openhab.io.mqttembeddedbroker.tests</module>
|
||||||
<module>org.openhab.persistence.mapdb.tests</module>
|
<module>org.openhab.persistence.mapdb.tests</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user