mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[mqtt] Fix most SAT findings (#12492)
Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
parent
af8202e668
commit
a6f5b48dd5
@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
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.binding.mqtt.generic.values.OnOffValue;
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
@ -327,8 +326,8 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAvailabilityTopic(@NonNull String availability_topic) {
|
public void removeAvailabilityTopic(String availabilityTopic) {
|
||||||
availabilityStates.computeIfPresent(availability_topic, (topic, state) -> {
|
availabilityStates.computeIfPresent(availabilityTopic, (topic, state) -> {
|
||||||
if (connection != null && state != null) {
|
if (connection != null && state != null) {
|
||||||
state.stop();
|
state.stop();
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.generic.mapping;
|
package org.openhab.binding.mqtt.generic.mapping;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color modes supported by the binding.
|
* Color modes supported by the binding.
|
||||||
*
|
*
|
||||||
* @author Aitor Iturrioz - Initial contribution
|
* @author Aitor Iturrioz - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public enum ColorMode {
|
public enum ColorMode {
|
||||||
HSB,
|
HSB,
|
||||||
RGB,
|
RGB,
|
||||||
|
@ -81,13 +81,13 @@ public class SubscribeFieldToMQTTtopic implements MqttMessageSubscriber {
|
|||||||
String typeName = type.getSimpleName();
|
String typeName = type.getSimpleName();
|
||||||
if (value instanceof BigDecimal && !type.equals(BigDecimal.class)) {
|
if (value instanceof BigDecimal && !type.equals(BigDecimal.class)) {
|
||||||
BigDecimal bdValue = (BigDecimal) value;
|
BigDecimal bdValue = (BigDecimal) value;
|
||||||
if (type.equals(Float.class) || typeName.equals("float")) {
|
if (type.equals(Float.class) || "float".equals(typeName)) {
|
||||||
result = bdValue.floatValue();
|
result = bdValue.floatValue();
|
||||||
} else if (type.equals(Double.class) || typeName.equals("double")) {
|
} else if (type.equals(Double.class) || "double".equals(typeName)) {
|
||||||
result = bdValue.doubleValue();
|
result = bdValue.doubleValue();
|
||||||
} else if (type.equals(Long.class) || typeName.equals("long")) {
|
} else if (type.equals(Long.class) || "long".equals(typeName)) {
|
||||||
result = bdValue.longValue();
|
result = bdValue.longValue();
|
||||||
} else if (type.equals(Integer.class) || typeName.equals("int")) {
|
} else if (type.equals(Integer.class) || "int".equals(typeName)) {
|
||||||
result = bdValue.intValue();
|
result = bdValue.intValue();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@ -95,17 +95,17 @@ public class SubscribeFieldToMQTTtopic implements MqttMessageSubscriber {
|
|||||||
// primitive types
|
// primitive types
|
||||||
if (value instanceof String && !type.equals(String.class)) {
|
if (value instanceof String && !type.equals(String.class)) {
|
||||||
String bdValue = (String) value;
|
String bdValue = (String) value;
|
||||||
if (type.equals(Float.class) || typeName.equals("float")) {
|
if (type.equals(Float.class) || "float".equals(typeName)) {
|
||||||
result = Float.valueOf(bdValue);
|
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);
|
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);
|
result = Long.valueOf(bdValue);
|
||||||
} else if (type.equals(BigDecimal.class)) {
|
} else if (type.equals(BigDecimal.class)) {
|
||||||
result = new BigDecimal(bdValue);
|
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);
|
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);
|
result = Boolean.valueOf(bdValue);
|
||||||
} else if (type.isEnum()) {
|
} else if (type.isEnum()) {
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
@ -18,21 +18,24 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collector;
|
import java.util.stream.Collector;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collector to combine a stream of CompletableFutures.
|
* Collector to combine a stream of CompletableFutures.
|
||||||
*
|
*
|
||||||
* @author Jochen Klein - Initial contribution
|
* @author Jochen Klein - Initial contribution
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class FutureCollector {
|
public class FutureCollector {
|
||||||
|
|
||||||
public static <X> Collector<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<Void>> allOf() {
|
public static <X> Collector<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<@Nullable Void>> allOf() {
|
||||||
return Collector.<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<Void>> of(
|
return Collector.<CompletableFuture<X>, Set<CompletableFuture<X>>, CompletableFuture<@Nullable Void>> of(
|
||||||
(Supplier<Set<CompletableFuture<X>>>) HashSet::new, Set::add, (left, right) -> {
|
(Supplier<Set<CompletableFuture<X>>>) HashSet::new, Set::add, (left, right) -> {
|
||||||
left.addAll(right);
|
left.addAll(right);
|
||||||
return left;
|
return left;
|
||||||
}, a -> {
|
}, a -> CompletableFuture.allOf(a.toArray(new CompletableFuture[a.size()])),
|
||||||
return CompletableFuture.allOf(a.toArray(new CompletableFuture[a.size()]));
|
Collector.Characteristics.UNORDERED);
|
||||||
}, Collector.Characteristics.UNORDERED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,8 @@
|
|||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import javax.ws.rs.NotSupportedException;
|
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
|
* @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) {
|
public ColorValue(ColorMode colorMode, @Nullable String onValue, @Nullable String offValue, int onBrightness) {
|
||||||
super(CoreItemFactory.COLOR,
|
super(CoreItemFactory.COLOR, List.of(OnOffType.class, PercentType.class, StringType.class));
|
||||||
Stream.of(OnOffType.class, PercentType.class, StringType.class).collect(Collectors.toList()));
|
|
||||||
|
|
||||||
if (onBrightness > 100) {
|
if (onBrightness > 100) {
|
||||||
throw new IllegalArgumentException("Brightness parameter must be <= 100");
|
throw new IllegalArgumentException("Brightness parameter must be <= 100");
|
||||||
@ -112,8 +110,8 @@ public class ColorValue extends Value {
|
|||||||
Integer.parseInt(split[2]));
|
Integer.parseInt(split[2]));
|
||||||
break;
|
break;
|
||||||
case XYY:
|
case XYY:
|
||||||
HSBType temp_state = HSBType.fromXY(Float.parseFloat(split[0]), Float.parseFloat(split[1]));
|
HSBType tempState = HSBType.fromXY(Float.parseFloat(split[0]), Float.parseFloat(split[1]));
|
||||||
state = new HSBType(temp_state.getHue(), temp_state.getSaturation(), new PercentType(split[2]));
|
state = new HSBType(tempState.getHue(), tempState.getSaturation(), new PercentType(split[2]));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.warn("Non supported color mode");
|
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) {
|
switch (this.colorMode) {
|
||||||
case HSB:
|
case HSB:
|
||||||
return String.format(formatPattern, hsb_state.getHue().intValue(), hsb_state.getSaturation().intValue(),
|
return String.format(formatPattern, hsbState.getHue().intValue(), hsbState.getSaturation().intValue(),
|
||||||
hsb_state.getBrightness().intValue());
|
hsbState.getBrightness().intValue());
|
||||||
case RGB:
|
case RGB:
|
||||||
PercentType[] rgb = hsb_state.toRGB();
|
PercentType[] rgb = hsbState.toRGB();
|
||||||
return String.format(formatPattern, rgb[0].toBigDecimal().multiply(factor).intValue(),
|
return String.format(formatPattern, rgb[0].toBigDecimal().multiply(factor).intValue(),
|
||||||
rgb[1].toBigDecimal().multiply(factor).intValue(),
|
rgb[1].toBigDecimal().multiply(factor).intValue(),
|
||||||
rgb[2].toBigDecimal().multiply(factor).intValue());
|
rgb[2].toBigDecimal().multiply(factor).intValue());
|
||||||
case XYY:
|
case XYY:
|
||||||
PercentType[] xyY = hsb_state.toXY();
|
PercentType[] xyY = hsbState.toXY();
|
||||||
return String.format(Locale.ROOT, formatPattern, xyY[0].floatValue() / 100.0f,
|
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:
|
default:
|
||||||
throw new NotSupportedException(String.format("Non supported color mode: {}", this.colorMode));
|
throw new NotSupportedException(String.format("Non supported color mode: {}", this.colorMode));
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
@ -32,7 +31,7 @@ import org.openhab.core.types.UnDefType;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class DateTimeValue extends Value {
|
public class DateTimeValue extends Value {
|
||||||
public DateTimeValue() {
|
public DateTimeValue() {
|
||||||
super(CoreItemFactory.DATETIME, Stream.of(DateTimeType.class, StringType.class).collect(Collectors.toList()));
|
super(CoreItemFactory.DATETIME, List.of(DateTimeType.class, StringType.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.library.CoreItemFactory;
|
import org.openhab.core.library.CoreItemFactory;
|
||||||
@ -26,7 +26,7 @@ import org.openhab.core.types.Command;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class ImageValue extends Value {
|
public class ImageValue extends Value {
|
||||||
public ImageValue() {
|
public ImageValue() {
|
||||||
super(CoreItemFactory.IMAGE, Collections.emptyList());
|
super(CoreItemFactory.IMAGE, List.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -13,11 +13,9 @@
|
|||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.library.CoreItemFactory;
|
import org.openhab.core.library.CoreItemFactory;
|
||||||
@ -33,11 +31,11 @@ import org.openhab.core.types.Command;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LocationValue extends Value {
|
public class LocationValue extends Value {
|
||||||
public LocationValue() {
|
public LocationValue() {
|
||||||
super(CoreItemFactory.LOCATION, Stream.of(PointType.class, StringType.class).collect(Collectors.toList()));
|
super(CoreItemFactory.LOCATION, List.of(PointType.class, StringType.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull String getMQTTpublishValue(@Nullable String pattern) {
|
public String getMQTTpublishValue(@Nullable String pattern) {
|
||||||
String formatPattern = pattern;
|
String formatPattern = pattern;
|
||||||
PointType point = ((PointType) state);
|
PointType point = ((PointType) state);
|
||||||
|
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import javax.measure.Unit;
|
import javax.measure.Unit;
|
||||||
|
|
||||||
@ -53,8 +52,7 @@ public class NumberValue extends Value {
|
|||||||
|
|
||||||
public NumberValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step,
|
public NumberValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step,
|
||||||
@Nullable Unit<?> unit) {
|
@Nullable Unit<?> unit) {
|
||||||
super(CoreItemFactory.NUMBER, Stream.of(QuantityType.class, IncreaseDecreaseType.class, UpDownType.class)
|
super(CoreItemFactory.NUMBER, List.of(QuantityType.class, IncreaseDecreaseType.class, UpDownType.class));
|
||||||
.collect(Collectors.toList()));
|
|
||||||
this.min = min;
|
this.min = min;
|
||||||
this.max = max;
|
this.max = max;
|
||||||
this.step = step == null ? BigDecimal.ONE : step;
|
this.step = step == null ? BigDecimal.ONE : step;
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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,
|
public OnOffValue(@Nullable String onState, @Nullable String offState, @Nullable String onCommand,
|
||||||
@Nullable String offCommand) {
|
@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.onState = onState == null ? OnOffType.ON.name() : onState;
|
||||||
this.offState = offState == null ? OnOffType.OFF.name() : offState;
|
this.offState = offState == null ? OnOffType.OFF.name() : offState;
|
||||||
this.onCommand = onCommand == null ? OnOffType.ON.name() : onCommand;
|
this.onCommand = onCommand == null ? OnOffType.ON.name() : onCommand;
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
@ -36,7 +35,7 @@ public class OpenCloseValue extends Value {
|
|||||||
* Creates a contact Open/Close type.
|
* Creates a contact Open/Close type.
|
||||||
*/
|
*/
|
||||||
public OpenCloseValue() {
|
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.openString = OpenClosedType.OPEN.name();
|
||||||
this.closeString = OpenClosedType.CLOSED.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.
|
* @param closeValue The OFF value string. This will be compared to MQTT messages.
|
||||||
*/
|
*/
|
||||||
public OpenCloseValue(@Nullable String openValue, @Nullable String closeValue) {
|
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.openString = openValue == null ? OpenClosedType.OPEN.name() : openValue;
|
||||||
this.closeString = closeValue == null ? OpenClosedType.CLOSED.name() : closeValue;
|
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.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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,
|
public PercentageValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step,
|
||||||
@Nullable String onValue, @Nullable String offValue) {
|
@Nullable String onValue, @Nullable String offValue) {
|
||||||
super(CoreItemFactory.DIMMER, Stream.of(DecimalType.class, QuantityType.class, IncreaseDecreaseType.class,
|
super(CoreItemFactory.DIMMER, List.of(DecimalType.class, QuantityType.class, IncreaseDecreaseType.class,
|
||||||
OnOffType.class, UpDownType.class, StringType.class).collect(Collectors.toList()));
|
OnOffType.class, UpDownType.class, StringType.class));
|
||||||
this.onValue = onValue;
|
this.onValue = onValue;
|
||||||
this.offValue = offValue;
|
this.offValue = offValue;
|
||||||
this.min = min == null ? BigDecimal.ZERO : min;
|
this.min = min == null ? BigDecimal.ZERO : min;
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.generic.values;
|
package org.openhab.binding.mqtt.generic.values;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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) {
|
public RollershutterValue(@Nullable String upString, @Nullable String downString, @Nullable String stopString) {
|
||||||
super(CoreItemFactory.ROLLERSHUTTER,
|
super(CoreItemFactory.ROLLERSHUTTER,
|
||||||
Stream.of(UpDownType.class, StopMoveType.class, PercentType.class, StringType.class)
|
List.of(UpDownType.class, StopMoveType.class, PercentType.class, StringType.class));
|
||||||
.collect(Collectors.toList()));
|
|
||||||
this.upString = upString;
|
this.upString = upString;
|
||||||
this.downString = downString;
|
this.downString = downString;
|
||||||
this.stopString = stopString == null ? StopMoveType.STOP.name() : stopString;
|
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 static java.util.function.Predicate.not;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -45,7 +45,7 @@ public class TextValue extends Value {
|
|||||||
* will be allowed.
|
* will be allowed.
|
||||||
*/
|
*/
|
||||||
public TextValue(String[] states) {
|
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());
|
Set<String> s = Stream.of(states).filter(not(String::isBlank)).collect(Collectors.toSet());
|
||||||
if (!s.isEmpty()) {
|
if (!s.isEmpty()) {
|
||||||
this.states = s;
|
this.states = s;
|
||||||
@ -55,7 +55,7 @@ public class TextValue extends Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TextValue() {
|
public TextValue() {
|
||||||
super(CoreItemFactory.STRING, Collections.singletonList(StringType.class));
|
super(CoreItemFactory.STRING, List.of(StringType.class));
|
||||||
this.states = null;
|
this.states = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +24,11 @@ import java.time.ZonedDateTime;
|
|||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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;
|
||||||
@ -62,25 +61,26 @@ import org.openhab.core.thing.ChannelUID;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class ChannelStateTests {
|
public class ChannelStateTests {
|
||||||
|
|
||||||
private @Mock MqttBrokerConnection connection;
|
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||||
private @Mock ChannelStateUpdateListener channelStateUpdateListener;
|
private @Mock @NonNullByDefault({}) ChannelStateUpdateListener channelStateUpdateListenerMock;
|
||||||
private @Mock ChannelUID channelUID;
|
private @Mock @NonNullByDefault({}) ChannelUID channelUIDMock;
|
||||||
private @Spy TextValue textValue;
|
private @Spy @NonNullByDefault({}) TextValue textValue;
|
||||||
|
|
||||||
private ScheduledExecutorService scheduler;
|
private @NonNullByDefault({}) ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
private ChannelConfig config = ChannelConfigBuilder.create("state", "command").build();
|
private ChannelConfig config = ChannelConfigBuilder.create("state", "command").build();
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
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(connectionMock).unsubscribeAll();
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).publish(any(), any(), anyInt(),
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).publish(any(), any(), anyInt(),
|
||||||
anyBoolean());
|
anyBoolean());
|
||||||
|
|
||||||
scheduler = new ScheduledThreadPoolExecutor(1);
|
scheduler = new ScheduledThreadPoolExecutor(1);
|
||||||
@ -92,74 +92,74 @@ public class ChannelStateTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noInteractionTimeoutTest() throws InterruptedException, ExecutionException, TimeoutException {
|
public void noInteractionTimeoutTest() throws Exception {
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, textValue, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, textValue, channelStateUpdateListenerMock));
|
||||||
c.start(connection, scheduler, 50).get(100, TimeUnit.MILLISECONDS);
|
c.start(connectionMock, scheduler, 50).get(100, TimeUnit.MILLISECONDS);
|
||||||
verify(connection).subscribe(eq("state"), eq(c));
|
verify(connectionMock).subscribe(eq("state"), eq(c));
|
||||||
c.stop().get();
|
c.stop().get();
|
||||||
verify(connection).unsubscribe(eq("state"), eq(c));
|
verify(connectionMock).unsubscribe(eq("state"), eq(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishFormatTest() throws InterruptedException, ExecutionException, TimeoutException {
|
public void publishFormatTest() throws Exception {
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, textValue, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, textValue, channelStateUpdateListenerMock));
|
||||||
|
|
||||||
c.start(connection, scheduler, 0).get(50, TimeUnit.MILLISECONDS);
|
c.start(connectionMock, scheduler, 0).get(50, TimeUnit.MILLISECONDS);
|
||||||
verify(connection).subscribe(eq("state"), eq(c));
|
verify(connectionMock).subscribe(eq("state"), eq(c));
|
||||||
|
|
||||||
c.publishValue(new StringType("UPDATE")).get();
|
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));
|
eq(false));
|
||||||
|
|
||||||
c.config.formatBeforePublish = "prefix%s";
|
c.config.formatBeforePublish = "prefix%s";
|
||||||
c.publishValue(new StringType("UPDATE")).get();
|
c.publishValue(new StringType("UPDATE")).get();
|
||||||
verify(connection).publish(eq("command"), argThat(p -> Arrays.equals(p, "prefixUPDATE".getBytes())), anyInt(),
|
verify(connectionMock).publish(eq("command"), argThat(p -> Arrays.equals(p, "prefixUPDATE".getBytes())),
|
||||||
eq(false));
|
anyInt(), eq(false));
|
||||||
|
|
||||||
c.config.formatBeforePublish = "%1$s-%1$s";
|
c.config.formatBeforePublish = "%1$s-%1$s";
|
||||||
c.publishValue(new StringType("UPDATE")).get();
|
c.publishValue(new StringType("UPDATE")).get();
|
||||||
verify(connection).publish(eq("command"), argThat(p -> Arrays.equals(p, "UPDATE-UPDATE".getBytes())), anyInt(),
|
verify(connectionMock).publish(eq("command"), argThat(p -> Arrays.equals(p, "UPDATE-UPDATE".getBytes())),
|
||||||
eq(false));
|
anyInt(), eq(false));
|
||||||
|
|
||||||
c.config.formatBeforePublish = "%s";
|
c.config.formatBeforePublish = "%s";
|
||||||
c.config.retained = true;
|
c.config.retained = true;
|
||||||
c.publishValue(new StringType("UPDATE")).get();
|
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();
|
c.stop().get();
|
||||||
verify(connection).unsubscribe(eq("state"), eq(c));
|
verify(connectionMock).unsubscribe(eq("state"), eq(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void receiveWildcardTest() throws InterruptedException, ExecutionException, TimeoutException {
|
public void receiveWildcardTest() throws Exception {
|
||||||
ChannelState c = spy(new ChannelState(ChannelConfigBuilder.create("state/+/topic", "command").build(),
|
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());
|
c.processMessage("state/bla/topic", "A TEST".getBytes());
|
||||||
future.get(300, TimeUnit.MILLISECONDS);
|
future.get(300, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
assertThat(textValue.getChannelState().toString(), is("A TEST"));
|
assertThat(textValue.getChannelState().toString(), is("A TEST"));
|
||||||
verify(channelStateUpdateListener).updateChannelState(eq(channelUID), any());
|
verify(channelStateUpdateListenerMock).updateChannelState(eq(channelUIDMock), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void receiveStringTest() throws InterruptedException, ExecutionException, TimeoutException {
|
public void receiveStringTest() throws Exception {
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, textValue, channelStateUpdateListener));
|
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());
|
c.processMessage("state", "A TEST".getBytes());
|
||||||
future.get(300, TimeUnit.MILLISECONDS);
|
future.get(300, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
assertThat(textValue.getChannelState().toString(), is("A TEST"));
|
assertThat(textValue.getChannelState().toString(), is("A TEST"));
|
||||||
verify(channelStateUpdateListener).updateChannelState(eq(channelUID), any());
|
verify(channelStateUpdateListenerMock).updateChannelState(eq(channelUIDMock), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void receiveDecimalTest() {
|
public void receiveDecimalTest() {
|
||||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10), null);
|
NumberValue value = new NumberValue(null, null, new BigDecimal(10), null);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "15".getBytes());
|
c.processMessage("state", "15".getBytes());
|
||||||
assertThat(value.getChannelState().toString(), is("15"));
|
assertThat(value.getChannelState().toString(), is("15"));
|
||||||
@ -170,14 +170,14 @@ public class ChannelStateTests {
|
|||||||
c.processMessage("state", "DECREASE".getBytes());
|
c.processMessage("state", "DECREASE".getBytes());
|
||||||
assertThat(value.getChannelState().toString(), is("15"));
|
assertThat(value.getChannelState().toString(), is("15"));
|
||||||
|
|
||||||
verify(channelStateUpdateListener, times(3)).updateChannelState(eq(channelUID), any());
|
verify(channelStateUpdateListenerMock, times(3)).updateChannelState(eq(channelUIDMock), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void receiveDecimalFractionalTest() {
|
public void receiveDecimalFractionalTest() {
|
||||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10.5), null);
|
NumberValue value = new NumberValue(null, null, new BigDecimal(10.5), null);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "5.5".getBytes());
|
c.processMessage("state", "5.5".getBytes());
|
||||||
assertThat(value.getChannelState().toString(), is("5.5"));
|
assertThat(value.getChannelState().toString(), is("5.5"));
|
||||||
@ -189,8 +189,8 @@ public class ChannelStateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void receiveDecimalUnitTest() {
|
public void receiveDecimalUnitTest() {
|
||||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10), Units.WATT);
|
NumberValue value = new NumberValue(null, null, new BigDecimal(10), Units.WATT);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "15".getBytes());
|
c.processMessage("state", "15".getBytes());
|
||||||
assertThat(value.getChannelState().toString(), is("15 W"));
|
assertThat(value.getChannelState().toString(), is("15 W"));
|
||||||
@ -201,27 +201,27 @@ public class ChannelStateTests {
|
|||||||
c.processMessage("state", "DECREASE".getBytes());
|
c.processMessage("state", "DECREASE".getBytes());
|
||||||
assertThat(value.getChannelState().toString(), is("15 W"));
|
assertThat(value.getChannelState().toString(), is("15 W"));
|
||||||
|
|
||||||
verify(channelStateUpdateListener, times(3)).updateChannelState(eq(channelUID), any());
|
verify(channelStateUpdateListenerMock, times(3)).updateChannelState(eq(channelUIDMock), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void receiveDecimalAsPercentageUnitTest() {
|
public void receiveDecimalAsPercentageUnitTest() {
|
||||||
NumberValue value = new NumberValue(null, null, new BigDecimal(10), Units.PERCENT);
|
NumberValue value = new NumberValue(null, null, new BigDecimal(10), Units.PERCENT);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "63.7".getBytes());
|
c.processMessage("state", "63.7".getBytes());
|
||||||
assertThat(value.getChannelState().toString(), is("63.7 %"));
|
assertThat(value.getChannelState().toString(), is("63.7 %"));
|
||||||
|
|
||||||
verify(channelStateUpdateListener, times(1)).updateChannelState(eq(channelUID), any());
|
verify(channelStateUpdateListenerMock, times(1)).updateChannelState(eq(channelUIDMock), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void receivePercentageTest() {
|
public void receivePercentageTest() {
|
||||||
PercentageValue value = new PercentageValue(new BigDecimal(-100), new BigDecimal(100), new BigDecimal(10), null,
|
PercentageValue value = new PercentageValue(new BigDecimal(-100), new BigDecimal(100), new BigDecimal(10), null,
|
||||||
null);
|
null);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "-100".getBytes()); // 0%
|
c.processMessage("state", "-100".getBytes()); // 0%
|
||||||
assertThat(value.getChannelState().toString(), is("0"));
|
assertThat(value.getChannelState().toString(), is("0"));
|
||||||
@ -241,8 +241,8 @@ public class ChannelStateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void receiveRGBColorTest() {
|
public void receiveRGBColorTest() {
|
||||||
ColorValue value = new ColorValue(ColorMode.RGB, "FON", "FOFF", 10);
|
ColorValue value = new ColorValue(ColorMode.RGB, "FON", "FOFF", 10);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "ON".getBytes()); // Normal on state
|
c.processMessage("state", "ON".getBytes()); // Normal on state
|
||||||
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
||||||
@ -268,8 +268,8 @@ public class ChannelStateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void receiveHSBColorTest() {
|
public void receiveHSBColorTest() {
|
||||||
ColorValue value = new ColorValue(ColorMode.HSB, "FON", "FOFF", 10);
|
ColorValue value = new ColorValue(ColorMode.HSB, "FON", "FOFF", 10);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "ON".getBytes()); // Normal on state
|
c.processMessage("state", "ON".getBytes()); // Normal on state
|
||||||
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
||||||
@ -291,8 +291,8 @@ public class ChannelStateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void receiveXYYColorTest() {
|
public void receiveXYYColorTest() {
|
||||||
ColorValue value = new ColorValue(ColorMode.XYY, "FON", "FOFF", 10);
|
ColorValue value = new ColorValue(ColorMode.XYY, "FON", "FOFF", 10);
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "ON".getBytes()); // Normal on state
|
c.processMessage("state", "ON".getBytes()); // Normal on state
|
||||||
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
assertThat(value.getChannelState().toString(), is("0,0,10"));
|
||||||
@ -317,8 +317,8 @@ public class ChannelStateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void receiveLocationTest() {
|
public void receiveLocationTest() {
|
||||||
LocationValue value = new LocationValue();
|
LocationValue value = new LocationValue();
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
c.processMessage("state", "46.833974, 7.108433".getBytes());
|
c.processMessage("state", "46.833974, 7.108433".getBytes());
|
||||||
assertThat(value.getChannelState().toString(), is("46.833974,7.108433"));
|
assertThat(value.getChannelState().toString(), is("46.833974,7.108433"));
|
||||||
@ -328,8 +328,8 @@ public class ChannelStateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void receiveDateTimeTest() {
|
public void receiveDateTimeTest() {
|
||||||
DateTimeValue value = new DateTimeValue();
|
DateTimeValue value = new DateTimeValue();
|
||||||
ChannelState subject = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState subject = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
subject.start(connection, mock(ScheduledExecutorService.class), 100);
|
subject.start(connectionMock, mock(ScheduledExecutorService.class), 100);
|
||||||
|
|
||||||
ZonedDateTime zd = ZonedDateTime.now();
|
ZonedDateTime zd = ZonedDateTime.now();
|
||||||
String datetime = zd.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
String datetime = zd.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||||
@ -345,10 +345,10 @@ public class ChannelStateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void receiveImageTest() {
|
public void receiveImageTest() {
|
||||||
ImageValue value = new ImageValue();
|
ImageValue value = new ImageValue();
|
||||||
ChannelState c = spy(new ChannelState(config, channelUID, value, channelStateUpdateListener));
|
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
|
||||||
c.start(connection, mock(ScheduledExecutorService.class), 100);
|
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);
|
c.processMessage("state", payload);
|
||||||
assertThat(value.getChannelState(), is(instanceOf(RawType.class)));
|
assertThat(value.getChannelState(), is(instanceOf(RawType.class)));
|
||||||
assertThat(((RawType) value.getChannelState()).getMimeType(), is("image/jpeg"));
|
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 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.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
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.binding.mqtt.handler.AbstractBrokerHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
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.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
@ -49,43 +48,44 @@ import org.openhab.core.transform.TransformationService;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class ChannelStateTransformationTests {
|
public class ChannelStateTransformationTests {
|
||||||
|
|
||||||
private @Mock TransformationService jsonPathService;
|
private @Mock @NonNullByDefault({}) TransformationService jsonPathServiceMock;
|
||||||
private @Mock TransformationServiceProvider transformationServiceProvider;
|
private @Mock @NonNullByDefault({}) TransformationServiceProvider transformationServiceProviderMock;
|
||||||
private @Mock ThingHandlerCallback callback;
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
private @Mock Thing thing;
|
private @Mock @NonNullByDefault({}) Thing thingMock;
|
||||||
private @Mock AbstractBrokerHandler bridgeHandler;
|
private @Mock @NonNullByDefault({}) AbstractBrokerHandler bridgeHandlerMock;
|
||||||
private @Mock MqttBrokerConnection connection;
|
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||||
|
|
||||||
private GenericMQTTThingHandler thingHandler;
|
private @NonNullByDefault({}) GenericMQTTThingHandler thingHandler;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() throws ConfigurationException, MqttException {
|
public void setUp() throws Exception {
|
||||||
ThingStatusInfo thingStatus = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
ThingStatusInfo thingStatus = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||||
|
|
||||||
// Mock the thing: We need the thingUID and the bridgeUID
|
// Mock the thing: We need the thingUID and the bridgeUID
|
||||||
when(thing.getUID()).thenReturn(testGenericThing);
|
when(thingMock.getUID()).thenReturn(TEST_GENERIC_THING);
|
||||||
when(thing.getChannels()).thenReturn(thingChannelListWithJson);
|
when(thingMock.getChannels()).thenReturn(THING_CHANNEL_LIST_WITH_JSON);
|
||||||
when(thing.getStatusInfo()).thenReturn(thingStatus);
|
when(thingMock.getStatusInfo()).thenReturn(thingStatus);
|
||||||
when(thing.getConfiguration()).thenReturn(new Configuration());
|
when(thingMock.getConfiguration()).thenReturn(new Configuration());
|
||||||
|
|
||||||
// Return the mocked connection object if the bridge handler is asked for it
|
// 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);
|
voidFutureComplete.complete(null);
|
||||||
doReturn(voidFutureComplete).when(connection).unsubscribeAll();
|
doReturn(voidFutureComplete).when(connectionMock).unsubscribeAll();
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||||
|
|
||||||
thingHandler = spy(new GenericMQTTThingHandler(thing, mock(MqttChannelStateDescriptionProvider.class),
|
thingHandler = spy(new GenericMQTTThingHandler(thingMock, mock(MqttChannelStateDescriptionProvider.class),
|
||||||
transformationServiceProvider, 1500));
|
transformationServiceProviderMock, 1500));
|
||||||
when(transformationServiceProvider.getTransformationService(anyString())).thenReturn(jsonPathService);
|
when(transformationServiceProviderMock.getTransformationService(anyString())).thenReturn(jsonPathServiceMock);
|
||||||
|
|
||||||
thingHandler.setCallback(callback);
|
thingHandler.setCallback(callbackMock);
|
||||||
// Return the bridge handler if the thing handler asks for it
|
// 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
|
// We are by default online
|
||||||
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
||||||
@ -93,31 +93,31 @@ public class ChannelStateTransformationTests {
|
|||||||
|
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
@Test
|
@Test
|
||||||
public void initialize() throws MqttException {
|
public void initialize() throws Exception {
|
||||||
when(thing.getChannels()).thenReturn(thingChannelListWithJson);
|
when(thingMock.getChannels()).thenReturn(THING_CHANNEL_LIST_WITH_JSON);
|
||||||
|
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
ChannelState channelConfig = thingHandler.getChannelState(textChannelUID);
|
ChannelState channelConfig = thingHandler.getChannelState(TEXT_CHANNEL_UID);
|
||||||
assertThat(channelConfig.transformationsIn.get(0).pattern, is(jsonPathPattern));
|
assertThat(channelConfig.transformationsIn.get(0).pattern, is(JSON_PATH_PATTERN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
@Test
|
@Test
|
||||||
public void processMessageWithJSONPath() throws Exception {
|
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();
|
thingHandler.initialize();
|
||||||
ChannelState channelConfig = thingHandler.getChannelState(textChannelUID);
|
ChannelState channelConfig = thingHandler.getChannelState(TEXT_CHANNEL_UID);
|
||||||
channelConfig.setChannelStateUpdateListener(thingHandler);
|
channelConfig.setChannelStateUpdateListener(thingHandler);
|
||||||
|
|
||||||
ChannelStateTransformation transformation = channelConfig.transformationsIn.get(0);
|
ChannelStateTransformation transformation = channelConfig.transformationsIn.get(0);
|
||||||
|
|
||||||
byte payload[] = jsonPathJSON.getBytes();
|
byte payload[] = JSON_PATH_JSON.getBytes();
|
||||||
assertThat(transformation.pattern, is(jsonPathPattern));
|
assertThat(transformation.pattern, is(JSON_PATH_PATTERN));
|
||||||
// Test process message
|
// Test process message
|
||||||
channelConfig.processMessage(channelConfig.getStateTopic(), payload);
|
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"));
|
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 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.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@ -57,42 +59,43 @@ import org.openhab.core.types.RefreshType;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class GenericThingHandlerTests {
|
public class GenericThingHandlerTests {
|
||||||
|
|
||||||
private @Mock ThingHandlerCallback callback;
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
private @Mock Thing thing;
|
private @Mock @NonNullByDefault({}) Thing thingMock;
|
||||||
private @Mock AbstractBrokerHandler bridgeHandler;
|
private @Mock @NonNullByDefault({}) AbstractBrokerHandler bridgeHandlerMock;
|
||||||
private @Mock MqttBrokerConnection connection;
|
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||||
|
|
||||||
private GenericMQTTThingHandler thingHandler;
|
private @NonNullByDefault({}) GenericMQTTThingHandler thingHandler;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
ThingStatusInfo thingStatus = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
ThingStatusInfo thingStatus = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||||
|
|
||||||
// Mock the thing: We need the thingUID and the bridgeUID
|
// Mock the thing: We need the thingUID and the bridgeUID
|
||||||
when(thing.getUID()).thenReturn(testGenericThing);
|
when(thingMock.getUID()).thenReturn(TEST_GENERIC_THING);
|
||||||
when(thing.getChannels()).thenReturn(thingChannelList);
|
when(thingMock.getChannels()).thenReturn(THING_CHANNEL_LIST);
|
||||||
when(thing.getStatusInfo()).thenReturn(thingStatus);
|
when(thingMock.getStatusInfo()).thenReturn(thingStatus);
|
||||||
when(thing.getConfiguration()).thenReturn(new Configuration());
|
when(thingMock.getConfiguration()).thenReturn(new Configuration());
|
||||||
|
|
||||||
// Return the mocked connection object if the bridge handler is asked for it
|
// 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);
|
voidFutureComplete.complete(null);
|
||||||
doReturn(voidFutureComplete).when(connection).unsubscribeAll();
|
doReturn(voidFutureComplete).when(connectionMock).unsubscribeAll();
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).publish(any(), any(), anyInt(),
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).publish(any(), any(), anyInt(),
|
||||||
anyBoolean());
|
anyBoolean());
|
||||||
|
|
||||||
thingHandler = spy(new GenericMQTTThingHandler(thing, mock(MqttChannelStateDescriptionProvider.class),
|
thingHandler = spy(new GenericMQTTThingHandler(thingMock, mock(MqttChannelStateDescriptionProvider.class),
|
||||||
mock(TransformationServiceProvider.class), 1500));
|
mock(TransformationServiceProvider.class), 1500));
|
||||||
thingHandler.setCallback(callback);
|
thingHandler.setCallback(callbackMock);
|
||||||
|
|
||||||
// Return the bridge handler if the thing handler asks for it
|
// 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
|
// The broker connection bridge is by default online
|
||||||
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
||||||
@ -102,8 +105,8 @@ public class GenericThingHandlerTests {
|
|||||||
public void initializeWithUnknownThingUID() {
|
public void initializeWithUnknownThingUID() {
|
||||||
ChannelConfig config = textConfiguration().as(ChannelConfig.class);
|
ChannelConfig config = textConfiguration().as(ChannelConfig.class);
|
||||||
assertThrows(IllegalArgumentException.class,
|
assertThrows(IllegalArgumentException.class,
|
||||||
() -> thingHandler.createChannelState(config, new ChannelUID(testGenericThing, "test"),
|
() -> thingHandler.createChannelState(config, new ChannelUID(TEST_GENERIC_THING, "test"),
|
||||||
ValueFactory.createValueState(config, unknownChannel.getId())));
|
ValueFactory.createValueState(config, UNKNOWN_CHANNEL.getId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -111,16 +114,16 @@ public class GenericThingHandlerTests {
|
|||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
verify(thingHandler).bridgeStatusChanged(any());
|
verify(thingHandler).bridgeStatusChanged(any());
|
||||||
verify(thingHandler).start(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.getStateTopic(), is("test/state"));
|
||||||
assertThat(channelConfig.getCommandTopic(), is("test/command"));
|
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)
|
verify(callbackMock).statusUpdated(eq(thingMock), argThat(arg -> ThingStatus.ONLINE.equals(arg.getStatus())
|
||||||
&& arg.getStatusDetail().equals(ThingStatusDetail.NONE)));
|
&& ThingStatusDetail.NONE.equals(arg.getStatusDetail())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -135,24 +138,24 @@ public class GenericThingHandlerTests {
|
|||||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
|
|
||||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||||
|
|
||||||
thingHandler.handleCommand(textChannelUID, RefreshType.REFRESH);
|
thingHandler.handleCommand(TEXT_CHANNEL_UID, RefreshType.REFRESH);
|
||||||
verify(callback).stateUpdated(eq(textChannelUID), argThat(arg -> "DEMOVALUE".equals(arg.toString())));
|
verify(callbackMock).stateUpdated(eq(TEXT_CHANNEL_UID), argThat(arg -> "DEMOVALUE".equals(arg.toString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleCommandUpdateString() {
|
public void handleCommandUpdateString() {
|
||||||
TextValue value = spy(new TextValue());
|
TextValue value = spy(new TextValue());
|
||||||
ChannelState channelConfig = spy(
|
ChannelState channelConfig = spy(
|
||||||
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), textChannelUID,
|
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), TEXT_CHANNEL_UID,
|
||||||
value, thingHandler));
|
value, thingHandler));
|
||||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||||
|
|
||||||
StringType updateValue = new StringType("UPDATE");
|
StringType updateValue = new StringType("UPDATE");
|
||||||
thingHandler.handleCommand(textChannelUID, updateValue);
|
thingHandler.handleCommand(TEXT_CHANNEL_UID, updateValue);
|
||||||
verify(value).update(eq(updateValue));
|
verify(value).update(eq(updateValue));
|
||||||
assertThat(channelConfig.getCache().getChannelState().toString(), is("UPDATE"));
|
assertThat(channelConfig.getCache().getChannelState().toString(), is("UPDATE"));
|
||||||
}
|
}
|
||||||
@ -161,14 +164,14 @@ public class GenericThingHandlerTests {
|
|||||||
public void handleCommandUpdateBoolean() {
|
public void handleCommandUpdateBoolean() {
|
||||||
OnOffValue value = spy(new OnOffValue("ON", "OFF"));
|
OnOffValue value = spy(new OnOffValue("ON", "OFF"));
|
||||||
ChannelState channelConfig = spy(
|
ChannelState channelConfig = spy(
|
||||||
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), textChannelUID,
|
new ChannelState(ChannelConfigBuilder.create("stateTopic", "commandTopic").build(), TEXT_CHANNEL_UID,
|
||||||
value, thingHandler));
|
value, thingHandler));
|
||||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||||
|
|
||||||
StringType updateValue = new StringType("ON");
|
StringType updateValue = new StringType("ON");
|
||||||
thingHandler.handleCommand(textChannelUID, updateValue);
|
thingHandler.handleCommand(TEXT_CHANNEL_UID, updateValue);
|
||||||
|
|
||||||
verify(value).update(eq(updateValue));
|
verify(value).update(eq(updateValue));
|
||||||
assertThat(channelConfig.getCache().getChannelState(), is(OnOffType.ON));
|
assertThat(channelConfig.getCache().getChannelState(), is(OnOffType.ON));
|
||||||
@ -178,7 +181,7 @@ public class GenericThingHandlerTests {
|
|||||||
public void processMessage() {
|
public void processMessage() {
|
||||||
TextValue textValue = new TextValue();
|
TextValue textValue = new TextValue();
|
||||||
ChannelState channelConfig = spy(
|
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));
|
textValue, thingHandler));
|
||||||
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
doReturn(channelConfig).when(thingHandler).createChannelState(any(), any(), any());
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
@ -186,10 +189,10 @@ public class GenericThingHandlerTests {
|
|||||||
// Test process message
|
// Test process message
|
||||||
channelConfig.processMessage("test/state", payload);
|
channelConfig.processMessage("test/state", payload);
|
||||||
|
|
||||||
verify(callback, atLeastOnce()).statusUpdated(eq(thing),
|
verify(callbackMock, atLeastOnce()).statusUpdated(eq(thingMock),
|
||||||
argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE)));
|
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"));
|
assertThat(textValue.getChannelState().toString(), is("UPDATE"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,11 +200,11 @@ public class GenericThingHandlerTests {
|
|||||||
public void handleBridgeStatusChange() {
|
public void handleBridgeStatusChange() {
|
||||||
Configuration config = new Configuration();
|
Configuration config = new Configuration();
|
||||||
config.put("availabilityTopic", "test/LWT");
|
config.put("availabilityTopic", "test/LWT");
|
||||||
when(thing.getConfiguration()).thenReturn(config);
|
when(thingMock.getConfiguration()).thenReturn(config);
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
thingHandler
|
thingHandler
|
||||||
.bridgeStatusChanged(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, null));
|
.bridgeStatusChanged(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, null));
|
||||||
thingHandler.bridgeStatusChanged(new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, 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
|
@NonNullByDefault
|
||||||
public class ThingChannelConstants {
|
public class ThingChannelConstants {
|
||||||
// Common ThingUID and ChannelUIDs
|
// 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 TEXT_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.STRING);
|
||||||
public static final ChannelTypeUID textWithJsonChannel = new ChannelTypeUID(BINDING_ID,
|
public static final ChannelTypeUID TEXT_WITH_JSON_CHANNEL = new ChannelTypeUID(BINDING_ID,
|
||||||
MqttBindingConstants.STRING);
|
MqttBindingConstants.STRING);
|
||||||
public static final ChannelTypeUID onoffChannel = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.SWITCH);
|
public static final ChannelTypeUID ON_OFF_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.SWITCH);
|
||||||
public static final ChannelTypeUID numberChannel = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.NUMBER);
|
public static final ChannelTypeUID NUMBER_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.NUMBER);
|
||||||
public static final ChannelTypeUID percentageChannel = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.DIMMER);
|
public static final ChannelTypeUID PERCENTAGE_CHANNEL = new ChannelTypeUID(BINDING_ID, MqttBindingConstants.DIMMER);
|
||||||
public static final ChannelTypeUID unknownChannel = new ChannelTypeUID(BINDING_ID, "unknown");
|
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 JSON_PATH_JSON = "{ \"device\": { \"status\": { \"temperature\": 23.2 }}}";
|
||||||
public static final String jsonPathPattern = "$.device.status.temperature";
|
public static final String JSON_PATH_PATTERN = "$.device.status.temperature";
|
||||||
|
|
||||||
public static final List<Channel> thingChannelList = new ArrayList<>();
|
public static final List<Channel> THING_CHANNEL_LIST = new ArrayList<>();
|
||||||
public static final List<Channel> thingChannelListWithJson = 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
|
* Create a channel with exact the parameters we need for the tests
|
||||||
@ -65,20 +65,21 @@ public class ThingChannelConstants {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static Channel cb(String id, String acceptedType, Configuration config, ChannelTypeUID channelTypeUID) {
|
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();
|
.withType(channelTypeUID).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
thingChannelList.add(cb("mytext", "TextItemType", textConfiguration(), textChannel));
|
THING_CHANNEL_LIST.add(cb("mytext", "TextItemType", textConfiguration(), TEXT_CHANNEL));
|
||||||
thingChannelList.add(cb("onoff", "OnOffType", onoffConfiguration(), onoffChannel));
|
THING_CHANNEL_LIST.add(cb("onoff", "OnOffType", onoffConfiguration(), ON_OFF_CHANNEL));
|
||||||
thingChannelList.add(cb("num", "NumberType", numberConfiguration(), numberChannel));
|
THING_CHANNEL_LIST.add(cb("num", "NumberType", numberConfiguration(), NUMBER_CHANNEL));
|
||||||
thingChannelList.add(cb("percent", "NumberType", percentageConfiguration(), percentageChannel));
|
THING_CHANNEL_LIST.add(cb("percent", "NumberType", percentageConfiguration(), PERCENTAGE_CHANNEL));
|
||||||
|
|
||||||
thingChannelListWithJson.add(cb("mytext", "TextItemType", textConfigurationWithJson(), textWithJsonChannel));
|
THING_CHANNEL_LIST_WITH_JSON
|
||||||
thingChannelListWithJson.add(cb("onoff", "OnOffType", onoffConfiguration(), onoffChannel));
|
.add(cb("mytext", "TextItemType", textConfigurationWithJson(), TEXT_WITH_JSON_CHANNEL));
|
||||||
thingChannelListWithJson.add(cb("num", "NumberType", numberConfiguration(), numberChannel));
|
THING_CHANNEL_LIST_WITH_JSON.add(cb("onoff", "OnOffType", onoffConfiguration(), ON_OFF_CHANNEL));
|
||||||
thingChannelListWithJson.add(cb("percent", "NumberType", percentageConfiguration(), percentageChannel));
|
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() {
|
static Configuration textConfiguration() {
|
||||||
@ -92,7 +93,7 @@ public class ThingChannelConstants {
|
|||||||
Map<String, Object> data = new HashMap<>();
|
Map<String, Object> data = new HashMap<>();
|
||||||
data.put("stateTopic", "test/state");
|
data.put("stateTopic", "test/state");
|
||||||
data.put("commandTopic", "test/command");
|
data.put("commandTopic", "test/command");
|
||||||
data.put("transformationPattern", "JSONPATH:" + jsonPathPattern);
|
data.put("transformationPattern", "JSONPATH:" + JSON_PATH_PATTERN);
|
||||||
return new Configuration(data);
|
return new Configuration(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.stream.Stream;
|
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.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -60,6 +60,7 @@ import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class MqttTopicClassMapperTests {
|
public class MqttTopicClassMapperTests {
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ FIELD })
|
@Target({ FIELD })
|
||||||
@ -72,15 +73,15 @@ public class MqttTopicClassMapperTests {
|
|||||||
public transient String ignoreTransient = "";
|
public transient String ignoreTransient = "";
|
||||||
public final String ignoreFinal = "";
|
public final String ignoreFinal = "";
|
||||||
|
|
||||||
public @TestValue("string") String aString;
|
public @TestValue("string") @Nullable String aString;
|
||||||
public @TestValue("false") Boolean aBoolean;
|
public @TestValue("false") @Nullable Boolean aBoolean;
|
||||||
public @TestValue("10") Long aLong;
|
public @TestValue("10") @Nullable Long aLong;
|
||||||
public @TestValue("10") Integer aInteger;
|
public @TestValue("10") @Nullable Integer aInteger;
|
||||||
public @TestValue("10") BigDecimal aDecimal;
|
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("false") boolean aBool = true;
|
||||||
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String[] properties;
|
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String @Nullable [] properties;
|
||||||
|
|
||||||
public enum ReadyState {
|
public enum ReadyState {
|
||||||
unknown,
|
unknown,
|
||||||
@ -99,22 +100,16 @@ public class MqttTopicClassMapperTests {
|
|||||||
public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
|
public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Object getFieldsOf() {
|
public Object getFieldsOf() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mock
|
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||||
MqttBrokerConnection connection;
|
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;
|
int injectedFields = 0;
|
||||||
|
|
||||||
// A completed future is returned for a subscribe call to the attributes
|
// A completed future is returned for a subscribe call to the attributes
|
||||||
@ -122,8 +117,8 @@ public class MqttTopicClassMapperTests {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||||
injectedFields = (int) Stream.of(countInjectedFields.getClass().getDeclaredFields())
|
injectedFields = (int) Stream.of(countInjectedFields.getClass().getDeclaredFields())
|
||||||
.filter(AbstractMqttAttributeClass::filterField).count();
|
.filter(AbstractMqttAttributeClass::filterField).count();
|
||||||
}
|
}
|
||||||
@ -148,8 +143,8 @@ public class MqttTopicClassMapperTests {
|
|||||||
anyBoolean());
|
anyBoolean());
|
||||||
|
|
||||||
// Subscribe now to all fields
|
// Subscribe now to all fields
|
||||||
CompletableFuture<Void> future = attributes.subscribeAndReceive(connection, executor, "homie/device123", null,
|
CompletableFuture<@Nullable Void> future = attributes.subscribeAndReceive(connectionMock, executorMock,
|
||||||
10);
|
"homie/device123", null, 10);
|
||||||
assertThat(future.isDone(), is(true));
|
assertThat(future.isDone(), is(true));
|
||||||
assertThat(attributes.subscriptions.size(), is(10 + injectedFields));
|
assertThat(attributes.subscriptions.size(), is(10 + injectedFields));
|
||||||
}
|
}
|
||||||
@ -157,17 +152,17 @@ public class MqttTopicClassMapperTests {
|
|||||||
// TODO timeout
|
// TODO timeout
|
||||||
@SuppressWarnings({ "null", "unused" })
|
@SuppressWarnings({ "null", "unused" })
|
||||||
@Test
|
@Test
|
||||||
public void subscribeAndReceive() throws IllegalArgumentException, IllegalAccessException {
|
public void subscribeAndReceive() throws Exception {
|
||||||
final Attributes attributes = spy(new Attributes());
|
final Attributes attributes = spy(new Attributes());
|
||||||
|
|
||||||
doAnswer(this::createSubscriberAnswer).when(attributes).createSubscriber(any(), any(), anyString(),
|
doAnswer(this::createSubscriberAnswer).when(attributes).createSubscriber(any(), any(), anyString(),
|
||||||
anyBoolean());
|
anyBoolean());
|
||||||
|
|
||||||
verify(connection, times(0)).subscribe(anyString(), any());
|
verify(connectionMock, times(0)).subscribe(anyString(), any());
|
||||||
|
|
||||||
// Subscribe now to all fields
|
// Subscribe now to all fields
|
||||||
CompletableFuture<Void> future = attributes.subscribeAndReceive(connection, executor, "homie/device123",
|
CompletableFuture<@Nullable Void> future = attributes.subscribeAndReceive(connectionMock, executorMock,
|
||||||
fieldChangedObserver, 10);
|
"homie/device123", fieldChangedObserverMock, 10);
|
||||||
assertThat(future.isDone(), is(true));
|
assertThat(future.isDone(), is(true));
|
||||||
|
|
||||||
// We expect 10 subscriptions now
|
// We expect 10 subscriptions now
|
||||||
@ -190,7 +185,7 @@ public class MqttTopicClassMapperTests {
|
|||||||
|
|
||||||
// Simulate a received MQTT value and use the annotation data as input.
|
// Simulate a received MQTT value and use the annotation data as input.
|
||||||
f.processMessage(f.topic, annotation.value().getBytes());
|
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());
|
anyBoolean());
|
||||||
|
|
||||||
// Check each value if the assignment worked
|
// Check each value if the assignment worked
|
||||||
@ -213,23 +208,23 @@ public class MqttTopicClassMapperTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void ignoresInvalidEnum() throws IllegalArgumentException, IllegalAccessException {
|
public void ignoresInvalidEnum() throws Exception {
|
||||||
final Attributes attributes = spy(new Attributes());
|
final Attributes attributes = spy(new Attributes());
|
||||||
|
|
||||||
doAnswer(this::createSubscriberAnswer).when(attributes).createSubscriber(any(), any(), anyString(),
|
doAnswer(this::createSubscriberAnswer).when(attributes).createSubscriber(any(), any(), anyString(),
|
||||||
anyBoolean());
|
anyBoolean());
|
||||||
|
|
||||||
verify(connection, times(0)).subscribe(anyString(), any());
|
verify(connectionMock, times(0)).subscribe(anyString(), any());
|
||||||
|
|
||||||
// Subscribe now to all fields
|
// Subscribe now to all fields
|
||||||
CompletableFuture<Void> future = attributes.subscribeAndReceive(connection, executor, "homie/device123",
|
CompletableFuture<@Nullable Void> future = attributes.subscribeAndReceive(connectionMock, executorMock,
|
||||||
fieldChangedObserver, 10);
|
"homie/device123", fieldChangedObserverMock, 10);
|
||||||
assertThat(future.isDone(), is(true));
|
assertThat(future.isDone(), is(true));
|
||||||
|
|
||||||
SubscribeFieldToMQTTtopic field = attributes.subscriptions.stream().filter(f -> f.field.getName() == "state")
|
SubscribeFieldToMQTTtopic field = attributes.subscriptions.stream().filter(f -> f.field.getName() == "state")
|
||||||
.findFirst().get();
|
.findFirst().get();
|
||||||
field.processMessage(field.topic, "garbage".getBytes());
|
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"));
|
assertThat(attributes.state.toString(), is("unknown"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +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.NonNull;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -50,6 +50,7 @@ import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class SubscribeFieldToMQTTtopicTests {
|
public class SubscribeFieldToMQTTtopicTests {
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ FIELD })
|
@Target({ FIELD })
|
||||||
@ -64,15 +65,15 @@ public class SubscribeFieldToMQTTtopicTests {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final String ignoreFinal = "";
|
public final String ignoreFinal = "";
|
||||||
|
|
||||||
public @TestValue("string") String aString;
|
public @TestValue("string") @Nullable String aString;
|
||||||
public @TestValue("false") Boolean aBoolean;
|
public @TestValue("false") @Nullable Boolean aBoolean;
|
||||||
public @TestValue("10") Long aLong;
|
public @TestValue("10") @Nullable Long aLong;
|
||||||
public @TestValue("10") Integer aInteger;
|
public @TestValue("10") @Nullable Integer aInteger;
|
||||||
public @TestValue("10") BigDecimal aDecimal;
|
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("false") boolean aBool = true;
|
||||||
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String[] properties;
|
public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String @Nullable [] properties;
|
||||||
|
|
||||||
public enum ReadyState {
|
public enum ReadyState {
|
||||||
unknown,
|
unknown,
|
||||||
@ -91,53 +92,44 @@ public class SubscribeFieldToMQTTtopicTests {
|
|||||||
public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
|
public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Object getFieldsOf() {
|
public Object getFieldsOf() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Attributes attributes = new Attributes();
|
Attributes attributes = new Attributes();
|
||||||
|
|
||||||
@Mock
|
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||||
MqttBrokerConnection connection;
|
private @Mock @NonNullByDefault({}) FieldChanged fieldChangedMock;
|
||||||
|
|
||||||
@Mock
|
|
||||||
SubscribeFieldToMQTTtopic fieldSubscriber;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
FieldChanged fieldChanged;
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void TimeoutIfNoMessageReceive()
|
public void timeoutIfNoMessageReceive() throws Exception {
|
||||||
throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
|
final Field field = Attributes.class.getField("aInt");
|
||||||
final Field field = Attributes.class.getField("Int");
|
|
||||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||||
|
|
||||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChanged,
|
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChangedMock,
|
||||||
"homie/device123", false);
|
"homie/device123", false);
|
||||||
assertThrows(TimeoutException.class,
|
assertThrows(TimeoutException.class,
|
||||||
() -> subscriber.subscribeAndReceive(connection, 1000).get(50, TimeUnit.MILLISECONDS));
|
() -> subscriber.subscribeAndReceive(connectionMock, 1000).get(50, TimeUnit.MILLISECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void MandatoryMissing()
|
public void mandatoryMissing() throws Exception {
|
||||||
throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
|
final Field field = Attributes.class.getField("aInt");
|
||||||
final Field field = Attributes.class.getField("Int");
|
|
||||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||||
|
|
||||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChanged,
|
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChangedMock,
|
||||||
"homie/device123", true);
|
"homie/device123", true);
|
||||||
assertThrows(ExecutionException.class, () -> subscriber.subscribeAndReceive(connection, 50).get());
|
assertThrows(ExecutionException.class, () -> subscriber.subscribeAndReceive(connectionMock, 50).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void MessageReceive()
|
public void messageReceive() throws Exception {
|
||||||
throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
|
|
||||||
final FieldChanged changed = (field, value) -> {
|
final FieldChanged changed = (field, value) -> {
|
||||||
try {
|
try {
|
||||||
field.set(attributes.getFieldsOf(), value);
|
field.set(attributes.getFieldsOf(), value);
|
||||||
@ -145,17 +137,17 @@ public class SubscribeFieldToMQTTtopicTests {
|
|||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final Field field = Attributes.class.getField("Int");
|
final Field field = Attributes.class.getField("aInt");
|
||||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||||
|
|
||||||
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, changed,
|
SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, changed,
|
||||||
"homie/device123", false);
|
"homie/device123", false);
|
||||||
CompletableFuture<@Nullable Void> future = subscriber.subscribeAndReceive(connection, 1000);
|
CompletableFuture<@Nullable Void> future = subscriber.subscribeAndReceive(connectionMock, 1000);
|
||||||
|
|
||||||
// Simulate a received MQTT message
|
// Simulate a received MQTT message
|
||||||
subscriber.processMessage("ignored", "10".getBytes());
|
subscriber.processMessage("ignored", "10".getBytes());
|
||||||
// No timeout should happen
|
// No timeout should happen
|
||||||
future.get(50, TimeUnit.MILLISECONDS);
|
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 static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.mapping.ColorMode;
|
import org.openhab.binding.mqtt.generic.mapping.ColorMode;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
@ -44,9 +46,10 @@ import org.openhab.core.types.TypeParser;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class ValueTests {
|
public class ValueTests {
|
||||||
Command p(Value v, String str) {
|
private Command p(Value v, String str) {
|
||||||
return TypeParser.parseCommand(v.getSupportedCommandTypes(), str);
|
return Objects.requireNonNull(TypeParser.parseCommand(v.getSupportedCommandTypes(), str));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -24,8 +24,6 @@ import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChanne
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
@ -37,8 +35,6 @@ import com.google.gson.Gson;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class ComponentFactory {
|
public class ComponentFactory {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ComponentFactory.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a HA MQTT component. The configuration JSon string is required.
|
* Create a HA MQTT component. The configuration JSon string is required.
|
||||||
*
|
*
|
||||||
|
@ -154,7 +154,7 @@ public class ChannelConfigurationTypeAdapterFactory implements TypeAdapterFactor
|
|||||||
|
|
||||||
field.set(config, newValue);
|
field.set(config, newValue);
|
||||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||||
throw new RuntimeException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homeassistant.internal.exception;
|
package org.openhab.binding.mqtt.homeassistant.internal.exception;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception class for errors in HomeAssistant components configurations
|
* Exception class for errors in HomeAssistant components configurations
|
||||||
*
|
*
|
||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class ConfigurationException extends RuntimeException {
|
public class ConfigurationException extends RuntimeException {
|
||||||
public ConfigurationException(String message) {
|
public ConfigurationException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homeassistant.internal.exception;
|
package org.openhab.binding.mqtt.homeassistant.internal.exception;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception class for unsupported components
|
* Exception class for unsupported components
|
||||||
*
|
*
|
||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class UnsupportedComponentException extends ConfigurationException {
|
public class UnsupportedComponentException extends ConfigurationException {
|
||||||
public UnsupportedComponentException(String message) {
|
public UnsupportedComponentException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
@ -19,12 +19,14 @@ import static org.hamcrest.core.IsIterableContaining.hasItem;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jochen Klein - Initial contribution
|
* @author Jochen Klein - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HaIDTests {
|
public class HaIDTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -33,7 +34,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import org.eclipse.jdt.annotation.NonNull;
|
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.hamcrest.CoreMatchers;
|
|
||||||
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.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@ -56,12 +56,13 @@ import org.openhab.core.types.State;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "ConstantConditions" })
|
@SuppressWarnings({ "ConstantConditions" })
|
||||||
|
@NonNullByDefault
|
||||||
public abstract class AbstractComponentTests extends AbstractHomeAssistantTests {
|
public abstract class AbstractComponentTests extends AbstractHomeAssistantTests {
|
||||||
private final static int SUBSCRIBE_TIMEOUT = 10000;
|
private static final int SUBSCRIBE_TIMEOUT = 10000;
|
||||||
private final static int ATTRIBUTE_RECEIVE_TIMEOUT = 2000;
|
private static final int ATTRIBUTE_RECEIVE_TIMEOUT = 2000;
|
||||||
|
|
||||||
private @Mock ThingHandlerCallback callback;
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
private LatchThingHandler thingHandler;
|
private @NonNullByDefault({}) LatchThingHandler thingHandler;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setupThingHandler() {
|
public void setupThingHandler() {
|
||||||
@ -70,12 +71,12 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
config.put(HandlerConfiguration.PROPERTY_BASETOPIC, HandlerConfiguration.DEFAULT_BASETOPIC);
|
config.put(HandlerConfiguration.PROPERTY_BASETOPIC, HandlerConfiguration.DEFAULT_BASETOPIC);
|
||||||
config.put(HandlerConfiguration.PROPERTY_TOPICS, getConfigTopics());
|
config.put(HandlerConfiguration.PROPERTY_TOPICS, getConfigTopics());
|
||||||
|
|
||||||
when(callback.getBridge(eq(BRIDGE_UID))).thenReturn(bridgeThing);
|
when(callbackMock.getBridge(eq(BRIDGE_UID))).thenReturn(bridgeThing);
|
||||||
|
|
||||||
thingHandler = new LatchThingHandler(haThing, channelTypeProvider, transformationServiceProvider,
|
thingHandler = new LatchThingHandler(haThing, channelTypeProvider, transformationServiceProvider,
|
||||||
SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
||||||
thingHandler.setConnection(bridgeConnection);
|
thingHandler.setConnection(bridgeConnection);
|
||||||
thingHandler.setCallback(callback);
|
thingHandler.setCallback(callbackMock);
|
||||||
thingHandler = spy(thingHandler);
|
thingHandler = spy(thingHandler);
|
||||||
|
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
@ -124,9 +125,7 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
assertThat(e.getMessage(), false);
|
assertThat(e.getMessage(), false);
|
||||||
}
|
}
|
||||||
var component = thingHandler.getDiscoveredComponent();
|
return Objects.requireNonNull(thingHandler.getDiscoveredComponent());
|
||||||
assertThat(component, CoreMatchers.notNullValue());
|
|
||||||
return component;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,7 +140,7 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
*/
|
*/
|
||||||
protected static void assertChannel(AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> component,
|
protected static void assertChannel(AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> component,
|
||||||
String channelId, String stateTopic, String commandTopic, String label, Class<? extends Value> valueClass) {
|
String channelId, String stateTopic, String commandTopic, String label, Class<? extends Value> valueClass) {
|
||||||
var stateChannel = component.getChannel(channelId);
|
var stateChannel = Objects.requireNonNull(component.getChannel(channelId));
|
||||||
assertChannel(stateChannel, stateTopic, commandTopic, label, valueClass);
|
assertChannel(stateChannel, stateTopic, commandTopic, label, valueClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +235,6 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNullByDefault
|
|
||||||
protected static class LatchThingHandler extends HomeAssistantThingHandler {
|
protected static class LatchThingHandler extends HomeAssistantThingHandler {
|
||||||
private @Nullable CountDownLatch latch;
|
private @Nullable CountDownLatch latch;
|
||||||
private @Nullable AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> discoveredComponent;
|
private @Nullable AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> discoveredComponent;
|
||||||
@ -247,6 +245,7 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
super(thing, channelTypeProvider, transformationServiceProvider, subscribeTimeout, attributeReceiveTimeout);
|
super(thing, channelTypeProvider, transformationServiceProvider, subscribeTimeout, attributeReceiveTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void componentDiscovered(HaID homeAssistantTopicID, AbstractComponent<@NonNull ?> component) {
|
public void componentDiscovered(HaID homeAssistantTopicID, AbstractComponent<@NonNull ?> component) {
|
||||||
accept(List.of(component));
|
accept(List.of(component));
|
||||||
discoveredComponent = component;
|
discoveredComponent = component;
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.TextValue;
|
import org.openhab.binding.mqtt.generic.values.TextValue;
|
||||||
import org.openhab.core.library.types.StringType;
|
import org.openhab.core.library.types.StringType;
|
||||||
@ -27,6 +28,7 @@ import org.openhab.core.library.types.StringType;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
@NonNullByDefault
|
||||||
public class AlarmControlPanelTests extends AbstractComponentTests {
|
public class AlarmControlPanelTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "alarm_control_panel/0x0000000000000000_alarm_control_panel_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "alarm_control_panel/0x0000000000000000_alarm_control_panel_zigbee2mqtt";
|
||||||
|
|
||||||
@ -89,6 +91,7 @@ public class AlarmControlPanelTests extends AbstractComponentTests {
|
|||||||
assertPublished("zigbee2mqtt/alarm/set/state", "ARM_HOME_");
|
assertPublished("zigbee2mqtt/alarm/set/state", "ARM_HOME_");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
@ -27,6 +28,7 @@ import org.openhab.core.types.UnDefType;
|
|||||||
*
|
*
|
||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class BinarySensorTests extends AbstractComponentTests {
|
public class BinarySensorTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "binary_sensor/0x0000000000000000_binary_sensor_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "binary_sensor/0x0000000000000000_binary_sensor_zigbee2mqtt";
|
||||||
|
|
||||||
@ -148,6 +150,7 @@ public class BinarySensorTests extends AbstractComponentTests {
|
|||||||
waitForAssert(() -> assertState(component, BinarySensor.SENSOR_CHANNEL_ID, UnDefType.UNDEF), 10000, 200);
|
waitForAssert(() -> assertState(component, BinarySensor.SENSOR_CHANNEL_ID, UnDefType.UNDEF), 10000, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.ImageValue;
|
import org.openhab.binding.mqtt.generic.values.ImageValue;
|
||||||
import org.openhab.core.library.types.RawType;
|
import org.openhab.core.library.types.RawType;
|
||||||
@ -26,6 +27,7 @@ import org.openhab.core.library.types.RawType;
|
|||||||
*
|
*
|
||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class CameraTests extends AbstractComponentTests {
|
public class CameraTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "camera/0x0000000000000000_camera_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "camera/0x0000000000000000_camera_zigbee2mqtt";
|
||||||
|
|
||||||
@ -63,6 +65,7 @@ public class CameraTests extends AbstractComponentTests {
|
|||||||
assertState(component, Camera.CAMERA_CHANNEL_ID, new RawType(imageBytes, "image/png"));
|
assertState(component, Camera.CAMERA_CHANNEL_ID, new RawType(imageBytes, "image/png"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.NumberValue;
|
import org.openhab.binding.mqtt.generic.values.NumberValue;
|
||||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
@ -34,6 +35,7 @@ import org.openhab.core.library.unit.SIUnits;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
@NonNullByDefault
|
||||||
public class ClimateTests extends AbstractComponentTests {
|
public class ClimateTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "climate/0x847127fffe11dd6a_climate_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "climate/0x847127fffe11dd6a_climate_zigbee2mqtt";
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.RollershutterValue;
|
import org.openhab.binding.mqtt.generic.values.RollershutterValue;
|
||||||
import org.openhab.core.library.types.PercentType;
|
import org.openhab.core.library.types.PercentType;
|
||||||
@ -28,6 +29,7 @@ import org.openhab.core.library.types.StopMoveType;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
@NonNullByDefault
|
||||||
public class CoverTests extends AbstractComponentTests {
|
public class CoverTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "cover/0x0000000000000000_cover_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "cover/0x0000000000000000_cover_zigbee2mqtt";
|
||||||
|
|
||||||
@ -82,6 +84,7 @@ public class CoverTests extends AbstractComponentTests {
|
|||||||
assertPublished("zigbee2mqtt/cover/set/state", "STOP_", 2);
|
assertPublished("zigbee2mqtt/cover/set/state", "STOP_", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
@ -27,6 +28,7 @@ import org.openhab.core.library.types.OnOffType;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ALL")
|
@SuppressWarnings("ALL")
|
||||||
|
@NonNullByDefault
|
||||||
public class FanTests extends AbstractComponentTests {
|
public class FanTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "fan/0x0000000000000000_fan_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "fan/0x0000000000000000_fan_zigbee2mqtt";
|
||||||
|
|
||||||
@ -78,6 +80,7 @@ public class FanTests extends AbstractComponentTests {
|
|||||||
assertPublished("zigbee2mqtt/fan/set/state", "ON_");
|
assertPublished("zigbee2mqtt/fan/set/state", "ON_");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,12 @@ import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
||||||
@ -36,6 +37,7 @@ import com.google.gson.GsonBuilder;
|
|||||||
/**
|
/**
|
||||||
* @author Jochen Klein - Initial contribution
|
* @author Jochen Klein - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HAConfigurationTests {
|
public class HAConfigurationTests {
|
||||||
|
|
||||||
private Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory())
|
private Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory())
|
||||||
@ -53,7 +55,7 @@ public class HAConfigurationTests {
|
|||||||
}
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new UncheckedIOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +81,7 @@ public class HAConfigurationTests {
|
|||||||
if (device != null) {
|
if (device != null) {
|
||||||
assertThat(device.getIdentifiers(), contains("H"));
|
assertThat(device.getIdentifiers(), contains("H"));
|
||||||
assertThat(device.getConnections(), is(notNullValue()));
|
assertThat(device.getConnections(), is(notNullValue()));
|
||||||
List<@NonNull Connection> connections = device.getConnections();
|
List<Connection> connections = device.getConnections();
|
||||||
if (connections != null) {
|
if (connections != null) {
|
||||||
assertThat(connections.get(0).getType(), is("I1"));
|
assertThat(connections.get(0).getType(), is("I1"));
|
||||||
assertThat(connections.get(0).getIdentifier(), is("I2"));
|
assertThat(connections.get(0).getIdentifier(), is("I2"));
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.ColorValue;
|
import org.openhab.binding.mqtt.generic.values.ColorValue;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
@ -28,6 +29,7 @@ import org.openhab.core.library.types.OnOffType;
|
|||||||
*
|
*
|
||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class LightTests extends AbstractComponentTests {
|
public class LightTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "light/0x0000000000000000_light_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "light/0x0000000000000000_light_zigbee2mqtt";
|
||||||
|
|
||||||
@ -85,6 +87,7 @@ public class LightTests extends AbstractComponentTests {
|
|||||||
assertPublished("zigbee2mqtt/light/set/state", "0,0,0");
|
assertPublished("zigbee2mqtt/light/set/state", "0,0,0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
@ -27,6 +28,7 @@ import org.openhab.core.library.types.OnOffType;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ALL")
|
@SuppressWarnings("ALL")
|
||||||
|
@NonNullByDefault
|
||||||
public class LockTests extends AbstractComponentTests {
|
public class LockTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "lock/0x0000000000000000_lock_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "lock/0x0000000000000000_lock_zigbee2mqtt";
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.NumberValue;
|
import org.openhab.binding.mqtt.generic.values.NumberValue;
|
||||||
import org.openhab.core.library.types.QuantityType;
|
import org.openhab.core.library.types.QuantityType;
|
||||||
@ -29,6 +30,7 @@ import org.openhab.core.types.UnDefType;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
@NonNullByDefault
|
||||||
public class SensorTests extends AbstractComponentTests {
|
public class SensorTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "sensor/0x0000000000000000_sensor_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "sensor/0x0000000000000000_sensor_zigbee2mqtt";
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
@ -27,6 +28,7 @@ import org.openhab.core.library.types.OnOffType;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
@NonNullByDefault
|
||||||
public class SwitchTests extends AbstractComponentTests {
|
public class SwitchTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "switch/0x847127fffe11dd6a_auto_lock_zigbee2mqtt";
|
public static final String CONFIG_TOPIC = "switch/0x847127fffe11dd6a_auto_lock_zigbee2mqtt";
|
||||||
|
|
||||||
@ -117,6 +119,7 @@ public class SwitchTests extends AbstractComponentTests {
|
|||||||
assertPublished("zigbee2mqtt/th1/set/auto_lock", "AUTO");
|
assertPublished("zigbee2mqtt/th1/set/auto_lock", "AUTO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
import org.openhab.binding.mqtt.generic.values.PercentageValue;
|
import org.openhab.binding.mqtt.generic.values.PercentageValue;
|
||||||
@ -32,6 +33,7 @@ import org.openhab.core.types.UnDefType;
|
|||||||
* @author Anton Kharuzhy - Initial contribution
|
* @author Anton Kharuzhy - Initial contribution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
@NonNullByDefault
|
||||||
public class VacuumTests extends AbstractComponentTests {
|
public class VacuumTests extends AbstractComponentTests {
|
||||||
public static final String CONFIG_TOPIC = "vacuum/rockrobo_vacuum";
|
public static final String CONFIG_TOPIC = "vacuum/rockrobo_vacuum";
|
||||||
|
|
||||||
@ -248,6 +250,7 @@ public class VacuumTests extends AbstractComponentTests {
|
|||||||
assertPublished("vacuum/send_command", "custom_command");
|
assertPublished("vacuum/send_command", "custom_command");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected Set<String> getConfigTopics() {
|
protected Set<String> getConfigTopics() {
|
||||||
return Set.of(CONFIG_TOPIC);
|
return Set.of(CONFIG_TOPIC);
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homeassistant.internal.discovery;
|
package org.openhab.binding.mqtt.homeassistant.internal.discovery;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.hasItems;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -46,8 +45,9 @@ import org.openhab.core.thing.ThingUID;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "ConstantConditions", "unchecked" })
|
@SuppressWarnings({ "ConstantConditions", "unchecked" })
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@NonNullByDefault
|
||||||
public class HomeAssistantDiscoveryTests extends AbstractHomeAssistantTests {
|
public class HomeAssistantDiscoveryTests extends AbstractHomeAssistantTests {
|
||||||
private HomeAssistantDiscovery discovery;
|
private @NonNullByDefault({}) HomeAssistantDiscovery discovery;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeEach() {
|
public void beforeEach() {
|
||||||
@ -89,11 +89,11 @@ public class HomeAssistantDiscoveryTests extends AbstractHomeAssistantTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNullByDefault
|
|
||||||
private static class LatchDiscoveryListener implements DiscoveryListener {
|
private static class LatchDiscoveryListener implements DiscoveryListener {
|
||||||
private final CopyOnWriteArrayList<DiscoveryResult> discoveryResults = new CopyOnWriteArrayList<>();
|
private final CopyOnWriteArrayList<DiscoveryResult> discoveryResults = new CopyOnWriteArrayList<>();
|
||||||
private @Nullable CountDownLatch latch;
|
private @Nullable CountDownLatch latch;
|
||||||
|
|
||||||
|
@Override
|
||||||
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
|
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
|
||||||
discoveryResults.add(result);
|
discoveryResults.add(result);
|
||||||
if (latch != null) {
|
if (latch != null) {
|
||||||
@ -101,9 +101,11 @@ public class HomeAssistantDiscoveryTests extends AbstractHomeAssistantTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
|
public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public @Nullable Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
|
public @Nullable Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
|
||||||
@Nullable Collection<ThingTypeUID> thingTypeUIDs, @Nullable ThingUID bridgeUID) {
|
@Nullable Collection<ThingTypeUID> thingTypeUIDs, @Nullable ThingUID bridgeUID) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
@ -13,20 +13,15 @@
|
|||||||
package org.openhab.binding.mqtt.homeassistant.internal.handler;
|
package org.openhab.binding.mqtt.homeassistant.internal.handler;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.Mockito.eq;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.timeout;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.hamcrest.CoreMatchers;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -47,6 +42,7 @@ import org.openhab.core.thing.binding.ThingHandlerCallback;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "ConstantConditions" })
|
@SuppressWarnings({ "ConstantConditions" })
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@NonNullByDefault
|
||||||
public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
||||||
private static final int SUBSCRIBE_TIMEOUT = 10000;
|
private static final int SUBSCRIBE_TIMEOUT = 10000;
|
||||||
private static final int ATTRIBUTE_RECEIVE_TIMEOUT = 2000;
|
private static final int ATTRIBUTE_RECEIVE_TIMEOUT = 2000;
|
||||||
@ -62,8 +58,8 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
|||||||
private static final List<String> MQTT_TOPICS = CONFIG_TOPICS.stream()
|
private static final List<String> MQTT_TOPICS = CONFIG_TOPICS.stream()
|
||||||
.map(AbstractHomeAssistantTests::configTopicToMqtt).collect(Collectors.toList());
|
.map(AbstractHomeAssistantTests::configTopicToMqtt).collect(Collectors.toList());
|
||||||
|
|
||||||
private @Mock ThingHandlerCallback callback;
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
private HomeAssistantThingHandler thingHandler;
|
private @NonNullByDefault({}) HomeAssistantThingHandler thingHandler;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
@ -72,12 +68,12 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
|||||||
config.put(HandlerConfiguration.PROPERTY_BASETOPIC, HandlerConfiguration.DEFAULT_BASETOPIC);
|
config.put(HandlerConfiguration.PROPERTY_BASETOPIC, HandlerConfiguration.DEFAULT_BASETOPIC);
|
||||||
config.put(HandlerConfiguration.PROPERTY_TOPICS, CONFIG_TOPICS);
|
config.put(HandlerConfiguration.PROPERTY_TOPICS, CONFIG_TOPICS);
|
||||||
|
|
||||||
when(callback.getBridge(eq(BRIDGE_UID))).thenReturn(bridgeThing);
|
when(callbackMock.getBridge(eq(BRIDGE_UID))).thenReturn(bridgeThing);
|
||||||
|
|
||||||
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, transformationServiceProvider,
|
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, transformationServiceProvider,
|
||||||
SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
||||||
thingHandler.setConnection(bridgeConnection);
|
thingHandler.setConnection(bridgeConnection);
|
||||||
thingHandler.setCallback(callback);
|
thingHandler.setCallback(callbackMock);
|
||||||
thingHandler = spy(thingHandler);
|
thingHandler = spy(thingHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +82,7 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
|||||||
// When initialize
|
// When initialize
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
|
|
||||||
verify(callback).statusUpdated(eq(haThing), any());
|
verify(callbackMock).statusUpdated(eq(haThing), any());
|
||||||
// Expect a call to the bridge status changed, the start, the propertiesChanged method
|
// Expect a call to the bridge status changed, the start, the propertiesChanged method
|
||||||
verify(thingHandler).bridgeStatusChanged(any());
|
verify(thingHandler).bridgeStatusChanged(any());
|
||||||
verify(thingHandler, timeout(SUBSCRIBE_TIMEOUT)).start(any());
|
verify(thingHandler, timeout(SUBSCRIBE_TIMEOUT)).start(any());
|
||||||
|
@ -13,12 +13,9 @@
|
|||||||
package org.openhab.binding.mqtt.homie.generic.internal;
|
package org.openhab.binding.mqtt.homie.generic.internal;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
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.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
|
||||||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||||
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
|
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
|
||||||
import org.openhab.binding.mqtt.homie.internal.handler.HomieThingHandler;
|
import org.openhab.binding.mqtt.homie.internal.handler.HomieThingHandler;
|
||||||
@ -45,9 +42,8 @@ import org.osgi.service.component.annotations.Reference;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class MqttThingHandlerFactory extends BaseThingHandlerFactory implements TransformationServiceProvider {
|
public class MqttThingHandlerFactory extends BaseThingHandlerFactory implements TransformationServiceProvider {
|
||||||
private @NonNullByDefault({}) MqttChannelTypeProvider typeProvider;
|
private @NonNullByDefault({}) MqttChannelTypeProvider typeProvider;
|
||||||
private @NonNullByDefault({}) MqttChannelStateDescriptionProvider stateDescriptionProvider;
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set
|
||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
|
.of(MqttBindingConstants.HOMIE300_MQTT_THING);
|
||||||
.of(MqttBindingConstants.HOMIE300_MQTT_THING).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
@ -66,15 +62,6 @@ public class MqttThingHandlerFactory extends BaseThingHandlerFactory implements
|
|||||||
super.deactivate(componentContext);
|
super.deactivate(componentContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Reference
|
|
||||||
protected void setStateDescriptionProvider(MqttChannelStateDescriptionProvider stateDescription) {
|
|
||||||
this.stateDescriptionProvider = stateDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void unsetStateDescriptionProvider(MqttChannelStateDescriptionProvider stateDescription) {
|
|
||||||
this.stateDescriptionProvider = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Reference
|
@Reference
|
||||||
protected void setChannelProvider(MqttChannelTypeProvider provider) {
|
protected void setChannelProvider(MqttChannelTypeProvider provider) {
|
||||||
this.typeProvider = provider;
|
this.typeProvider = provider;
|
||||||
|
@ -14,6 +14,7 @@ package org.openhab.binding.mqtt.homie.internal.homie300;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -275,8 +276,9 @@ public class Device implements AbstractMqttAttributeClass.AttributeChanged {
|
|||||||
|
|
||||||
CompletableFuture<@Nullable Void> applyNodes(MqttBrokerConnection connection, ScheduledExecutorService scheduler,
|
CompletableFuture<@Nullable Void> applyNodes(MqttBrokerConnection connection, ScheduledExecutorService scheduler,
|
||||||
int timeout) {
|
int timeout) {
|
||||||
return nodes.apply(attributes.nodes, node -> node.subscribe(connection, scheduler, timeout), this::createNode,
|
return nodes.apply(Objects.requireNonNull(attributes.nodes),
|
||||||
this::notifyNodeRemoved).exceptionally(e -> {
|
node -> node.subscribe(connection, scheduler, timeout), this::createNode, this::notifyNodeRemoved)
|
||||||
|
.exceptionally(e -> {
|
||||||
logger.warn("Could not subscribe", e);
|
logger.warn("Could not subscribe", e);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -311,15 +313,11 @@ public class Device implements AbstractMqttAttributeClass.AttributeChanged {
|
|||||||
* @return Returns a list of relative topics
|
* @return Returns a list of relative topics
|
||||||
*/
|
*/
|
||||||
public List<String> getRetainedTopics() {
|
public List<String> getRetainedTopics() {
|
||||||
List<String> topics = new ArrayList<>();
|
List<String> topics = new ArrayList<>(Stream.of(this.attributes.getClass().getDeclaredFields())
|
||||||
|
.map(f -> String.format("%s/$%s", this.deviceID, f.getName())).collect(Collectors.toList()));
|
||||||
|
|
||||||
topics.addAll(Stream.of(this.attributes.getClass().getDeclaredFields()).map(f -> {
|
this.nodes.stream().map(n -> n.getRetainedTopics().stream().map(a -> String.format("%s/%s", this.deviceID, a))
|
||||||
return String.format("%s/$%s", this.deviceID, f.getName());
|
.collect(Collectors.toList())).collect(Collectors.toList()).forEach(topics::addAll);
|
||||||
}).collect(Collectors.toList()));
|
|
||||||
|
|
||||||
this.nodes.stream().map(n -> n.getRetainedTopics().stream().map(a -> {
|
|
||||||
return String.format("%s/%s", this.deviceID, a);
|
|
||||||
}).collect(Collectors.toList())).collect(Collectors.toList()).forEach(topics::addAll);
|
|
||||||
|
|
||||||
return topics;
|
return topics;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homie.internal.homie300;
|
package org.openhab.binding.mqtt.homie.internal.homie300;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.mqtt.generic.mapping.AbstractMqttAttributeClass;
|
import org.openhab.binding.mqtt.generic.mapping.AbstractMqttAttributeClass;
|
||||||
import org.openhab.binding.mqtt.generic.mapping.MQTTvalueTransform;
|
import org.openhab.binding.mqtt.generic.mapping.MQTTvalueTransform;
|
||||||
import org.openhab.binding.mqtt.generic.mapping.MandatoryField;
|
import org.openhab.binding.mqtt.generic.mapping.MandatoryField;
|
||||||
@ -24,6 +25,7 @@ import org.openhab.binding.mqtt.generic.mapping.TopicPrefix;
|
|||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
@TopicPrefix
|
@TopicPrefix
|
||||||
|
@NonNullByDefault
|
||||||
public class DeviceAttributes extends AbstractMqttAttributeClass {
|
public class DeviceAttributes extends AbstractMqttAttributeClass {
|
||||||
// Lower-case enum value names required. Those are identifiers for the MQTT/homie protocol.
|
// Lower-case enum value names required. Those are identifiers for the MQTT/homie protocol.
|
||||||
public enum ReadyState {
|
public enum ReadyState {
|
||||||
@ -36,13 +38,13 @@ public class DeviceAttributes extends AbstractMqttAttributeClass {
|
|||||||
alert
|
alert
|
||||||
}
|
}
|
||||||
|
|
||||||
public @MandatoryField String homie;
|
public @MandatoryField @Nullable String homie;
|
||||||
public @MandatoryField String name;
|
public @MandatoryField @Nullable String name;
|
||||||
public @MandatoryField ReadyState state = ReadyState.unknown;
|
public @MandatoryField ReadyState state = ReadyState.unknown;
|
||||||
public @MandatoryField @MQTTvalueTransform(splitCharacter = ",") String[] nodes;
|
public @MandatoryField @MQTTvalueTransform(splitCharacter = ",") String @Nullable [] nodes;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Object getFieldsOf() {
|
public Object getFieldsOf() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ package org.openhab.binding.mqtt.homie.internal.homie300;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -173,8 +174,9 @@ public class Node implements AbstractMqttAttributeClass.AttributeChanged {
|
|||||||
|
|
||||||
protected CompletableFuture<@Nullable Void> applyProperties(MqttBrokerConnection connection,
|
protected CompletableFuture<@Nullable Void> applyProperties(MqttBrokerConnection connection,
|
||||||
ScheduledExecutorService scheduler, int timeout) {
|
ScheduledExecutorService scheduler, int timeout) {
|
||||||
return properties.apply(attributes.properties, prop -> prop.subscribe(connection, scheduler, timeout),
|
return properties.apply(Objects.requireNonNull(attributes.properties),
|
||||||
this::createProperty, this::notifyPropertyRemoved).exceptionally(e -> {
|
prop -> prop.subscribe(connection, scheduler, timeout), this::createProperty,
|
||||||
|
this::notifyPropertyRemoved).exceptionally(e -> {
|
||||||
logger.warn("Could not subscribe", e);
|
logger.warn("Could not subscribe", e);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -189,10 +191,8 @@ public class Node implements AbstractMqttAttributeClass.AttributeChanged {
|
|||||||
// Special case: Not all fields were known before
|
// Special case: Not all fields were known before
|
||||||
if (!attributes.isComplete()) {
|
if (!attributes.isComplete()) {
|
||||||
attributesReceived(connection, scheduler, 500);
|
attributesReceived(connection, scheduler, 500);
|
||||||
} else {
|
} else if ("properties".equals(name)) {
|
||||||
if ("properties".equals(name)) {
|
applyProperties(connection, scheduler, 500);
|
||||||
applyProperties(connection, scheduler, 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
callback.nodeAddedOrChanged(this);
|
callback.nodeAddedOrChanged(this);
|
||||||
}
|
}
|
||||||
@ -208,15 +208,12 @@ public class Node implements AbstractMqttAttributeClass.AttributeChanged {
|
|||||||
* @return Returns a list of relative topics
|
* @return Returns a list of relative topics
|
||||||
*/
|
*/
|
||||||
public List<String> getRetainedTopics() {
|
public List<String> getRetainedTopics() {
|
||||||
List<String> topics = new ArrayList<>();
|
List<String> topics = new ArrayList<>(Stream.of(this.attributes.getClass().getDeclaredFields())
|
||||||
|
.map(f -> String.format("%s/$%s", this.nodeID, f.getName())).collect(Collectors.toList()));
|
||||||
|
|
||||||
topics.addAll(Stream.of(this.attributes.getClass().getDeclaredFields()).map(f -> {
|
this.properties.stream().map(p -> p.getRetainedTopics().stream()
|
||||||
return String.format("%s/$%s", this.nodeID, f.getName());
|
.map(a -> String.format("%s/%s", this.nodeID, a)).collect(Collectors.toList()))
|
||||||
}).collect(Collectors.toList()));
|
.collect(Collectors.toList()).forEach(topics::addAll);
|
||||||
|
|
||||||
this.properties.stream().map(p -> p.getRetainedTopics().stream().map(a -> {
|
|
||||||
return String.format("%s/%s", this.nodeID, a);
|
|
||||||
}).collect(Collectors.toList())).collect(Collectors.toList()).forEach(topics::addAll);
|
|
||||||
|
|
||||||
return topics;
|
return topics;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homie.internal.homie300;
|
package org.openhab.binding.mqtt.homie.internal.homie300;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.mqtt.generic.mapping.AbstractMqttAttributeClass;
|
import org.openhab.binding.mqtt.generic.mapping.AbstractMqttAttributeClass;
|
||||||
import org.openhab.binding.mqtt.generic.mapping.MQTTvalueTransform;
|
import org.openhab.binding.mqtt.generic.mapping.MQTTvalueTransform;
|
||||||
import org.openhab.binding.mqtt.generic.mapping.MandatoryField;
|
import org.openhab.binding.mqtt.generic.mapping.MandatoryField;
|
||||||
@ -24,14 +25,15 @@ import org.openhab.binding.mqtt.generic.mapping.TopicPrefix;
|
|||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
@TopicPrefix
|
@TopicPrefix
|
||||||
|
@NonNullByDefault
|
||||||
public class NodeAttributes extends AbstractMqttAttributeClass {
|
public class NodeAttributes extends AbstractMqttAttributeClass {
|
||||||
public @MandatoryField String name;
|
public @MandatoryField String name = "";
|
||||||
public @MandatoryField @MQTTvalueTransform(splitCharacter = ",") String[] properties;
|
public @MandatoryField @MQTTvalueTransform(splitCharacter = ",") String @Nullable [] properties;
|
||||||
// Type has no meaning yet and is currently purely of textual, descriptive nature
|
// Type has no meaning yet and is currently purely of textual, descriptive nature
|
||||||
public String type;
|
public @Nullable String type;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Object getFieldsOf() {
|
public Object getFieldsOf() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import static org.mockito.Mockito.*;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@ -40,8 +41,9 @@ import org.openhab.binding.mqtt.homie.internal.homie300.NodeAttributes;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class HomieChildMapTests {
|
public class HomieChildMapTests {
|
||||||
private @Mock DeviceCallback callback;
|
private @Mock @NonNullByDefault({}) DeviceCallback callbackMock;
|
||||||
|
|
||||||
private final String deviceID = ThingChannelConstants.TEST_HOMIE_THING.getId();
|
private final String deviceID = ThingChannelConstants.TEST_HOMIE_THING.getId();
|
||||||
private final String deviceTopic = "homie/" + deviceID;
|
private final String deviceTopic = "homie/" + deviceID;
|
||||||
@ -52,7 +54,7 @@ public class HomieChildMapTests {
|
|||||||
ChildMap<Node> subject = new ChildMap<>();
|
ChildMap<Node> subject = new ChildMap<>();
|
||||||
|
|
||||||
private Node createNode(String id) {
|
private Node createNode(String id) {
|
||||||
Node node = new Node(deviceTopic, id, ThingChannelConstants.TEST_HOMIE_THING, callback,
|
Node node = new Node(deviceTopic, id, ThingChannelConstants.TEST_HOMIE_THING, callbackMock,
|
||||||
spy(new NodeAttributes()));
|
spy(new NodeAttributes()));
|
||||||
doReturn(future).when(node.attributes).subscribeAndReceive(any(), any(), anyString(), any(), anyInt());
|
doReturn(future).when(node.attributes).subscribeAndReceive(any(), any(), anyString(), any(), anyInt());
|
||||||
doReturn(future).when(node.attributes).unsubscribe();
|
doReturn(future).when(node.attributes).unsubscribe();
|
||||||
@ -60,7 +62,7 @@ public class HomieChildMapTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removedNode(Node node) {
|
private void removedNode(Node node) {
|
||||||
callback.nodeRemoved(node);
|
callbackMock.nodeRemoved(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AddedAction implements Function<Node, CompletableFuture<Void>> {
|
public static class AddedAction implements Function<Node, CompletableFuture<Void>> {
|
||||||
@ -85,6 +87,6 @@ public class HomieChildMapTests {
|
|||||||
|
|
||||||
Node soonToBeRemoved = subject.get("def");
|
Node soonToBeRemoved = subject.get("def");
|
||||||
subject.apply(new String[] { "abc" }, addedAction, this::createNode, this::removedNode);
|
subject.apply(new String[] { "abc" }, addedAction, this::createNode, this::removedNode);
|
||||||
verify(callback).nodeRemoved(eq(soonToBeRemoved));
|
verify(callbackMock).nodeRemoved(eq(soonToBeRemoved));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
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.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -82,20 +82,20 @@ import org.openhab.core.types.TypeParser;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class HomieThingHandlerTests {
|
public class HomieThingHandlerTests {
|
||||||
|
|
||||||
private Thing thing;
|
private @Mock @NonNullByDefault({}) AbstractBrokerHandler bridgeHandlerMock;
|
||||||
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
|
private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
|
||||||
|
private @Mock @NonNullByDefault({}) ScheduledExecutorService schedulerMock;
|
||||||
|
private @Mock @NonNullByDefault({}) ScheduledFuture<?> scheduledFutureMock;
|
||||||
|
private @Mock @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistryMock;
|
||||||
|
|
||||||
private @Mock AbstractBrokerHandler bridgeHandler;
|
private @NonNullByDefault({}) Thing thing;
|
||||||
private @Mock ThingHandlerCallback callback;
|
private @NonNullByDefault({}) HomieThingHandler thingHandler;
|
||||||
private @Mock MqttBrokerConnection connection;
|
|
||||||
private @Mock ScheduledExecutorService scheduler;
|
|
||||||
private @Mock ScheduledFuture<?> scheduledFuture;
|
|
||||||
private @Mock ThingTypeRegistry thingTypeRegistry;
|
|
||||||
|
|
||||||
private HomieThingHandler thingHandler;
|
private final MqttChannelTypeProvider channelTypeProvider = new MqttChannelTypeProvider(thingTypeRegistryMock);
|
||||||
|
|
||||||
private final MqttChannelTypeProvider channelTypeProvider = new MqttChannelTypeProvider(thingTypeRegistry);
|
|
||||||
|
|
||||||
private final String deviceID = ThingChannelConstants.TEST_HOMIE_THING.getId();
|
private final String deviceID = ThingChannelConstants.TEST_HOMIE_THING.getId();
|
||||||
private final String deviceTopic = "homie/" + deviceID;
|
private final String deviceTopic = "homie/" + deviceID;
|
||||||
@ -116,26 +116,27 @@ public class HomieThingHandlerTests {
|
|||||||
thing.setStatusInfo(thingStatus);
|
thing.setStatusInfo(thingStatus);
|
||||||
|
|
||||||
// Return the mocked connection object if the bridge handler is asked for it
|
// 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));
|
||||||
|
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribe(any(), any());
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribe(any(), any());
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).unsubscribeAll();
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).unsubscribeAll();
|
||||||
doReturn(CompletableFuture.completedFuture(true)).when(connection).publish(any(), any(), anyInt(),
|
doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).publish(any(), any(), anyInt(),
|
||||||
anyBoolean());
|
anyBoolean());
|
||||||
|
|
||||||
doReturn(false).when(scheduledFuture).isDone();
|
doReturn(false).when(scheduledFutureMock).isDone();
|
||||||
doReturn(scheduledFuture).when(scheduler).schedule(any(Runnable.class), anyLong(), any(TimeUnit.class));
|
doReturn(scheduledFutureMock).when(schedulerMock).schedule(any(Runnable.class), anyLong(), any(TimeUnit.class));
|
||||||
|
|
||||||
final HomieThingHandler handler = new HomieThingHandler(thing, channelTypeProvider, 1000, 30, 5);
|
final HomieThingHandler handler = new HomieThingHandler(thing, channelTypeProvider, 1000, 30, 5);
|
||||||
thingHandler = spy(handler);
|
thingHandler = spy(handler);
|
||||||
thingHandler.setCallback(callback);
|
thingHandler.setCallback(callbackMock);
|
||||||
final Device device = new Device(thing.getUID(), thingHandler, spy(new DeviceAttributes()),
|
final Device device = new Device(thing.getUID(), thingHandler, spy(new DeviceAttributes()),
|
||||||
spy(new ChildMap<>()));
|
spy(new ChildMap<>()));
|
||||||
thingHandler.setInternalObjects(spy(device), spy(new DelayedBatchProcessing<>(500, thingHandler, scheduler)));
|
thingHandler.setInternalObjects(spy(device),
|
||||||
|
spy(new DelayedBatchProcessing<>(500, thingHandler, schedulerMock)));
|
||||||
|
|
||||||
// Return the bridge handler if the thing handler asks for it
|
// 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
|
// We are by default online
|
||||||
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
doReturn(thingStatus).when(thingHandler).getBridgeStatus();
|
||||||
@ -153,7 +154,7 @@ public class HomieThingHandlerTests {
|
|||||||
// Pretend that a device state change arrived.
|
// Pretend that a device state change arrived.
|
||||||
thingHandler.device.attributes.state = ReadyState.ready;
|
thingHandler.device.attributes.state = ReadyState.ready;
|
||||||
|
|
||||||
verify(callback, times(0)).statusUpdated(eq(thing), any());
|
verify(callbackMock, times(0)).statusUpdated(eq(thing), any());
|
||||||
|
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
|
|
||||||
@ -166,8 +167,8 @@ public class HomieThingHandlerTests {
|
|||||||
|
|
||||||
assertThat(thingHandler.device.isInitialized(), is(true));
|
assertThat(thingHandler.device.isInitialized(), is(true));
|
||||||
|
|
||||||
verify(callback).statusUpdated(eq(thing), argThat((arg) -> arg.getStatus().equals(ThingStatus.ONLINE)
|
verify(callbackMock).statusUpdated(eq(thing), argThat(arg -> ThingStatus.ONLINE.equals(arg.getStatus())
|
||||||
&& arg.getStatusDetail().equals(ThingStatusDetail.NONE)));
|
&& ThingStatusDetail.NONE.equals(arg.getStatusDetail())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -182,8 +183,8 @@ public class HomieThingHandlerTests {
|
|||||||
|
|
||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
|
|
||||||
verify(callback).statusUpdated(eq(thing), argThat((arg) -> arg.getStatus().equals(ThingStatus.OFFLINE)
|
verify(callbackMock).statusUpdated(eq(thing), argThat(arg -> ThingStatus.OFFLINE.equals(arg.getStatus())
|
||||||
&& arg.getStatusDetail().equals(ThingStatusDetail.COMMUNICATION_ERROR)));
|
&& ThingStatusDetail.COMMUNICATION_ERROR.equals(arg.getStatusDetail())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -199,8 +200,8 @@ public class HomieThingHandlerTests {
|
|||||||
thingHandler.initialize();
|
thingHandler.initialize();
|
||||||
assertThat(thingHandler.device.isInitialized(), is(true));
|
assertThat(thingHandler.device.isInitialized(), is(true));
|
||||||
|
|
||||||
verify(callback).statusUpdated(eq(thing), argThat((arg) -> arg.getStatus().equals(ThingStatus.OFFLINE)
|
verify(callbackMock).statusUpdated(eq(thing), argThat(arg -> ThingStatus.OFFLINE.equals(arg.getStatus())
|
||||||
&& arg.getStatusDetail().equals(ThingStatusDetail.GONE)));
|
&& ThingStatusDetail.GONE.equals(arg.getStatusDetail())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
@ -222,12 +223,12 @@ 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);
|
||||||
|
|
||||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||||
// we need to set a channel value first, undefined values ignored on REFRESH
|
// we need to set a channel value first, undefined values ignored on REFRESH
|
||||||
property.getChannelState().getCache().update(new StringType("testString"));
|
property.getChannelState().getCache().update(new StringType("testString"));
|
||||||
|
|
||||||
thingHandler.handleCommand(property.channelUID, RefreshType.REFRESH);
|
thingHandler.handleCommand(property.channelUID, RefreshType.REFRESH);
|
||||||
verify(callback).stateUpdated(argThat(arg -> property.channelUID.equals(arg)),
|
verify(callbackMock).stateUpdated(argThat(arg -> property.channelUID.equals(arg)),
|
||||||
argThat(arg -> property.getChannelState().getCache().getChannelState().equals(arg)));
|
argThat(arg -> property.getChannelState().getCache().getChannelState().equals(arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,14 +253,14 @@ public class HomieThingHandlerTests {
|
|||||||
|
|
||||||
ChannelState channelState = requireNonNull(property.getChannelState());
|
ChannelState channelState = requireNonNull(property.getChannelState());
|
||||||
assertNotNull(channelState);
|
assertNotNull(channelState);
|
||||||
ChannelStateHelper.setConnection(channelState, connection);// Pretend we called start()
|
ChannelStateHelper.setConnection(channelState, connectionMock);// Pretend we called start()
|
||||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||||
|
|
||||||
StringType updateValue = new StringType("UPDATE");
|
StringType updateValue = new StringType("UPDATE");
|
||||||
thingHandler.handleCommand(property.channelUID, updateValue);
|
thingHandler.handleCommand(property.channelUID, updateValue);
|
||||||
|
|
||||||
assertThat(property.getChannelState().getCache().getChannelState().toString(), is("UPDATE"));
|
assertThat(property.getChannelState().getCache().getChannelState().toString(), is("UPDATE"));
|
||||||
verify(connection, times(1)).publish(any(), any(), anyInt(), anyBoolean());
|
verify(connectionMock, times(1)).publish(any(), any(), anyInt(), anyBoolean());
|
||||||
|
|
||||||
// Check non writable property
|
// Check non writable property
|
||||||
property.attributes.settable = false;
|
property.attributes.settable = false;
|
||||||
@ -274,7 +275,7 @@ public class HomieThingHandlerTests {
|
|||||||
thingHandler.handleCommand(property.channelUID, updateValue);
|
thingHandler.handleCommand(property.channelUID, updateValue);
|
||||||
// Expect old value and no MQTT publish
|
// Expect old value and no MQTT publish
|
||||||
assertThat(property.getChannelState().getCache().getChannelState().toString(), is("OLDVALUE"));
|
assertThat(property.getChannelState().getCache().getChannelState().toString(), is("OLDVALUE"));
|
||||||
verify(connection, times(1)).publish(any(), any(), anyInt(), anyBoolean());
|
verify(connectionMock, times(1)).publish(any(), any(), anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +321,7 @@ public class HomieThingHandlerTests {
|
|||||||
@Test
|
@Test
|
||||||
public void propertiesChanged() throws InterruptedException, ExecutionException {
|
public void propertiesChanged() throws InterruptedException, ExecutionException {
|
||||||
thingHandler.device.initialize("homie", "device", new ArrayList<>());
|
thingHandler.device.initialize("homie", "device", new ArrayList<>());
|
||||||
ThingHandlerHelper.setConnection(thingHandler, connection);
|
ThingHandlerHelper.setConnection(thingHandler, connectionMock);
|
||||||
|
|
||||||
// Create mocked homie device tree with one node and one property
|
// Create mocked homie device tree with one node and one property
|
||||||
doAnswer(this::createSubscriberAnswer).when(thingHandler.device.attributes).createSubscriber(any(), any(),
|
doAnswer(this::createSubscriberAnswer).when(thingHandler.device.attributes).createSubscriber(any(), any(),
|
||||||
@ -355,14 +356,14 @@ public class HomieThingHandlerTests {
|
|||||||
thingHandler.delayedProcessing.forceProcessNow();
|
thingHandler.delayedProcessing.forceProcessNow();
|
||||||
|
|
||||||
// Called for the updated property + for the new channels
|
// Called for the updated property + for the new channels
|
||||||
verify(callback, atLeast(2)).thingUpdated(any());
|
verify(callbackMock, atLeast(2)).thingUpdated(any());
|
||||||
|
|
||||||
final List<@NonNull Channel> channels = thingHandler.getThing().getChannels();
|
final List<Channel> channels = thingHandler.getThing().getChannels();
|
||||||
assertThat(channels.size(), is(1));
|
assertThat(channels.size(), is(1));
|
||||||
assertThat(channels.get(0).getLabel(), is("testprop"));
|
assertThat(channels.get(0).getLabel(), is("testprop"));
|
||||||
assertThat(channels.get(0).getKind(), is(ChannelKind.STATE));
|
assertThat(channels.get(0).getKind(), is(ChannelKind.STATE));
|
||||||
|
|
||||||
final Map<@NonNull String, @NonNull String> properties = thingHandler.getThing().getProperties();
|
final Map<String, String> properties = thingHandler.getThing().getProperties();
|
||||||
assertThat(properties.get(MqttBindingConstants.HOMIE_PROPERTY_VERSION), is("3.0"));
|
assertThat(properties.get(MqttBindingConstants.HOMIE_PROPERTY_VERSION), is("3.0"));
|
||||||
assertThat(properties.size(), is(1));
|
assertThat(properties.size(), is(1));
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homie.internal.handler;
|
package org.openhab.binding.mqtt.homie.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.mqtt.homie.generic.internal.MqttBindingConstants.*;
|
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 {
|
||||||
public static final ThingUID TEST_HOMIE_THING = new ThingUID(HOMIE300_MQTT_THING, "device123");
|
public static final ThingUID TEST_HOMIE_THING = new ThingUID(HOMIE300_MQTT_THING, "device123");
|
||||||
}
|
}
|
||||||
|
@ -154,13 +154,13 @@ public class BrokerHandler extends AbstractBrokerHandler implements PinnedCallba
|
|||||||
try {
|
try {
|
||||||
Pin pin;
|
Pin pin;
|
||||||
if (config.certificate.isBlank()) {
|
if (config.certificate.isBlank()) {
|
||||||
pin = Pin.LearningPin(PinType.CERTIFICATE_TYPE);
|
pin = Pin.learningPin(PinType.CERTIFICATE_TYPE);
|
||||||
} else {
|
} else {
|
||||||
String[] split = config.certificate.split(":");
|
String[] split = config.certificate.split(":");
|
||||||
if (split.length != 2) {
|
if (split.length != 2) {
|
||||||
throw new NoSuchAlgorithmException("Algorithm is missing");
|
throw new NoSuchAlgorithmException("Algorithm is missing");
|
||||||
}
|
}
|
||||||
pin = Pin.CheckingPin(PinType.CERTIFICATE_TYPE, new PinMessageDigest(split[0]),
|
pin = Pin.checkingPin(PinType.CERTIFICATE_TYPE, new PinMessageDigest(split[0]),
|
||||||
HexUtils.hexToBytes(split[1]));
|
HexUtils.hexToBytes(split[1]));
|
||||||
}
|
}
|
||||||
trustManager.addPinning(pin);
|
trustManager.addPinning(pin);
|
||||||
@ -172,13 +172,13 @@ public class BrokerHandler extends AbstractBrokerHandler implements PinnedCallba
|
|||||||
try {
|
try {
|
||||||
Pin pin;
|
Pin pin;
|
||||||
if (config.publickey.isBlank()) {
|
if (config.publickey.isBlank()) {
|
||||||
pin = Pin.LearningPin(PinType.PUBLIC_KEY_TYPE);
|
pin = Pin.learningPin(PinType.PUBLIC_KEY_TYPE);
|
||||||
} else {
|
} else {
|
||||||
String[] split = config.publickey.split(":");
|
String[] split = config.publickey.split(":");
|
||||||
if (split.length != 2) {
|
if (split.length != 2) {
|
||||||
throw new NoSuchAlgorithmException("Algorithm is missing");
|
throw new NoSuchAlgorithmException("Algorithm is missing");
|
||||||
}
|
}
|
||||||
pin = Pin.CheckingPin(PinType.PUBLIC_KEY_TYPE, new PinMessageDigest(split[0]),
|
pin = Pin.checkingPin(PinType.PUBLIC_KEY_TYPE, new PinMessageDigest(split[0]),
|
||||||
HexUtils.hexToBytes(split[1]));
|
HexUtils.hexToBytes(split[1]));
|
||||||
}
|
}
|
||||||
trustManager.addPinning(pin);
|
trustManager.addPinning(pin);
|
||||||
|
@ -34,8 +34,6 @@ import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
|||||||
import org.openhab.core.thing.binding.ThingHandler;
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||||
import org.osgi.service.component.annotations.Component;
|
import org.osgi.service.component.annotations.Component;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MqttBrokerHandlerFactory} is responsible for creating things and thing
|
* The {@link MqttBrokerHandlerFactory} is responsible for creating things and thing
|
||||||
@ -52,8 +50,6 @@ public class MqttBrokerHandlerFactory extends BaseThingHandlerFactory implements
|
|||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
|
||||||
.of(MqttBindingConstants.BRIDGE_TYPE_BROKER).collect(Collectors.toSet());
|
.of(MqttBindingConstants.BRIDGE_TYPE_BROKER).collect(Collectors.toSet());
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(MqttBrokerHandlerFactory.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Map provides a lookup between a Topic string (key) and a Set of MQTTTopicDiscoveryParticipants (value),
|
* This Map provides a lookup between a Topic string (key) and a Set of MQTTTopicDiscoveryParticipants (value),
|
||||||
* where the Set itself is a list of participants which are subscribed to the respective Topic.
|
* where the Set itself is a list of participants which are subscribed to the respective Topic.
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.internal;
|
package org.openhab.binding.mqtt.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.mqtt.MqttBindingConstants;
|
import org.openhab.binding.mqtt.MqttBindingConstants;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ import org.openhab.core.thing.ThingUID;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class MqttThingID {
|
public class MqttThingID {
|
||||||
/**
|
/**
|
||||||
* Convert the url (tcp://122.123.111.123:1883) to a version without colons, dots or slashes
|
* Convert the url (tcp://122.123.111.123:1883) to a version without colons, dots or slashes
|
||||||
|
@ -72,11 +72,11 @@ public class Pin {
|
|||||||
this.pinData = data;
|
this.pinData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pin LearningPin(PinType pinType) {
|
public static Pin learningPin(PinType pinType) {
|
||||||
return new Pin(pinType, null, true, null);
|
return new Pin(pinType, null, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pin CheckingPin(PinType pinType, PinMessageDigest method, byte[] pinData) {
|
public static Pin checkingPin(PinType pinType, PinMessageDigest method, byte[] pinData) {
|
||||||
return new Pin(pinType, method, false, pinData);
|
return new Pin(pinType, method, false, pinData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.internal.ssl;
|
package org.openhab.binding.mqtt.internal.ssl;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Pin} is either a Public Key or Certificate Pin.
|
* A {@link Pin} is either a Public Key or Certificate Pin.
|
||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public enum PinType {
|
public enum PinType {
|
||||||
PUBLIC_KEY_TYPE,
|
PUBLIC_KEY_TYPE,
|
||||||
CERTIFICATE_TYPE
|
CERTIFICATE_TYPE
|
||||||
|
@ -14,7 +14,7 @@ package org.openhab.binding.mqtt.handler;
|
|||||||
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
@ -25,6 +25,7 @@ import org.openhab.core.thing.Bridge;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class BrokerHandlerEx extends BrokerHandler {
|
public class BrokerHandlerEx extends BrokerHandler {
|
||||||
final MqttBrokerConnectionEx e;
|
final MqttBrokerConnectionEx e;
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ public class BrokerHandlerEx extends BrokerHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @NonNull MqttBrokerConnection createBrokerConnection() throws IllegalArgumentException {
|
protected MqttBrokerConnection createBrokerConnection() throws IllegalArgumentException {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
|
|||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
|
||||||
|
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;
|
||||||
@ -48,15 +49,15 @@ import org.osgi.service.cm.ConfigurationException;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class BrokerHandlerTest extends JavaTest {
|
public class BrokerHandlerTest extends JavaTest {
|
||||||
private ScheduledExecutorService scheduler;
|
|
||||||
|
|
||||||
private @Mock ThingHandlerCallback callback;
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
private @Mock Bridge thing;
|
private @Mock @NonNullByDefault({}) Bridge thingMock;
|
||||||
|
|
||||||
private MqttBrokerConnectionEx connection;
|
private @NonNullByDefault({}) MqttBrokerConnectionEx connection;
|
||||||
|
private @NonNullByDefault({}) BrokerHandler handler;
|
||||||
private BrokerHandler handler;
|
private @NonNullByDefault({}) ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@ -66,10 +67,10 @@ public class BrokerHandlerTest extends JavaTest {
|
|||||||
connection.setConnectionCallback(connection);
|
connection.setConnectionCallback(connection);
|
||||||
|
|
||||||
Configuration config = new Configuration();
|
Configuration config = new Configuration();
|
||||||
when(thing.getConfiguration()).thenReturn(config);
|
when(thingMock.getConfiguration()).thenReturn(config);
|
||||||
|
|
||||||
handler = spy(new BrokerHandlerEx(thing, connection));
|
handler = spy(new BrokerHandlerEx(thingMock, connection));
|
||||||
handler.setCallback(callback);
|
handler.setCallback(callbackMock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
@ -80,7 +81,7 @@ public class BrokerHandlerTest extends JavaTest {
|
|||||||
@Test
|
@Test
|
||||||
public void handlerInitWithoutUrl() throws IllegalArgumentException {
|
public void handlerInitWithoutUrl() throws IllegalArgumentException {
|
||||||
// Assume it is a real handler and not a mock as defined above
|
// Assume it is a real handler and not a mock as defined above
|
||||||
handler = new BrokerHandler(thing);
|
handler = new BrokerHandler(thingMock);
|
||||||
assertThrows(IllegalArgumentException.class, this::initializeHandlerWaitForTimeout);
|
assertThrows(IllegalArgumentException.class, this::initializeHandlerWaitForTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ public class BrokerHandlerTest extends JavaTest {
|
|||||||
Configuration config = new Configuration();
|
Configuration config = new Configuration();
|
||||||
config.put("host", "10.10.0.10");
|
config.put("host", "10.10.0.10");
|
||||||
config.put("port", 80);
|
config.put("port", 80);
|
||||||
when(thing.getConfiguration()).thenReturn(config);
|
when(thingMock.getConfiguration()).thenReturn(config);
|
||||||
handler.initialize();
|
handler.initialize();
|
||||||
verify(handler).createBrokerConnection();
|
verify(handler).createBrokerConnection();
|
||||||
}
|
}
|
||||||
@ -99,7 +100,7 @@ public class BrokerHandlerTest extends JavaTest {
|
|||||||
assertThat(initializeHandlerWaitForTimeout(), is(true));
|
assertThat(initializeHandlerWaitForTimeout(), is(true));
|
||||||
|
|
||||||
ArgumentCaptor<ThingStatusInfo> statusInfoCaptor = ArgumentCaptor.forClass(ThingStatusInfo.class);
|
ArgumentCaptor<ThingStatusInfo> statusInfoCaptor = ArgumentCaptor.forClass(ThingStatusInfo.class);
|
||||||
verify(callback, atLeast(3)).statusUpdated(eq(thing), statusInfoCaptor.capture());
|
verify(callbackMock, atLeast(3)).statusUpdated(eq(thingMock), statusInfoCaptor.capture());
|
||||||
assertThat(statusInfoCaptor.getValue().getStatus(), is(ThingStatus.ONLINE));
|
assertThat(statusInfoCaptor.getValue().getStatus(), is(ThingStatus.ONLINE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ import static org.mockito.Mockito.spy;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
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;
|
||||||
@ -65,7 +64,7 @@ public class MqttBrokerConnectionEx extends MqttBrokerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull MqttConnectionState connectionState() {
|
public MqttConnectionState connectionState() {
|
||||||
return connectionStateOverwrite;
|
return connectionStateOverwrite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ package org.openhab.binding.mqtt.handler;
|
|||||||
|
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
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.MqttConnectionObserver;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
||||||
@ -24,6 +24,7 @@ import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class MqttConnectionObserverEx implements MqttConnectionObserver {
|
public class MqttConnectionObserverEx implements MqttConnectionObserver {
|
||||||
public int counter = 0;
|
public int counter = 0;
|
||||||
public Semaphore semaphore = new Semaphore(1);
|
public Semaphore semaphore = new Semaphore(1);
|
||||||
@ -33,7 +34,7 @@ public class MqttConnectionObserverEx implements MqttConnectionObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectionStateChanged(@NonNull MqttConnectionState state, @Nullable Throwable error) {
|
public void connectionStateChanged(MqttConnectionState state, @Nullable Throwable error) {
|
||||||
// First we expect a CONNECTING state and then a DISCONNECTED state change
|
// First we expect a CONNECTING state and then a DISCONNECTED state change
|
||||||
if (counter == 0 && state == MqttConnectionState.CONNECTING) {
|
if (counter == 0 && state == MqttConnectionState.CONNECTING) {
|
||||||
counter = 1;
|
counter = 1;
|
||||||
|
@ -20,6 +20,7 @@ import static org.mockito.Mockito.*;
|
|||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
|
||||||
|
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;
|
||||||
@ -44,29 +45,23 @@ import org.openhab.core.thing.binding.ThingHandlerCallback;
|
|||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@MockitoSettings(strictness = Strictness.WARN)
|
@MockitoSettings(strictness = Strictness.WARN)
|
||||||
|
@NonNullByDefault
|
||||||
public class MQTTTopicDiscoveryServiceTest {
|
public class MQTTTopicDiscoveryServiceTest {
|
||||||
private ScheduledExecutorService scheduler;
|
|
||||||
|
|
||||||
private MqttBrokerHandlerFactory subject;
|
private @Mock @NonNullByDefault({}) Bridge thingMock;
|
||||||
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
|
private @Mock @NonNullByDefault({}) MQTTTopicDiscoveryParticipant listenerMock;
|
||||||
|
|
||||||
@Mock
|
private @NonNullByDefault({}) MqttBrokerConnectionEx connection;
|
||||||
private Bridge thing;
|
private @NonNullByDefault({}) BrokerHandler handler;
|
||||||
|
private @NonNullByDefault({}) ScheduledExecutorService scheduler;
|
||||||
@Mock
|
private @NonNullByDefault({}) MqttBrokerHandlerFactory subject;
|
||||||
private ThingHandlerCallback callback;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
MQTTTopicDiscoveryParticipant listener;
|
|
||||||
|
|
||||||
private MqttBrokerConnectionEx connection;
|
|
||||||
|
|
||||||
private BrokerHandler handler;
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
scheduler = new ScheduledThreadPoolExecutor(1);
|
scheduler = new ScheduledThreadPoolExecutor(1);
|
||||||
|
|
||||||
when(thing.getUID()).thenReturn(MqttThingID.getThingUID("10.10.0.10", 80));
|
when(thingMock.getUID()).thenReturn(MqttThingID.getThingUID("10.10.0.10", 80));
|
||||||
connection = spy(new MqttBrokerConnectionEx("10.10.0.10", 80, false, "BrokerHandlerTest"));
|
connection = spy(new MqttBrokerConnectionEx("10.10.0.10", 80, false, "BrokerHandlerTest"));
|
||||||
connection.setTimeoutExecutor(scheduler, 10);
|
connection.setTimeoutExecutor(scheduler, 10);
|
||||||
connection.setConnectionCallback(connection);
|
connection.setConnectionCallback(connection);
|
||||||
@ -74,10 +69,10 @@ public class MQTTTopicDiscoveryServiceTest {
|
|||||||
Configuration config = new Configuration();
|
Configuration config = new Configuration();
|
||||||
config.put("host", "10.10.0.10");
|
config.put("host", "10.10.0.10");
|
||||||
config.put("port", 80);
|
config.put("port", 80);
|
||||||
when(thing.getConfiguration()).thenReturn(config);
|
when(thingMock.getConfiguration()).thenReturn(config);
|
||||||
|
|
||||||
handler = spy(new BrokerHandlerEx(thing, connection));
|
handler = spy(new BrokerHandlerEx(thingMock, connection));
|
||||||
handler.setCallback(callback);
|
handler.setCallback(callbackMock);
|
||||||
|
|
||||||
subject = new MqttBrokerHandlerFactory();
|
subject = new MqttBrokerHandlerFactory();
|
||||||
}
|
}
|
||||||
@ -92,13 +87,13 @@ public class MQTTTopicDiscoveryServiceTest {
|
|||||||
handler.initialize();
|
handler.initialize();
|
||||||
BrokerHandlerEx.verifyCreateBrokerConnection(handler, 1);
|
BrokerHandlerEx.verifyCreateBrokerConnection(handler, 1);
|
||||||
|
|
||||||
subject.subscribe(listener, "topic");
|
subject.subscribe(listenerMock, "topic");
|
||||||
subject.createdHandler(handler);
|
subject.createdHandler(handler);
|
||||||
assertThat(subject.discoveryTopics.get("topic"), hasItem(listener));
|
assertThat(subject.discoveryTopics.get("topic"), hasItem(listenerMock));
|
||||||
// Simulate receiving
|
// Simulate receiving
|
||||||
final byte[] bytes = "TEST".getBytes();
|
final byte[] bytes = "TEST".getBytes();
|
||||||
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
||||||
verify(listener).receivedMessage(eq(thing.getUID()), eq(connection), eq("topic"), eq(bytes));
|
verify(listenerMock).receivedMessage(eq(thingMock.getUID()), eq(connection), eq("topic"), eq(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -107,20 +102,20 @@ public class MQTTTopicDiscoveryServiceTest {
|
|||||||
BrokerHandlerEx.verifyCreateBrokerConnection(handler, 1);
|
BrokerHandlerEx.verifyCreateBrokerConnection(handler, 1);
|
||||||
|
|
||||||
subject.createdHandler(handler);
|
subject.createdHandler(handler);
|
||||||
subject.subscribe(listener, "topic");
|
subject.subscribe(listenerMock, "topic");
|
||||||
assertThat(subject.discoveryTopics.get("topic"), hasItem(listener));
|
assertThat(subject.discoveryTopics.get("topic"), hasItem(listenerMock));
|
||||||
|
|
||||||
// Simulate receiving
|
// Simulate receiving
|
||||||
final byte[] bytes = "TEST".getBytes();
|
final byte[] bytes = "TEST".getBytes();
|
||||||
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
||||||
verify(listener).receivedMessage(eq(thing.getUID()), eq(connection), eq("topic"), eq(bytes));
|
verify(listenerMock).receivedMessage(eq(thingMock.getUID()), eq(connection), eq("topic"), eq(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlerInitializeAfterSubscribe() {
|
public void handlerInitializeAfterSubscribe() {
|
||||||
subject.createdHandler(handler);
|
subject.createdHandler(handler);
|
||||||
subject.subscribe(listener, "topic");
|
subject.subscribe(listenerMock, "topic");
|
||||||
assertThat(subject.discoveryTopics.get("topic"), hasItem(listener));
|
assertThat(subject.discoveryTopics.get("topic"), hasItem(listenerMock));
|
||||||
|
|
||||||
// Init handler -> create connection
|
// Init handler -> create connection
|
||||||
handler.initialize();
|
handler.initialize();
|
||||||
@ -129,7 +124,7 @@ public class MQTTTopicDiscoveryServiceTest {
|
|||||||
// Simulate receiving
|
// Simulate receiving
|
||||||
final byte[] bytes = "TEST".getBytes();
|
final byte[] bytes = "TEST".getBytes();
|
||||||
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
||||||
verify(listener).receivedMessage(eq(thing.getUID()), eq(connection), eq("topic"), eq(bytes));
|
verify(listenerMock).receivedMessage(eq(thingMock.getUID()), eq(connection), eq("topic"), eq(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -138,12 +133,12 @@ public class MQTTTopicDiscoveryServiceTest {
|
|||||||
BrokerHandlerEx.verifyCreateBrokerConnection(handler, 1);
|
BrokerHandlerEx.verifyCreateBrokerConnection(handler, 1);
|
||||||
|
|
||||||
subject.createdHandler(handler);
|
subject.createdHandler(handler);
|
||||||
subject.subscribe(listener, "topic");
|
subject.subscribe(listenerMock, "topic");
|
||||||
assertThat(subject.discoveryTopics.get("topic"), hasItem(listener));
|
assertThat(subject.discoveryTopics.get("topic"), hasItem(listenerMock));
|
||||||
|
|
||||||
// Simulate receiving
|
// Simulate receiving
|
||||||
final byte[] bytes = "".getBytes();
|
final byte[] bytes = "".getBytes();
|
||||||
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
connection.getSubscribers().get("topic").messageArrived("topic", bytes, false);
|
||||||
verify(listener).topicVanished(eq(thing.getUID()), eq(connection), eq("topic"));
|
verify(listenerMock).topicVanished(eq(thingMock.getUID()), eq(connection), eq("topic"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import java.security.cert.CertificateException;
|
|||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNull;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.core.util.HexUtils;
|
import org.openhab.core.util.HexUtils;
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ import org.openhab.core.util.HexUtils;
|
|||||||
*
|
*
|
||||||
* @author David Graeff - Initial contribution
|
* @author David Graeff - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class PinningSSLContextProviderTest {
|
public class PinningSSLContextProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -61,7 +62,7 @@ public class PinningSSLContextProviderTest {
|
|||||||
@Test
|
@Test
|
||||||
public void certPinCallsX509CertificateGetEncoded() throws NoSuchAlgorithmException, CertificateException {
|
public void certPinCallsX509CertificateGetEncoded() throws NoSuchAlgorithmException, CertificateException {
|
||||||
PinTrustManager pinTrustManager = new PinTrustManager();
|
PinTrustManager pinTrustManager = new PinTrustManager();
|
||||||
pinTrustManager.addPinning(Pin.LearningPin(PinType.CERTIFICATE_TYPE));
|
pinTrustManager.addPinning(Pin.learningPin(PinType.CERTIFICATE_TYPE));
|
||||||
|
|
||||||
// Mock a certificate
|
// Mock a certificate
|
||||||
X509Certificate certificate = mock(X509Certificate.class);
|
X509Certificate certificate = mock(X509Certificate.class);
|
||||||
@ -77,7 +78,7 @@ public class PinningSSLContextProviderTest {
|
|||||||
@Test
|
@Test
|
||||||
public void pubKeyPinCallsX509CertificateGetPublicKey() throws NoSuchAlgorithmException, CertificateException {
|
public void pubKeyPinCallsX509CertificateGetPublicKey() throws NoSuchAlgorithmException, CertificateException {
|
||||||
PinTrustManager pinTrustManager = new PinTrustManager();
|
PinTrustManager pinTrustManager = new PinTrustManager();
|
||||||
pinTrustManager.addPinning(Pin.LearningPin(PinType.PUBLIC_KEY_TYPE));
|
pinTrustManager.addPinning(Pin.learningPin(PinType.PUBLIC_KEY_TYPE));
|
||||||
|
|
||||||
// Mock a certificate
|
// Mock a certificate
|
||||||
PublicKey publicKey = mock(PublicKey.class);
|
PublicKey publicKey = mock(PublicKey.class);
|
||||||
@ -102,8 +103,7 @@ public class PinningSSLContextProviderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
PinMessageDigest getMessageDigestForSigAlg(String sigAlg) throws CertificateException {
|
||||||
PinMessageDigest getMessageDigestForSigAlg(@NonNull String sigAlg) throws CertificateException {
|
|
||||||
return pinMessageDigest;
|
return pinMessageDigest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ public class PinningSSLContextProviderTest {
|
|||||||
byte[] digestOfTestCert = pinMessageDigest.digest(testCert);
|
byte[] digestOfTestCert = pinMessageDigest.digest(testCert);
|
||||||
|
|
||||||
// Add a certificate pin in learning mode to a trust manager
|
// Add a certificate pin in learning mode to a trust manager
|
||||||
Pin pin = Pin.LearningPin(PinType.CERTIFICATE_TYPE);
|
Pin pin = Pin.learningPin(PinType.CERTIFICATE_TYPE);
|
||||||
pinTrustManager.addPinning(pin);
|
pinTrustManager.addPinning(pin);
|
||||||
assertThat(pinTrustManager.pins.size(), is(1));
|
assertThat(pinTrustManager.pins.size(), is(1));
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ public class PinningSSLContextProviderTest {
|
|||||||
byte[] digestOfTestCert = pinMessageDigest.digest(testCert);
|
byte[] digestOfTestCert = pinMessageDigest.digest(testCert);
|
||||||
|
|
||||||
// Add a certificate pin in checking mode to a trust manager
|
// Add a certificate pin in checking mode to a trust manager
|
||||||
Pin pin = Pin.CheckingPin(PinType.CERTIFICATE_TYPE, pinMessageDigest, digestOfTestCert);
|
Pin pin = Pin.checkingPin(PinType.CERTIFICATE_TYPE, pinMessageDigest, digestOfTestCert);
|
||||||
pinTrustManager.addPinning(pin);
|
pinTrustManager.addPinning(pin);
|
||||||
assertThat(pinTrustManager.pins.size(), is(1));
|
assertThat(pinTrustManager.pins.size(), is(1));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user