[mqtt] Fix most SAT findings (#12492)
Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
@@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||
@@ -327,8 +326,8 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAvailabilityTopic(@NonNull String availability_topic) {
|
||||
availabilityStates.computeIfPresent(availability_topic, (topic, state) -> {
|
||||
public void removeAvailabilityTopic(String availabilityTopic) {
|
||||
availabilityStates.computeIfPresent(availabilityTopic, (topic, state) -> {
|
||||
if (connection != null && state != null) {
|
||||
state.stop();
|
||||
}
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.generic.mapping;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Color modes supported by the binding.
|
||||
*
|
||||
* @author Aitor Iturrioz - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum ColorMode {
|
||||
HSB,
|
||||
RGB,
|
||||
|
||||
@@ -81,13 +81,13 @@ public class SubscribeFieldToMQTTtopic implements MqttMessageSubscriber {
|
||||
String typeName = type.getSimpleName();
|
||||
if (value instanceof BigDecimal && !type.equals(BigDecimal.class)) {
|
||||
BigDecimal bdValue = (BigDecimal) value;
|
||||
if (type.equals(Float.class) || typeName.equals("float")) {
|
||||
if (type.equals(Float.class) || "float".equals(typeName)) {
|
||||
result = bdValue.floatValue();
|
||||
} else if (type.equals(Double.class) || typeName.equals("double")) {
|
||||
} else if (type.equals(Double.class) || "double".equals(typeName)) {
|
||||
result = bdValue.doubleValue();
|
||||
} else if (type.equals(Long.class) || typeName.equals("long")) {
|
||||
} else if (type.equals(Long.class) || "long".equals(typeName)) {
|
||||
result = bdValue.longValue();
|
||||
} else if (type.equals(Integer.class) || typeName.equals("int")) {
|
||||
} else if (type.equals(Integer.class) || "int".equals(typeName)) {
|
||||
result = bdValue.intValue();
|
||||
}
|
||||
} else
|
||||
@@ -95,17 +95,17 @@ public class SubscribeFieldToMQTTtopic implements MqttMessageSubscriber {
|
||||
// primitive types
|
||||
if (value instanceof String && !type.equals(String.class)) {
|
||||
String bdValue = (String) value;
|
||||
if (type.equals(Float.class) || typeName.equals("float")) {
|
||||
if (type.equals(Float.class) || "float".equals(typeName)) {
|
||||
result = Float.valueOf(bdValue);
|
||||
} else if (type.equals(Double.class) || typeName.equals("double")) {
|
||||
} else if (type.equals(Double.class) || "double".equals(typeName)) {
|
||||
result = Double.valueOf(bdValue);
|
||||
} else if (type.equals(Long.class) || typeName.equals("long")) {
|
||||
} else if (type.equals(Long.class) || "long".equals(typeName)) {
|
||||
result = Long.valueOf(bdValue);
|
||||
} else if (type.equals(BigDecimal.class)) {
|
||||
result = new BigDecimal(bdValue);
|
||||
} else if (type.equals(Integer.class) || typeName.equals("int")) {
|
||||
} else if (type.equals(Integer.class) || "int".equals(typeName)) {
|
||||
result = Integer.valueOf(bdValue);
|
||||
} else if (type.equals(Boolean.class) || typeName.equals("boolean")) {
|
||||
} else if (type.equals(Boolean.class) || "boolean".equals(typeName)) {
|
||||
result = Boolean.valueOf(bdValue);
|
||||
} else if (type.isEnum()) {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
|
||||
@@ -18,21 +18,24 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Collector to combine a stream of CompletableFutures.
|
||||
*
|
||||
* @author Jochen Klein - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FutureCollector {
|
||||
|
||||
public static <X> Collector<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<Void>> allOf() {
|
||||
return Collector.<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<Void>> of(
|
||||
public static <X> Collector<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<@Nullable Void>> allOf() {
|
||||
return Collector.<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<@Nullable Void>> of(
|
||||
(Supplier<Set<CompletableFuture<X>>>) HashSet::new, Set::add, (left, right) -> {
|
||||
left.addAll(right);
|
||||
return left;
|
||||
}, a -> {
|
||||
return CompletableFuture.allOf(a.toArray(new CompletableFuture[a.size()]));
|
||||
}, Collector.Characteristics.UNORDERED);
|
||||
}, a -> CompletableFuture.allOf(a.toArray(new CompletableFuture[a.size()])),
|
||||
Collector.Characteristics.UNORDERED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.ws.rs.NotSupportedException;
|
||||
|
||||
@@ -63,8 +62,7 @@ public class ColorValue extends Value {
|
||||
* @param onBrightness When receiving a ON command, the brightness percentage is set to this value
|
||||
*/
|
||||
public ColorValue(ColorMode colorMode, @Nullable String onValue, @Nullable String offValue, int onBrightness) {
|
||||
super(CoreItemFactory.COLOR,
|
||||
Stream.of(OnOffType.class, PercentType.class, StringType.class).collect(Collectors.toList()));
|
||||
super(CoreItemFactory.COLOR, List.of(OnOffType.class, PercentType.class, StringType.class));
|
||||
|
||||
if (onBrightness > 100) {
|
||||
throw new IllegalArgumentException("Brightness parameter must be <= 100");
|
||||
@@ -112,8 +110,8 @@ public class ColorValue extends Value {
|
||||
Integer.parseInt(split[2]));
|
||||
break;
|
||||
case XYY:
|
||||
HSBType temp_state = HSBType.fromXY(Float.parseFloat(split[0]), Float.parseFloat(split[1]));
|
||||
state = new HSBType(temp_state.getHue(), temp_state.getSaturation(), new PercentType(split[2]));
|
||||
HSBType tempState = HSBType.fromXY(Float.parseFloat(split[0]), Float.parseFloat(split[1]));
|
||||
state = new HSBType(tempState.getHue(), tempState.getSaturation(), new PercentType(split[2]));
|
||||
break;
|
||||
default:
|
||||
logger.warn("Non supported color mode");
|
||||
@@ -146,21 +144,21 @@ public class ColorValue extends Value {
|
||||
}
|
||||
}
|
||||
|
||||
HSBType hsb_state = (HSBType) state;
|
||||
HSBType hsbState = (HSBType) state;
|
||||
|
||||
switch (this.colorMode) {
|
||||
case HSB:
|
||||
return String.format(formatPattern, hsb_state.getHue().intValue(), hsb_state.getSaturation().intValue(),
|
||||
hsb_state.getBrightness().intValue());
|
||||
return String.format(formatPattern, hsbState.getHue().intValue(), hsbState.getSaturation().intValue(),
|
||||
hsbState.getBrightness().intValue());
|
||||
case RGB:
|
||||
PercentType[] rgb = hsb_state.toRGB();
|
||||
PercentType[] rgb = hsbState.toRGB();
|
||||
return String.format(formatPattern, rgb[0].toBigDecimal().multiply(factor).intValue(),
|
||||
rgb[1].toBigDecimal().multiply(factor).intValue(),
|
||||
rgb[2].toBigDecimal().multiply(factor).intValue());
|
||||
case XYY:
|
||||
PercentType[] xyY = hsb_state.toXY();
|
||||
PercentType[] xyY = hsbState.toXY();
|
||||
return String.format(Locale.ROOT, formatPattern, xyY[0].floatValue() / 100.0f,
|
||||
xyY[1].floatValue() / 100.0f, hsb_state.getBrightness().floatValue());
|
||||
xyY[1].floatValue() / 100.0f, hsbState.getBrightness().floatValue());
|
||||
default:
|
||||
throw new NotSupportedException(String.format("Non supported color mode: {}", this.colorMode));
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@@ -32,7 +31,7 @@ import org.openhab.core.types.UnDefType;
|
||||
@NonNullByDefault
|
||||
public class DateTimeValue extends Value {
|
||||
public DateTimeValue() {
|
||||
super(CoreItemFactory.DATETIME, Stream.of(DateTimeType.class, StringType.class).collect(Collectors.toList()));
|
||||
super(CoreItemFactory.DATETIME, List.of(DateTimeType.class, StringType.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.CoreItemFactory;
|
||||
@@ -26,7 +26,7 @@ import org.openhab.core.types.Command;
|
||||
@NonNullByDefault
|
||||
public class ImageValue extends Value {
|
||||
public ImageValue() {
|
||||
super(CoreItemFactory.IMAGE, Collections.emptyList());
|
||||
super(CoreItemFactory.IMAGE, List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,11 +13,9 @@
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.CoreItemFactory;
|
||||
@@ -33,11 +31,11 @@ import org.openhab.core.types.Command;
|
||||
@NonNullByDefault
|
||||
public class LocationValue extends Value {
|
||||
public LocationValue() {
|
||||
super(CoreItemFactory.LOCATION, Stream.of(PointType.class, StringType.class).collect(Collectors.toList()));
|
||||
super(CoreItemFactory.LOCATION, List.of(PointType.class, StringType.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String getMQTTpublishValue(@Nullable String pattern) {
|
||||
public String getMQTTpublishValue(@Nullable String pattern) {
|
||||
String formatPattern = pattern;
|
||||
PointType point = ((PointType) state);
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
@@ -53,8 +52,7 @@ public class NumberValue extends Value {
|
||||
|
||||
public NumberValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step,
|
||||
@Nullable Unit<?> unit) {
|
||||
super(CoreItemFactory.NUMBER, Stream.of(QuantityType.class, IncreaseDecreaseType.class, UpDownType.class)
|
||||
.collect(Collectors.toList()));
|
||||
super(CoreItemFactory.NUMBER, List.of(QuantityType.class, IncreaseDecreaseType.class, UpDownType.class));
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.step = step == null ? BigDecimal.ONE : step;
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@@ -65,7 +64,7 @@ public class OnOffValue extends Value {
|
||||
*/
|
||||
public OnOffValue(@Nullable String onState, @Nullable String offState, @Nullable String onCommand,
|
||||
@Nullable String offCommand) {
|
||||
super(CoreItemFactory.SWITCH, Stream.of(OnOffType.class, StringType.class).collect(Collectors.toList()));
|
||||
super(CoreItemFactory.SWITCH, List.of(OnOffType.class, StringType.class));
|
||||
this.onState = onState == null ? OnOffType.ON.name() : onState;
|
||||
this.offState = offState == null ? OnOffType.OFF.name() : offState;
|
||||
this.onCommand = onCommand == null ? OnOffType.ON.name() : onCommand;
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@@ -36,7 +35,7 @@ public class OpenCloseValue extends Value {
|
||||
* Creates a contact Open/Close type.
|
||||
*/
|
||||
public OpenCloseValue() {
|
||||
super(CoreItemFactory.CONTACT, Stream.of(OpenClosedType.class, StringType.class).collect(Collectors.toList()));
|
||||
super(CoreItemFactory.CONTACT, List.of(OpenClosedType.class, StringType.class));
|
||||
this.openString = OpenClosedType.OPEN.name();
|
||||
this.closeString = OpenClosedType.CLOSED.name();
|
||||
}
|
||||
@@ -48,7 +47,7 @@ public class OpenCloseValue extends Value {
|
||||
* @param closeValue The OFF value string. This will be compared to MQTT messages.
|
||||
*/
|
||||
public OpenCloseValue(@Nullable String openValue, @Nullable String closeValue) {
|
||||
super(CoreItemFactory.CONTACT, Stream.of(OpenClosedType.class, StringType.class).collect(Collectors.toList()));
|
||||
super(CoreItemFactory.CONTACT, List.of(OpenClosedType.class, StringType.class));
|
||||
this.openString = openValue == null ? OpenClosedType.OPEN.name() : openValue;
|
||||
this.closeString = closeValue == null ? OpenClosedType.CLOSED.name() : closeValue;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@@ -58,8 +57,8 @@ public class PercentageValue extends Value {
|
||||
|
||||
public PercentageValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step,
|
||||
@Nullable String onValue, @Nullable String offValue) {
|
||||
super(CoreItemFactory.DIMMER, Stream.of(DecimalType.class, QuantityType.class, IncreaseDecreaseType.class,
|
||||
OnOffType.class, UpDownType.class, StringType.class).collect(Collectors.toList()));
|
||||
super(CoreItemFactory.DIMMER, List.of(DecimalType.class, QuantityType.class, IncreaseDecreaseType.class,
|
||||
OnOffType.class, UpDownType.class, StringType.class));
|
||||
this.onValue = onValue;
|
||||
this.offValue = offValue;
|
||||
this.min = min == null ? BigDecimal.ZERO : min;
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@@ -51,8 +50,7 @@ public class RollershutterValue extends Value {
|
||||
*/
|
||||
public RollershutterValue(@Nullable String upString, @Nullable String downString, @Nullable String stopString) {
|
||||
super(CoreItemFactory.ROLLERSHUTTER,
|
||||
Stream.of(UpDownType.class, StopMoveType.class, PercentType.class, StringType.class)
|
||||
.collect(Collectors.toList()));
|
||||
List.of(UpDownType.class, StopMoveType.class, PercentType.class, StringType.class));
|
||||
this.upString = upString;
|
||||
this.downString = downString;
|
||||
this.stopString = stopString == null ? StopMoveType.STOP.name() : stopString;
|
||||
|
||||
@@ -14,7 +14,7 @@ package org.openhab.binding.mqtt.generic.values;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -45,7 +45,7 @@ public class TextValue extends Value {
|
||||
* will be allowed.
|
||||
*/
|
||||
public TextValue(String[] states) {
|
||||
super(CoreItemFactory.STRING, Collections.singletonList(StringType.class));
|
||||
super(CoreItemFactory.STRING, List.of(StringType.class));
|
||||
Set<String> s = Stream.of(states).filter(not(String::isBlank)).collect(Collectors.toSet());
|
||||
if (!s.isEmpty()) {
|
||||
this.states = s;
|
||||
@@ -55,7 +55,7 @@ public class TextValue extends Value {
|
||||
}
|
||||
|
||||
public TextValue() {
|
||||
super(CoreItemFactory.STRING, Collections.singletonList(StringType.class));
|
||||
super(CoreItemFactory.STRING, List.of(StringType.class));
|
||||
this.states = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,11 @@ import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
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.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -62,25 +61,26 @@ import org.openhab.core.thing.ChannelUID;
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
@NonNullByDefault
|
||||
public class ChannelStateTests {
|
||||
|
||||
private @Mock MqttBrokerConnection connection;
|
||||
private @Mock ChannelStateUpdateListener channelStateUpdateListener;
|
||||
private @Mock ChannelUID channelUID;
|
||||
private @Spy TextValue textValue;
|
||||
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||
private @Mock @NonNullByDefault({}) ChannelStateUpdateListener channelStateUpdateListenerMock;
|
||||
private @Mock @NonNullByDefault({}) ChannelUID channelUIDMock;
|
||||
private @Spy @NonNullByDefault({}) TextValue textValue;
|
||||
|
||||
private ScheduledExecutorService scheduler;
|
||||
private @NonNullByDefault({}) ScheduledExecutorService scheduler;
|
||||
|
||||
private ChannelConfig config = ChannelConfigBuilder.create("state", "command").build();
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
CompletableFuture<Void> voidFutureComplete = new CompletableFuture<>();
|
||||
CompletableFuture<@Nullable 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(), anyInt(),
|
||||
doReturn(voidFutureComplete).when(connectionMock).unsubscribeAll();
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).publish(any(), any(), anyInt(),
|
||||
anyBoolean());
|
||||
|
||||
scheduler = new ScheduledThreadPoolExecutor(1);
|
||||
@@ -92,74 +92,74 @@ public class ChannelStateTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noInteractionTimeoutTest() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, textValue, channelStateUpdateListener));
|
||||
c.start(connection, scheduler, 50).get(100, TimeUnit.MILLISECONDS);
|
||||
verify(connection).subscribe(eq("state"), eq(c));
|
||||
public void noInteractionTimeoutTest() throws Exception {
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, textValue, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, scheduler, 50).get(100, TimeUnit.MILLISECONDS);
|
||||
verify(connectionMock).subscribe(eq("state"), eq(c));
|
||||
c.stop().get();
|
||||
verify(connection).unsubscribe(eq("state"), eq(c));
|
||||
verify(connectionMock).unsubscribe(eq("state"), eq(c));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishFormatTest() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, textValue, channelStateUpdateListener));
|
||||
public void publishFormatTest() throws Exception {
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, textValue, channelStateUpdateListenerMock));
|
||||
|
||||
c.start(connection, scheduler, 0).get(50, TimeUnit.MILLISECONDS);
|
||||
verify(connection).subscribe(eq("state"), eq(c));
|
||||
c.start(connectionMock, scheduler, 0).get(50, TimeUnit.MILLISECONDS);
|
||||
verify(connectionMock).subscribe(eq("state"), eq(c));
|
||||
|
||||
c.publishValue(new StringType("UPDATE")).get();
|
||||
verify(connection).publish(eq("command"), argThat(p -> Arrays.equals(p, "UPDATE".getBytes())), anyInt(),
|
||||
verify(connectionMock).publish(eq("command"), argThat(p -> Arrays.equals(p, "UPDATE".getBytes())), anyInt(),
|
||||
eq(false));
|
||||
|
||||
c.config.formatBeforePublish = "prefix%s";
|
||||
c.publishValue(new StringType("UPDATE")).get();
|
||||
verify(connection).publish(eq("command"), argThat(p -> Arrays.equals(p, "prefixUPDATE".getBytes())), anyInt(),
|
||||
eq(false));
|
||||
verify(connectionMock).publish(eq("command"), argThat(p -> Arrays.equals(p, "prefixUPDATE".getBytes())),
|
||||
anyInt(), eq(false));
|
||||
|
||||
c.config.formatBeforePublish = "%1$s-%1$s";
|
||||
c.publishValue(new StringType("UPDATE")).get();
|
||||
verify(connection).publish(eq("command"), argThat(p -> Arrays.equals(p, "UPDATE-UPDATE".getBytes())), anyInt(),
|
||||
eq(false));
|
||||
verify(connectionMock).publish(eq("command"), argThat(p -> Arrays.equals(p, "UPDATE-UPDATE".getBytes())),
|
||||
anyInt(), eq(false));
|
||||
|
||||
c.config.formatBeforePublish = "%s";
|
||||
c.config.retained = true;
|
||||
c.publishValue(new StringType("UPDATE")).get();
|
||||
verify(connection).publish(eq("command"), any(), anyInt(), eq(true));
|
||||
verify(connectionMock).publish(eq("command"), any(), anyInt(), eq(true));
|
||||
|
||||
c.stop().get();
|
||||
verify(connection).unsubscribe(eq("state"), eq(c));
|
||||
verify(connectionMock).unsubscribe(eq("state"), eq(c));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveWildcardTest() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
public void receiveWildcardTest() throws Exception {
|
||||
ChannelState c = spy(new ChannelState(ChannelConfigBuilder.create("state/+/topic", "command").build(),
|
||||
channelUID, textValue, channelStateUpdateListener));
|
||||
channelUIDMock, textValue, channelStateUpdateListenerMock));
|
||||
|
||||
CompletableFuture<@Nullable Void> future = c.start(connection, scheduler, 100);
|
||||
CompletableFuture<@Nullable Void> future = c.start(connectionMock, scheduler, 100);
|
||||
c.processMessage("state/bla/topic", "A TEST".getBytes());
|
||||
future.get(300, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertThat(textValue.getChannelState().toString(), is("A TEST"));
|
||||
verify(channelStateUpdateListener).updateChannelState(eq(channelUID), any());
|
||||
verify(channelStateUpdateListenerMock).updateChannelState(eq(channelUIDMock), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveStringTest() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, textValue, channelStateUpdateListener));
|
||||
public void receiveStringTest() throws Exception {
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, textValue, channelStateUpdateListenerMock));
|
||||
|
||||
CompletableFuture<@Nullable Void> future = c.start(connection, scheduler, 100);
|
||||
CompletableFuture<@Nullable Void> future = c.start(connectionMock, scheduler, 100);
|
||||
c.processMessage("state", "A TEST".getBytes());
|
||||
future.get(300, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertThat(textValue.getChannelState().toString(), is("A TEST"));
|
||||
verify(channelStateUpdateListener).updateChannelState(eq(channelUID), any());
|
||||
verify(channelStateUpdateListenerMock).updateChannelState(eq(channelUIDMock), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveDecimalTest() {
|
||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10), null);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "15".getBytes());
|
||||
assertThat(value.getChannelState().toString(), is("15"));
|
||||
@@ -170,14 +170,14 @@ public class ChannelStateTests {
|
||||
c.processMessage("state", "DECREASE".getBytes());
|
||||
assertThat(value.getChannelState().toString(), is("15"));
|
||||
|
||||
verify(channelStateUpdateListener, times(3)).updateChannelState(eq(channelUID), any());
|
||||
verify(channelStateUpdateListenerMock, times(3)).updateChannelState(eq(channelUIDMock), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveDecimalFractionalTest() {
|
||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10.5), null);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "5.5".getBytes());
|
||||
assertThat(value.getChannelState().toString(), is("5.5"));
|
||||
@@ -189,8 +189,8 @@ public class ChannelStateTests {
|
||||
@Test
|
||||
public void receiveDecimalUnitTest() {
|
||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10), Units.WATT);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "15".getBytes());
|
||||
assertThat(value.getChannelState().toString(), is("15 W"));
|
||||
@@ -201,27 +201,27 @@ public class ChannelStateTests {
|
||||
c.processMessage("state", "DECREASE".getBytes());
|
||||
assertThat(value.getChannelState().toString(), is("15 W"));
|
||||
|
||||
verify(channelStateUpdateListener, times(3)).updateChannelState(eq(channelUID), any());
|
||||
verify(channelStateUpdateListenerMock, times(3)).updateChannelState(eq(channelUIDMock), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveDecimalAsPercentageUnitTest() {
|
||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10), Units.PERCENT);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "63.7".getBytes());
|
||||
assertThat(value.getChannelState().toString(), is("63.7 %"));
|
||||
|
||||
verify(channelStateUpdateListener, times(1)).updateChannelState(eq(channelUID), any());
|
||||
verify(channelStateUpdateListenerMock, times(1)).updateChannelState(eq(channelUIDMock), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receivePercentageTest() {
|
||||
PercentageValue value = new PercentageValue(new BigDecimal(-100), new BigDecimal(100), new BigDecimal(10), null,
|
||||
null);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "-100".getBytes()); // 0%
|
||||
assertThat(value.getChannelState().toString(), is("0"));
|
||||
@@ -241,8 +241,8 @@ public class ChannelStateTests {
|
||||
@Test
|
||||
public void receiveRGBColorTest() {
|
||||
ColorValue value = new ColorValue(ColorMode.RGB, "FON", "FOFF", 10);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "ON".getBytes()); // Normal on state
|
||||
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
||||
@@ -268,8 +268,8 @@ public class ChannelStateTests {
|
||||
@Test
|
||||
public void receiveHSBColorTest() {
|
||||
ColorValue value = new ColorValue(ColorMode.HSB, "FON", "FOFF", 10);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "ON".getBytes()); // Normal on state
|
||||
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
||||
@@ -291,8 +291,8 @@ public class ChannelStateTests {
|
||||
@Test
|
||||
public void receiveXYYColorTest() {
|
||||
ColorValue value = new ColorValue(ColorMode.XYY, "FON", "FOFF", 10);
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "ON".getBytes()); // Normal on state
|
||||
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
||||
@@ -317,8 +317,8 @@ public class ChannelStateTests {
|
||||
@Test
|
||||
public void receiveLocationTest() {
|
||||
LocationValue value = new LocationValue();
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
c.processMessage("state", "46.833974, 7.108433".getBytes());
|
||||
assertThat(value.getChannelState().toString(), is("46.833974,7.108433"));
|
||||
@@ -328,8 +328,8 @@ public class ChannelStateTests {
|
||||
@Test
|
||||
public void receiveDateTimeTest() {
|
||||
DateTimeValue value = new DateTimeValue();
|
||||
ChannelState subject = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
subject.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState subject = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
subject.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
ZonedDateTime zd = ZonedDateTime.now();
|
||||
String datetime = zd.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
@@ -345,10 +345,10 @@ public class ChannelStateTests {
|
||||
@Test
|
||||
public void receiveImageTest() {
|
||||
ImageValue value = new ImageValue();
|
||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
||||
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||
|
||||
byte[] payload = new byte[] { (byte) 0xFF, (byte) 0xD8, 0x01, 0x02, (byte) 0xFF, (byte) 0xD9 };
|
||||
byte[] payload = { (byte) 0xFF, (byte) 0xD8, 0x01, 0x02, (byte) 0xFF, (byte) 0xD9 };
|
||||
c.processMessage("state", payload);
|
||||
assertThat(value.getChannelState(), is(instanceOf(RawType.class)));
|
||||
assertThat(((RawType) value.getChannelState()).getMimeType(), is("image/jpeg"));
|
||||
|
||||
@@ -20,8 +20,8 @@ import static org.openhab.binding.mqtt.generic.internal.handler.ThingChannelCons
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -33,7 +33,6 @@ import org.openhab.binding.mqtt.generic.internal.handler.GenericMQTTThingHandler
|
||||
import org.openhab.binding.mqtt.handler.AbstractBrokerHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||
import org.openhab.core.io.transport.mqtt.MqttException;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
@@ -49,43 +48,44 @@ import org.openhab.core.transform.TransformationService;
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
@NonNullByDefault
|
||||
public class ChannelStateTransformationTests {
|
||||
|
||||
private @Mock TransformationService jsonPathService;
|
||||
private @Mock TransformationServiceProvider transformationServiceProvider;
|
||||
private @Mock ThingHandlerCallback callback;
|
||||
private @Mock Thing thing;
|
||||
private @Mock AbstractBrokerHandler bridgeHandler;
|
||||
private @Mock MqttBrokerConnection connection;
|
||||
private @Mock @NonNullByDefault({}) TransformationService jsonPathServiceMock;
|
||||
private @Mock @NonNullByDefault({}) TransformationServiceProvider transformationServiceProviderMock;
|
||||
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||
private @Mock @NonNullByDefault({}) Thing thingMock;
|
||||
private @Mock @NonNullByDefault({}) AbstractBrokerHandler bridgeHandlerMock;
|
||||
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||
|
||||
private GenericMQTTThingHandler thingHandler;
|
||||
private @NonNullByDefault({}) GenericMQTTThingHandler thingHandler;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws ConfigurationException, MqttException {
|
||||
public void setUp() throws Exception {
|
||||
ThingStatusInfo thingStatus = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
|
||||
// Mock the thing: We need the thingUID and the bridgeUID
|
||||
when(thing.getUID()).thenReturn(testGenericThing);
|
||||
when(thing.getChannels()).thenReturn(thingChannelListWithJson);
|
||||
when(thing.getStatusInfo()).thenReturn(thingStatus);
|
||||
when(thing.getConfiguration()).thenReturn(new Configuration());
|
||||
when(thingMock.getUID()).thenReturn(TEST_GENERIC_THING);
|
||||
when(thingMock.getChannels()).thenReturn(THING_CHANNEL_LIST_WITH_JSON);
|
||||
when(thingMock.getStatusInfo()).thenReturn(thingStatus);
|
||||
when(thingMock.getConfiguration()).thenReturn(new Configuration());
|
||||
|
||||
// Return the mocked connection object if the bridge handler is asked for it
|
||||
when(bridgeHandler.getConnectionAsync()).thenReturn(CompletableFuture.completedFuture(connection));
|
||||
when(bridgeHandlerMock.getConnectionAsync()).thenReturn(CompletableFuture.completedFuture(connectionMock));
|
||||
|
||||
CompletableFuture<Void> voidFutureComplete = new CompletableFuture<>();
|
||||
CompletableFuture<@Nullable 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(voidFutureComplete).when(connectionMock).unsubscribeAll();
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||
|
||||
thingHandler = spy(new GenericMQTTThingHandler(thing, mock(MqttChannelStateDescriptionProvider.class),
|
||||
transformationServiceProvider, 1500));
|
||||
when(transformationServiceProvider.getTransformationService(anyString())).thenReturn(jsonPathService);
|
||||
thingHandler = spy(new GenericMQTTThingHandler(thingMock, mock(MqttChannelStateDescriptionProvider.class),
|
||||
transformationServiceProviderMock, 1500));
|
||||
when(transformationServiceProviderMock.getTransformationService(anyString())).thenReturn(jsonPathServiceMock);
|
||||
|
||||
thingHandler.setCallback(callback);
|
||||
thingHandler.setCallback(callbackMock);
|
||||
// Return the bridge handler if the thing handler asks for it
|
||||
doReturn(bridgeHandler).when(thingHandler).getBridgeHandler();
|
||||
doReturn(bridgeHandlerMock).when(thingHandler).getBridgeHandler();
|
||||
|
||||
// We are by default online
|
||||
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
||||
@@ -93,31 +93,31 @@ public class ChannelStateTransformationTests {
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void initialize() throws MqttException {
|
||||
when(thing.getChannels()).thenReturn(thingChannelListWithJson);
|
||||
public void initialize() throws Exception {
|
||||
when(thingMock.getChannels()).thenReturn(THING_CHANNEL_LIST_WITH_JSON);
|
||||
|
||||
thingHandler.initialize();
|
||||
ChannelState channelConfig = thingHandler.getChannelState(textChannelUID);
|
||||
assertThat(channelConfig.transformationsIn.get(0).pattern, is(jsonPathPattern));
|
||||
ChannelState channelConfig = thingHandler.getChannelState(TEXT_CHANNEL_UID);
|
||||
assertThat(channelConfig.transformationsIn.get(0).pattern, is(JSON_PATH_PATTERN));
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void processMessageWithJSONPath() throws Exception {
|
||||
when(jsonPathService.transform(jsonPathPattern, jsonPathJSON)).thenReturn("23.2");
|
||||
when(jsonPathServiceMock.transform(JSON_PATH_PATTERN, JSON_PATH_JSON)).thenReturn("23.2");
|
||||
|
||||
thingHandler.initialize();
|
||||
ChannelState channelConfig = thingHandler.getChannelState(textChannelUID);
|
||||
ChannelState channelConfig = thingHandler.getChannelState(TEXT_CHANNEL_UID);
|
||||
channelConfig.setChannelStateUpdateListener(thingHandler);
|
||||
|
||||
ChannelStateTransformation transformation = channelConfig.transformationsIn.get(0);
|
||||
|
||||
byte payload[] = jsonPathJSON.getBytes();
|
||||
assertThat(transformation.pattern, is(jsonPathPattern));
|
||||
byte payload[] = JSON_PATH_JSON.getBytes();
|
||||
assertThat(transformation.pattern, is(JSON_PATH_PATTERN));
|
||||
// Test process message
|
||||
channelConfig.processMessage(channelConfig.getStateTopic(), payload);
|
||||
|
||||
verify(callback).stateUpdated(eq(textChannelUID), argThat(arg -> "23.2".equals(arg.toString())));
|
||||
verify(callbackMock).stateUpdated(eq(TEXT_CHANNEL_UID), argThat(arg -> "23.2".equals(arg.toString())));
|
||||
assertThat(channelConfig.getCache().getChannelState().toString(), is("23.2"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import static org.openhab.binding.mqtt.generic.internal.handler.ThingChannelCons
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -57,42 +59,43 @@ import org.openhab.core.types.RefreshType;
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
@NonNullByDefault
|
||||
public class GenericThingHandlerTests {
|
||||
|
||||
private @Mock ThingHandlerCallback callback;
|
||||
private @Mock Thing thing;
|
||||
private @Mock AbstractBrokerHandler bridgeHandler;
|
||||
private @Mock MqttBrokerConnection connection;
|
||||
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||
private @Mock @NonNullByDefault({}) Thing thingMock;
|
||||
private @Mock @NonNullByDefault({}) AbstractBrokerHandler bridgeHandlerMock;
|
||||
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||
|
||||
private GenericMQTTThingHandler thingHandler;
|
||||
private @NonNullByDefault({}) GenericMQTTThingHandler thingHandler;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
ThingStatusInfo thingStatus = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
|
||||
// Mock the thing: We need the thingUID and the bridgeUID
|
||||
when(thing.getUID()).thenReturn(testGenericThing);
|
||||
when(thing.getChannels()).thenReturn(thingChannelList);
|
||||
when(thing.getStatusInfo()).thenReturn(thingStatus);
|
||||
when(thing.getConfiguration()).thenReturn(new Configuration());
|
||||
when(thingMock.getUID()).thenReturn(TEST_GENERIC_THING);
|
||||
when(thingMock.getChannels()).thenReturn(THING_CHANNEL_LIST);
|
||||
when(thingMock.getStatusInfo()).thenReturn(thingStatus);
|
||||
when(thingMock.getConfiguration()).thenReturn(new Configuration());
|
||||
|
||||
// Return the mocked connection object if the bridge handler is asked for it
|
||||
when(bridgeHandler.getConnectionAsync()).thenReturn(CompletableFuture.completedFuture(connection));
|
||||
when(bridgeHandlerMock.getConnectionAsync()).thenReturn(CompletableFuture.completedFuture(connectionMock));
|
||||
|
||||
CompletableFuture<Void> voidFutureComplete = new CompletableFuture<>();
|
||||
CompletableFuture<@Nullable 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(), anyInt(),
|
||||
doReturn(voidFutureComplete).when(connectionMock).unsubscribeAll();
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).publish(any(), any(), anyInt(),
|
||||
anyBoolean());
|
||||
|
||||
thingHandler = spy(new GenericMQTTThingHandler(thing, mock(MqttChannelStateDescriptionProvider.class),
|
||||
thingHandler = spy(new GenericMQTTThingHandler(thingMock, mock(MqttChannelStateDescriptionProvider.class),
|
||||
mock(TransformationServiceProvider.class), 1500));
|
||||
thingHandler.setCallback(callback);
|
||||
thingHandler.setCallback(callbackMock);
|
||||
|
||||
// Return the bridge handler if the thing handler asks for it
|
||||
doReturn(bridgeHandler).when(thingHandler).getBridgeHandler();
|
||||
doReturn(bridgeHandlerMock).when(thingHandler).getBridgeHandler();
|
||||
|
||||
// The broker connection bridge is by default online
|
||||
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
||||
@@ -102,8 +105,8 @@ public class GenericThingHandlerTests {
|
||||
public void initializeWithUnknownThingUID() {
|
||||
ChannelConfig config = textConfiguration().as(ChannelConfig.class);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> thingHandler.createChannelState(config, new ChannelUID(testGenericThing, "test"),
|
||||
ValueFactory.createValueState(config, unknownChannel.getId())));
|
||||
() -> thingHandler.createChannelState(config, new ChannelUID(TEST_GENERIC_THING, "test"),
|
||||
ValueFactory.createValueState(config, UNKNOWN_CHANNEL.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -111,16 +114,16 @@ public class GenericThingHandlerTests {
|
||||
thingHandler.initialize();
|
||||
verify(thingHandler).bridgeStatusChanged(any());
|
||||
verify(thingHandler).start(any());
|
||||
assertThat(thingHandler.getConnection(), is(connection));
|
||||
assertThat(thingHandler.getConnection(), is(connectionMock));
|
||||
|
||||
ChannelState channelConfig = thingHandler.channelStateByChannelUID.get(textChannelUID);
|
||||
ChannelState channelConfig = thingHandler.channelStateByChannelUID.get(TEXT_CHANNEL_UID);
|
||||
assertThat(channelConfig.getStateTopic(), is("test/state"));
|
||||
assertThat(channelConfig.getCommandTopic(), is("test/command"));
|
||||
|
||||
verify(connection).subscribe(eq(channelConfig.getStateTopic()), eq(channelConfig));
|
||||
verify(connectionMock).subscribe(eq(channelConfig.getStateTopic()), eq(channelConfig));
|
||||
|
||||
verify(callback).statusUpdated(eq(thing), argThat((arg) -> arg.getStatus().equals(ThingStatus.ONLINE)
|
||||
&& arg.getStatusDetail().equals(ThingStatusDetail.NONE)));
|
||||
verify(callbackMock).statusUpdated(eq(thingMock), argThat(arg -> ThingStatus.ONLINE.equals(arg.getStatus())
|
||||
&& ThingStatusDetail.NONE.equals(arg.getStatusDetail())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -135,24 +138,24 @@ public class GenericThingHandlerTests {
|
||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||
thingHandler.initialize();
|
||||
|
||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
||||
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||
|
||||
thingHandler.handleCommand(textChannelUID, RefreshType.REFRESH);
|
||||
verify(callback).stateUpdated(eq(textChannelUID), argThat(arg -> "DEMOVALUE".equals(arg.toString())));
|
||||
thingHandler.handleCommand(TEXT_CHANNEL_UID, RefreshType.REFRESH);
|
||||
verify(callbackMock).stateUpdated(eq(TEXT_CHANNEL_UID), argThat(arg -> "DEMOVALUE".equals(arg.toString())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleCommandUpdateString() {
|
||||
TextValue value = spy(new TextValue());
|
||||
ChannelState channelConfig = spy(
|
||||
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), textChannelUID,
|
||||
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), TEXT_CHANNEL_UID,
|
||||
value, thingHandler));
|
||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||
thingHandler.initialize();
|
||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
||||
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||
|
||||
StringType updateValue = new StringType("UPDATE");
|
||||
thingHandler.handleCommand(textChannelUID, updateValue);
|
||||
thingHandler.handleCommand(TEXT_CHANNEL_UID, updateValue);
|
||||
verify(value).update(eq(updateValue));
|
||||
assertThat(channelConfig.getCache().getChannelState().toString(), is("UPDATE"));
|
||||
}
|
||||
@@ -161,14 +164,14 @@ public class GenericThingHandlerTests {
|
||||
public void handleCommandUpdateBoolean() {
|
||||
OnOffValue value = spy(new OnOffValue("ON", "OFF"));
|
||||
ChannelState channelConfig = spy(
|
||||
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), textChannelUID,
|
||||
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), TEXT_CHANNEL_UID,
|
||||
value, thingHandler));
|
||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||
thingHandler.initialize();
|
||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
||||
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||
|
||||
StringType updateValue = new StringType("ON");
|
||||
thingHandler.handleCommand(textChannelUID, updateValue);
|
||||
thingHandler.handleCommand(TEXT_CHANNEL_UID, updateValue);
|
||||
|
||||
verify(value).update(eq(updateValue));
|
||||
assertThat(channelConfig.getCache().getChannelState(), is(OnOffType.ON));
|
||||
@@ -178,7 +181,7 @@ public class GenericThingHandlerTests {
|
||||
public void processMessage() {
|
||||
TextValue textValue = new TextValue();
|
||||
ChannelState channelConfig = spy(
|
||||
new ChannelState(ChannelConfigBuilder.create("test/state", "test/state/set").build(), textChannelUID,
|
||||
new ChannelState(ChannelConfigBuilder.create("test/state", "test/state/set").build(), TEXT_CHANNEL_UID,
|
||||
textValue, thingHandler));
|
||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||
thingHandler.initialize();
|
||||
@@ -186,10 +189,10 @@ public class GenericThingHandlerTests {
|
||||
// Test process message
|
||||
channelConfig.processMessage("test/state", payload);
|
||||
|
||||
verify(callback, atLeastOnce()).statusUpdated(eq(thing),
|
||||
argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE)));
|
||||
verify(callbackMock, atLeastOnce()).statusUpdated(eq(thingMock),
|
||||
argThat(arg -> ThingStatus.ONLINE.equals(arg.getStatus())));
|
||||
|
||||
verify(callback).stateUpdated(eq(textChannelUID), argThat(arg -> "UPDATE".equals(arg.toString())));
|
||||
verify(callbackMock).stateUpdated(eq(TEXT_CHANNEL_UID), argThat(arg -> "UPDATE".equals(arg.toString())));
|
||||
assertThat(textValue.getChannelState().toString(), is("UPDATE"));
|
||||
}
|
||||
|
||||
@@ -197,11 +200,11 @@ public class GenericThingHandlerTests {
|
||||
public void handleBridgeStatusChange() {
|
||||
Configuration config = new Configuration();
|
||||
config.put("availabilityTopic", "test/LWT");
|
||||
when(thing.getConfiguration()).thenReturn(config);
|
||||
when(thingMock.getConfiguration()).thenReturn(config);
|
||||
thingHandler.initialize();
|
||||
thingHandler
|
||||
.bridgeStatusChanged(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, null));
|
||||
thingHandler.bridgeStatusChanged(new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null));
|
||||
verify(connection, times(2)).subscribe(eq("test/LWT"), any());
|
||||
verify(connectionMock, times(2)).subscribe(eq("test/LWT"), any());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,23 +37,23 @@ import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
@NonNullByDefault
|
||||
public class ThingChannelConstants {
|
||||
// Common ThingUID and ChannelUIDs
|
||||
public static final ThingUID testGenericThing = new ThingUID(GENERIC_MQTT_THING, "genericthing");
|
||||
public static final ThingUID TEST_GENERIC_THING = new ThingUID(GENERIC_MQTT_THING, "genericthing");
|
||||
|
||||
public static final ChannelTypeUID textChannel = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.STRING);
|
||||
public static final ChannelTypeUID textWithJsonChannel = new ChannelTypeUID(BINDING_ID,
|
||||
public static final ChannelTypeUID TEXT_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.STRING);
|
||||
public static final ChannelTypeUID TEXT_WITH_JSON_CHANNEL = new ChannelTypeUID(BINDING_ID,
|
||||
MqttBindingConstants.STRING);
|
||||
public static final ChannelTypeUID onoffChannel = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.SWITCH);
|
||||
public static final ChannelTypeUID numberChannel = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.NUMBER);
|
||||
public static final ChannelTypeUID percentageChannel = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.DIMMER);
|
||||
public static final ChannelTypeUID unknownChannel = new ChannelTypeUID(BINDING_ID, "unknown");
|
||||
public static final ChannelTypeUID ON_OFF_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.SWITCH);
|
||||
public static final ChannelTypeUID NUMBER_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.NUMBER);
|
||||
public static final ChannelTypeUID PERCENTAGE_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.DIMMER);
|
||||
public static final ChannelTypeUID UNKNOWN_CHANNEL = new ChannelTypeUID(BINDING_ID, "unknown");
|
||||
|
||||
public static final ChannelUID textChannelUID = new ChannelUID(testGenericThing, "mytext");
|
||||
public static final ChannelUID TEXT_CHANNEL_UID = new ChannelUID(TEST_GENERIC_THING, "mytext");
|
||||
|
||||
public static final String jsonPathJSON = "{ \"device\": { \"status\": { \"temperature\": 23.2 }}}";
|
||||
public static final String jsonPathPattern = "$.device.status.temperature";
|
||||
public static final String JSON_PATH_JSON = "{ \"device\": { \"status\": { \"temperature\": 23.2 }}}";
|
||||
public static final String JSON_PATH_PATTERN = "$.device.status.temperature";
|
||||
|
||||
public static final List<Channel> thingChannelList = new ArrayList<>();
|
||||
public static final List<Channel> thingChannelListWithJson = new ArrayList<>();
|
||||
public static final List<Channel> THING_CHANNEL_LIST = new ArrayList<>();
|
||||
public static final List<Channel> THING_CHANNEL_LIST_WITH_JSON = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Create a channel with exact the parameters we need for the tests
|
||||
@@ -65,20 +65,21 @@ public class ThingChannelConstants {
|
||||
* @return
|
||||
*/
|
||||
public static Channel cb(String id, String acceptedType, Configuration config, ChannelTypeUID channelTypeUID) {
|
||||
return ChannelBuilder.create(new ChannelUID(testGenericThing, id), acceptedType).withConfiguration(config)
|
||||
return ChannelBuilder.create(new ChannelUID(TEST_GENERIC_THING, id), acceptedType).withConfiguration(config)
|
||||
.withType(channelTypeUID).build();
|
||||
}
|
||||
|
||||
static {
|
||||
thingChannelList.add(cb("mytext", "TextItemType", textConfiguration(), textChannel));
|
||||
thingChannelList.add(cb("onoff", "OnOffType", onoffConfiguration(), onoffChannel));
|
||||
thingChannelList.add(cb("num", "NumberType", numberConfiguration(), numberChannel));
|
||||
thingChannelList.add(cb("percent", "NumberType", percentageConfiguration(), percentageChannel));
|
||||
THING_CHANNEL_LIST.add(cb("mytext", "TextItemType", textConfiguration(), TEXT_CHANNEL));
|
||||
THING_CHANNEL_LIST.add(cb("onoff", "OnOffType", onoffConfiguration(), ON_OFF_CHANNEL));
|
||||
THING_CHANNEL_LIST.add(cb("num", "NumberType", numberConfiguration(), NUMBER_CHANNEL));
|
||||
THING_CHANNEL_LIST.add(cb("percent", "NumberType", percentageConfiguration(), PERCENTAGE_CHANNEL));
|
||||
|
||||
thingChannelListWithJson.add(cb("mytext", "TextItemType", textConfigurationWithJson(), textWithJsonChannel));
|
||||
thingChannelListWithJson.add(cb("onoff", "OnOffType", onoffConfiguration(), onoffChannel));
|
||||
thingChannelListWithJson.add(cb("num", "NumberType", numberConfiguration(), numberChannel));
|
||||
thingChannelListWithJson.add(cb("percent", "NumberType", percentageConfiguration(), percentageChannel));
|
||||
THING_CHANNEL_LIST_WITH_JSON
|
||||
.add(cb("mytext", "TextItemType", textConfigurationWithJson(), TEXT_WITH_JSON_CHANNEL));
|
||||
THING_CHANNEL_LIST_WITH_JSON.add(cb("onoff", "OnOffType", onoffConfiguration(), ON_OFF_CHANNEL));
|
||||
THING_CHANNEL_LIST_WITH_JSON.add(cb("num", "NumberType", numberConfiguration(), NUMBER_CHANNEL));
|
||||
THING_CHANNEL_LIST_WITH_JSON.add(cb("percent", "NumberType", percentageConfiguration(), PERCENTAGE_CHANNEL));
|
||||
}
|
||||
|
||||
static Configuration textConfiguration() {
|
||||
@@ -92,7 +93,7 @@ public class ThingChannelConstants {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("stateTopic", "test/state");
|
||||
data.put("commandTopic", "test/command");
|
||||
data.put("transformationPattern", "JSONPATH:" + jsonPathPattern);
|
||||
data.put("transformationPattern", "JSONPATH:" + JSON_PATH_PATTERN);
|
||||
return new Configuration(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -60,6 +60,7 @@ import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
@NonNullByDefault
|
||||
public class MqttTopicClassMapperTests {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ FIELD })
|
||||
@@ -72,15 +73,15 @@ public class MqttTopicClassMapperTests {
|
||||
public transient String ignoreTransient = "";
|
||||
public final String ignoreFinal = "";
|
||||
|
||||
public @TestValue("string") String aString;
|
||||
public @TestValue("false") Boolean aBoolean;
|
||||
public @TestValue("10") Long aLong;
|
||||
public @TestValue("10") Integer aInteger;
|
||||
public @TestValue("10") BigDecimal aDecimal;
|
||||
public @TestValue("string") @Nullable String aString;
|
||||
public @TestValue("false") @Nullable Boolean aBoolean;
|
||||
public @TestValue("10") @Nullable Long aLong;
|
||||
public @TestValue("10") @Nullable Integer aInteger;
|
||||
public @TestValue("10") @Nullable BigDecimal aDecimal;
|
||||
|
||||
public @TestValue("10") @TopicPrefix("a") int Int = 24;
|
||||
public @TestValue("10") @TopicPrefix("a") int aInt = 24;
|
||||
public @TestValue("false") boolean aBool = true;
|
||||
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String[] properties;
|
||||
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String @Nullable [] properties;
|
||||
|
||||
public enum ReadyState {
|
||||
unknown,
|
||||
@@ -99,22 +100,16 @@ public class MqttTopicClassMapperTests {
|
||||
public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
|
||||
|
||||
@Override
|
||||
public @NonNull Object getFieldsOf() {
|
||||
public Object getFieldsOf() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Mock
|
||||
MqttBrokerConnection connection;
|
||||
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||
private @Mock @NonNullByDefault({}) ScheduledExecutorService executorMock;
|
||||
private @Mock @NonNullByDefault({}) AttributeChanged fieldChangedObserverMock;
|
||||
private @Spy Object countInjectedFields = new Object();
|
||||
|
||||
@Mock
|
||||
ScheduledExecutorService executor;
|
||||
|
||||
@Mock
|
||||
AttributeChanged fieldChangedObserver;
|
||||
|
||||
@Spy
|
||||
Object countInjectedFields = new Object();
|
||||
int injectedFields = 0;
|
||||
|
||||
// A completed future is returned for a subscribe call to the attributes
|
||||
@@ -122,8 +117,8 @@ public class MqttTopicClassMapperTests {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||
injectedFields = (int) Stream.of(countInjectedFields.getClass().getDeclaredFields())
|
||||
.filter(AbstractMqttAttributeClass::filterField).count();
|
||||
}
|
||||
@@ -148,8 +143,8 @@ public class MqttTopicClassMapperTests {
|
||||
anyBoolean());
|
||||
|
||||
// Subscribe now to all fields
|
||||
CompletableFuture<Void> future = attributes.subscribeAndReceive(connection, executor, "homie/device123", null,
|
||||
10);
|
||||
CompletableFuture<@Nullable Void> future = attributes.subscribeAndReceive(connectionMock, executorMock,
|
||||
"homie/device123", null, 10);
|
||||
assertThat(future.isDone(), is(true));
|
||||
assertThat(attributes.subscriptions.size(), is(10 + injectedFields));
|
||||
}
|
||||
@@ -157,17 +152,17 @@ public class MqttTopicClassMapperTests {
|
||||
// TODO timeout
|
||||
@SuppressWarnings({ "null", "unused" })
|
||||
@Test
|
||||
public void subscribeAndReceive() throws IllegalArgumentException, IllegalAccessException {
|
||||
public void subscribeAndReceive() throws Exception {
|
||||
final Attributes attributes = spy(new Attributes());
|
||||
|
||||
doAnswer(this::createSubscriberAnswer).when(attributes).createSubscriber(any(), any(), anyString(),
|
||||
anyBoolean());
|
||||
|
||||
verify(connection, times(0)).subscribe(anyString(), any());
|
||||
verify(connectionMock, times(0)).subscribe(anyString(), any());
|
||||
|
||||
// Subscribe now to all fields
|
||||
CompletableFuture<Void> future = attributes.subscribeAndReceive(connection, executor, "homie/device123",
|
||||
fieldChangedObserver, 10);
|
||||
CompletableFuture<@Nullable Void> future = attributes.subscribeAndReceive(connectionMock, executorMock,
|
||||
"homie/device123", fieldChangedObserverMock, 10);
|
||||
assertThat(future.isDone(), is(true));
|
||||
|
||||
// We expect 10 subscriptions now
|
||||
@@ -190,7 +185,7 @@ public class MqttTopicClassMapperTests {
|
||||
|
||||
// Simulate a received MQTT value and use the annotation data as input.
|
||||
f.processMessage(f.topic, annotation.value().getBytes());
|
||||
verify(fieldChangedObserver, times(++loopCounter)).attributeChanged(any(), any(), any(), any(),
|
||||
verify(fieldChangedObserverMock, times(++loopCounter)).attributeChanged(any(), any(), any(), any(),
|
||||
anyBoolean());
|
||||
|
||||
// Check each value if the assignment worked
|
||||
@@ -213,23 +208,23 @@ public class MqttTopicClassMapperTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresInvalidEnum() throws IllegalArgumentException, IllegalAccessException {
|
||||
public void ignoresInvalidEnum() throws Exception {
|
||||
final Attributes attributes = spy(new Attributes());
|
||||
|
||||
doAnswer(this::createSubscriberAnswer).when(attributes).createSubscriber(any(), any(), anyString(),
|
||||
anyBoolean());
|
||||
|
||||
verify(connection, times(0)).subscribe(anyString(), any());
|
||||
verify(connectionMock, times(0)).subscribe(anyString(), any());
|
||||
|
||||
// Subscribe now to all fields
|
||||
CompletableFuture<Void> future = attributes.subscribeAndReceive(connection, executor, "homie/device123",
|
||||
fieldChangedObserver, 10);
|
||||
CompletableFuture<@Nullable Void> future = attributes.subscribeAndReceive(connectionMock, executorMock,
|
||||
"homie/device123", fieldChangedObserverMock, 10);
|
||||
assertThat(future.isDone(), is(true));
|
||||
|
||||
SubscribeFieldToMQTTtopic field = attributes.subscriptions.stream().filter(f -> f.field.getName() == "state")
|
||||
.findFirst().get();
|
||||
field.processMessage(field.topic, "garbage".getBytes());
|
||||
verify(fieldChangedObserver, times(0)).attributeChanged(any(), any(), any(), any(), anyBoolean());
|
||||
verify(fieldChangedObserverMock, times(0)).attributeChanged(any(), any(), any(), any(), anyBoolean());
|
||||
assertThat(attributes.state.toString(), is("unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -50,6 +50,7 @@ import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
@NonNullByDefault
|
||||
public class SubscribeFieldToMQTTtopicTests {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ FIELD })
|
||||
@@ -64,15 +65,15 @@ public class SubscribeFieldToMQTTtopicTests {
|
||||
@SuppressWarnings("unused")
|
||||
public final String ignoreFinal = "";
|
||||
|
||||
public @TestValue("string") String aString;
|
||||
public @TestValue("false") Boolean aBoolean;
|
||||
public @TestValue("10") Long aLong;
|
||||
public @TestValue("10") Integer aInteger;
|
||||
public @TestValue("10") BigDecimal aDecimal;
|
||||
public @TestValue("string") @Nullable String aString;
|
||||
public @TestValue("false") @Nullable Boolean aBoolean;
|
||||
public @TestValue("10") @Nullable Long aLong;
|
||||
public @TestValue("10") @Nullable Integer aInteger;
|
||||
public @TestValue("10") @Nullable BigDecimal aDecimal;
|
||||
|
||||
public @TestValue("10") @TopicPrefix("a") int Int = 24;
|
||||
public @TestValue("10") @TopicPrefix("a") int aInt = 24;
|
||||
public @TestValue("false") boolean aBool = true;
|
||||
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String[] properties;
|
||||
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String @Nullable [] properties;
|
||||
|
||||
public enum ReadyState {
|
||||
unknown,
|
||||
@@ -91,53 +92,44 @@ public class SubscribeFieldToMQTTtopicTests {
|
||||
public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
|
||||
|
||||
@Override
|
||||
public @NonNull Object getFieldsOf() {
|
||||
public Object getFieldsOf() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
Attributes attributes = new Attributes();
|
||||
|
||||
@Mock
|
||||
MqttBrokerConnection connection;
|
||||
|
||||
@Mock
|
||||
SubscribeFieldToMQTTtopic fieldSubscriber;
|
||||
|
||||
@Mock
|
||||
FieldChanged fieldChanged;
|
||||
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||
private @Mock @NonNullByDefault({}) FieldChanged fieldChangedMock;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
||||
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TimeoutIfNoMessageReceive()
|
||||
throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
|
||||
final Field field = Attributes.class.getField("Int");
|
||||
public void timeoutIfNoMessageReceive() throws Exception {
|
||||
final Field field = Attributes.class.getField("aInt");
|
||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChanged,
|
||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChangedMock,
|
||||
"homie/device123", false);
|
||||
assertThrows(TimeoutException.class,
|
||||
() -> subscriber.subscribeAndReceive(connection, 1000).get(50, TimeUnit.MILLISECONDS));
|
||||
() -> subscriber.subscribeAndReceive(connectionMock, 1000).get(50, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void MandatoryMissing()
|
||||
throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
|
||||
final Field field = Attributes.class.getField("Int");
|
||||
public void mandatoryMissing() throws Exception {
|
||||
final Field field = Attributes.class.getField("aInt");
|
||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChanged,
|
||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChangedMock,
|
||||
"homie/device123", true);
|
||||
assertThrows(ExecutionException.class, () -> subscriber.subscribeAndReceive(connection, 50).get());
|
||||
assertThrows(ExecutionException.class, () -> subscriber.subscribeAndReceive(connectionMock, 50).get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void MessageReceive()
|
||||
throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
|
||||
public void messageReceive() throws Exception {
|
||||
final FieldChanged changed = (field, value) -> {
|
||||
try {
|
||||
field.set(attributes.getFieldsOf(), value);
|
||||
@@ -145,17 +137,17 @@ public class SubscribeFieldToMQTTtopicTests {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
};
|
||||
final Field field = Attributes.class.getField("Int");
|
||||
final Field field = Attributes.class.getField("aInt");
|
||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, changed,
|
||||
"homie/device123", false);
|
||||
CompletableFuture<@Nullable Void> future = subscriber.subscribeAndReceive(connection, 1000);
|
||||
CompletableFuture<@Nullable Void> future = subscriber.subscribeAndReceive(connectionMock, 1000);
|
||||
|
||||
// Simulate a received MQTT message
|
||||
subscriber.processMessage("ignored", "10".getBytes());
|
||||
// No timeout should happen
|
||||
future.get(50, TimeUnit.MILLISECONDS);
|
||||
assertThat(attributes.Int, is(10));
|
||||
assertThat(attributes.aInt, is(10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.mqtt.generic.mapping.ColorMode;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
@@ -44,9 +46,10 @@ import org.openhab.core.types.TypeParser;
|
||||
*
|
||||
* @author David Graeff - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ValueTests {
|
||||
Command p(Value v, String str) {
|
||||
return TypeParser.parseCommand(v.getSupportedCommandTypes(), str);
|
||||
private Command p(Value v, String str) {
|
||||
return Objects.requireNonNull(TypeParser.parseCommand(v.getSupportedCommandTypes(), str));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user