2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mqtt.generic.mapping;
15 import static java.lang.annotation.ElementType.FIELD;
16 import static org.hamcrest.CoreMatchers.is;
17 import static org.hamcrest.MatcherAssert.assertThat;
18 import static org.junit.jupiter.api.Assertions.*;
19 import static org.mockito.ArgumentMatchers.any;
20 import static org.mockito.Mockito.doReturn;
22 import java.lang.annotation.Retention;
23 import java.lang.annotation.RetentionPolicy;
24 import java.lang.annotation.Target;
25 import java.lang.reflect.Field;
26 import java.math.BigDecimal;
27 import java.util.concurrent.CompletableFuture;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.ScheduledExecutorService;
30 import java.util.concurrent.ScheduledThreadPoolExecutor;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.TimeoutException;
34 import org.eclipse.jdt.annotation.NonNull;
35 import org.eclipse.jdt.annotation.Nullable;
36 import org.junit.jupiter.api.BeforeEach;
37 import org.junit.jupiter.api.Test;
38 import org.junit.jupiter.api.extension.ExtendWith;
39 import org.mockito.Mock;
40 import org.mockito.junit.jupiter.MockitoExtension;
41 import org.mockito.junit.jupiter.MockitoSettings;
42 import org.mockito.quality.Strictness;
43 import org.openhab.binding.mqtt.generic.mapping.SubscribeFieldToMQTTtopic.FieldChanged;
44 import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
47 * Tests cases for {@link org.openhab.binding.mqtt.generic.mapping.SubscribeFieldToMQTTtopic}.
49 * @author David Graeff - Initial contribution
51 @ExtendWith(MockitoExtension.class)
52 @MockitoSettings(strictness = Strictness.WARN)
53 public class SubscribeFieldToMQTTtopicTests {
54 @Retention(RetentionPolicy.RUNTIME)
56 private @interface TestValue {
57 String value() default "";
61 public static class Attributes extends AbstractMqttAttributeClass {
62 @SuppressWarnings("unused")
63 public transient String ignoreTransient = "";
64 @SuppressWarnings("unused")
65 public final String ignoreFinal = "";
67 public @TestValue("string") String aString;
68 public @TestValue("false") Boolean aBoolean;
69 public @TestValue("10") Long aLong;
70 public @TestValue("10") Integer aInteger;
71 public @TestValue("10") BigDecimal aDecimal;
73 public @TestValue("10") @TopicPrefix("a") int Int = 24;
74 public @TestValue("false") boolean aBool = true;
75 public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String[] properties;
77 public enum ReadyState {
83 public @TestValue("init") ReadyState state = ReadyState.unknown;
85 public enum DataTypeEnum {
91 public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
94 public @NonNull Object getFieldsOf() {
99 Attributes attributes = new Attributes();
102 MqttBrokerConnection connection;
105 SubscribeFieldToMQTTtopic fieldSubscriber;
108 FieldChanged fieldChanged;
111 public void setUp() {
112 doReturn(CompletableFuture.completedFuture(true)).when(connection).subscribe(any(), any());
116 public void TimeoutIfNoMessageReceive()
117 throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
118 final Field field = Attributes.class.getField("Int");
119 ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
121 SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChanged,
122 "homie/device123", false);
123 assertThrows(TimeoutException.class,
124 () -> subscriber.subscribeAndReceive(connection, 1000).get(50, TimeUnit.MILLISECONDS));
128 public void MandatoryMissing()
129 throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
130 final Field field = Attributes.class.getField("Int");
131 ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
133 SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChanged,
134 "homie/device123", true);
135 assertThrows(ExecutionException.class, () -> subscriber.subscribeAndReceive(connection, 50).get());
139 public void MessageReceive()
140 throws InterruptedException, NoSuchFieldException, ExecutionException, TimeoutException {
141 final FieldChanged changed = (field, value) -> {
143 field.set(attributes.getFieldsOf(), value);
144 } catch (IllegalArgumentException | IllegalAccessException e) {
145 fail(e.getMessage());
148 final Field field = Attributes.class.getField("Int");
149 ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
151 SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, changed,
152 "homie/device123", false);
153 CompletableFuture<@Nullable Void> future = subscriber.subscribeAndReceive(connection, 1000);
155 // Simulate a received MQTT message
156 subscriber.processMessage("ignored", "10".getBytes());
157 // No timeout should happen
158 future.get(50, TimeUnit.MILLISECONDS);
159 assertThat(attributes.Int, is(10));