]> git.basschouten.com Git - openhab-addons.git/blob
e4f6ef6d5573aa8bfafd72467120017e9d9b550f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.mqtt.generic.mapping;
14
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;
21
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;
33
34 import org.eclipse.jdt.annotation.NonNullByDefault;
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;
45
46 /**
47  * Tests cases for {@link org.openhab.binding.mqtt.generic.mapping.SubscribeFieldToMQTTtopic}.
48  *
49  * @author David Graeff - Initial contribution
50  */
51 @ExtendWith(MockitoExtension.class)
52 @MockitoSettings(strictness = Strictness.LENIENT)
53 @NonNullByDefault
54 public class SubscribeFieldToMQTTtopicTests {
55     @Retention(RetentionPolicy.RUNTIME)
56     @Target({ FIELD })
57     private @interface TestValue {
58         String value() default "";
59     }
60
61     @TopicPrefix
62     public static class Attributes extends AbstractMqttAttributeClass {
63         @SuppressWarnings("unused")
64         public transient String ignoreTransient = "";
65         @SuppressWarnings("unused")
66         public final String ignoreFinal = "";
67
68         public @TestValue("string") @Nullable String aString;
69         public @TestValue("false") @Nullable Boolean aBoolean;
70         public @TestValue("10") @Nullable Long aLong;
71         public @TestValue("10") @Nullable Integer aInteger;
72         public @TestValue("10") @Nullable BigDecimal aDecimal;
73
74         public @TestValue("10") @TopicPrefix("a") int aInt = 24;
75         public @TestValue("false") boolean aBool = true;
76         public @TestValue("abc,def") @MQTTvalueTransform(splitCharacter = ",") String @Nullable [] properties;
77
78         public enum ReadyState {
79             unknown,
80             init,
81             ready,
82         }
83
84         public @TestValue("init") ReadyState state = ReadyState.unknown;
85
86         public enum DataTypeEnum {
87             unknown,
88             integer_,
89             float_,
90         }
91
92         public @TestValue("integer") @MQTTvalueTransform(suffix = "_") DataTypeEnum datatype = DataTypeEnum.unknown;
93
94         @Override
95         public Object getFieldsOf() {
96             return this;
97         }
98     }
99
100     Attributes attributes = new Attributes();
101
102     private @Mock @NonNullByDefault({}) MqttBrokerConnection connectionMock;
103     private @Mock @NonNullByDefault({}) FieldChanged fieldChangedMock;
104
105     @BeforeEach
106     public void setUp() {
107         doReturn(CompletableFuture.completedFuture(true)).when(connectionMock).subscribe(any(), any());
108     }
109
110     @Test
111     public void timeoutIfNoMessageReceive() throws Exception {
112         final Field field = Attributes.class.getField("aInt");
113         ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
114
115         SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChangedMock,
116                 "homie/device123", false);
117         assertThrows(TimeoutException.class,
118                 () -> subscriber.subscribeAndReceive(connectionMock, 1000).get(50, TimeUnit.MILLISECONDS));
119     }
120
121     @Test
122     public void mandatoryMissing() throws Exception {
123         final Field field = Attributes.class.getField("aInt");
124         ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
125
126         SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, fieldChangedMock,
127                 "homie/device123", true);
128         assertThrows(ExecutionException.class, () -> subscriber.subscribeAndReceive(connectionMock, 50).get());
129     }
130
131     @Test
132     public void messageReceive() throws Exception {
133         final FieldChanged changed = (field, value) -> {
134             try {
135                 field.set(attributes.getFieldsOf(), value);
136             } catch (IllegalArgumentException | IllegalAccessException e) {
137                 fail(e.getMessage());
138             }
139         };
140         final Field field = Attributes.class.getField("aInt");
141         ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
142
143         SubscribeFieldToMQTTtopic subscriber = new SubscribeFieldToMQTTtopic(scheduler, field, changed,
144                 "homie/device123", false);
145         CompletableFuture<@Nullable Void> future = subscriber.subscribeAndReceive(connectionMock, 1000);
146
147         // Simulate a received MQTT message
148         subscriber.processMessage("ignored", "10".getBytes());
149         // No timeout should happen
150         future.get(50, TimeUnit.MILLISECONDS);
151         assertThat(attributes.aInt, is(10));
152     }
153 }