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:
Wouter Born 2020-09-29 23:05:39 +02:00 committed by GitHub
parent 831eaeb026
commit d72a077ba9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 117 additions and 92 deletions

View File

@ -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);

View File

@ -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

View File

@ -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>

View File

@ -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());

View File

@ -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);

View File

@ -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()

View File

@ -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");

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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");

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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>