]> git.basschouten.com Git - openhab-addons.git/blob
80c703339b2813152046969c73efebacb9be9afb
[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.homeassistant.internal;
14
15 import static org.mockito.ArgumentMatchers.*;
16 import static org.mockito.Mockito.*;
17
18 import java.io.IOException;
19 import java.net.URISyntaxException;
20 import java.nio.file.Files;
21 import java.nio.file.Path;
22 import java.nio.file.Paths;
23 import java.util.Objects;
24 import java.util.Set;
25 import java.util.UUID;
26 import java.util.concurrent.CompletableFuture;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ConcurrentMap;
29
30 import org.eclipse.jdt.annotation.NonNullByDefault;
31 import org.junit.jupiter.api.Assertions;
32 import org.junit.jupiter.api.BeforeEach;
33 import org.junit.jupiter.api.extension.ExtendWith;
34 import org.mockito.Mock;
35 import org.mockito.junit.jupiter.MockitoExtension;
36 import org.mockito.junit.jupiter.MockitoSettings;
37 import org.mockito.quality.Strictness;
38 import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
39 import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
40 import org.openhab.binding.mqtt.handler.BrokerHandler;
41 import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
42 import org.openhab.core.io.transport.mqtt.MqttMessageSubscriber;
43 import org.openhab.core.test.java.JavaTest;
44 import org.openhab.core.thing.Bridge;
45 import org.openhab.core.thing.Thing;
46 import org.openhab.core.thing.ThingStatus;
47 import org.openhab.core.thing.ThingStatusDetail;
48 import org.openhab.core.thing.ThingStatusInfo;
49 import org.openhab.core.thing.ThingTypeUID;
50 import org.openhab.core.thing.ThingUID;
51 import org.openhab.core.thing.binding.builder.BridgeBuilder;
52 import org.openhab.core.thing.binding.builder.ThingBuilder;
53 import org.openhab.core.thing.type.ThingTypeBuilder;
54 import org.openhab.core.thing.type.ThingTypeRegistry;
55 import org.openhab.transform.jinja.internal.JinjaTransformationService;
56 import org.openhab.transform.jinja.internal.profiles.JinjaTransformationProfile;
57
58 /**
59  * Abstract class for HomeAssistant unit tests.
60  *
61  * @author Anton Kharuzhy - Initial contribution
62  */
63 @ExtendWith(MockitoExtension.class)
64 @MockitoSettings(strictness = Strictness.LENIENT)
65 @NonNullByDefault
66 public abstract class AbstractHomeAssistantTests extends JavaTest {
67     public static final String BINDING_ID = "mqtt";
68
69     public static final String BRIDGE_TYPE_ID = "broker";
70     public static final String BRIDGE_TYPE_LABEL = "MQTT Broker";
71     public static final ThingTypeUID BRIDGE_TYPE_UID = new ThingTypeUID(BINDING_ID, BRIDGE_TYPE_ID);
72     public static final String BRIDGE_ID = UUID.randomUUID().toString();
73     public static final ThingUID BRIDGE_UID = new ThingUID(BRIDGE_TYPE_UID, BRIDGE_ID);
74
75     public static final String HA_TYPE_ID = "homeassistant";
76     public static final String HA_TYPE_LABEL = "Homeassistant";
77     public static final ThingTypeUID HA_TYPE_UID = new ThingTypeUID(BINDING_ID, HA_TYPE_ID);
78     public static final String HA_ID = UUID.randomUUID().toString();
79     public static final ThingUID HA_UID = new ThingUID(HA_TYPE_UID, HA_ID);
80
81     protected @Mock @NonNullByDefault({}) MqttBrokerConnection bridgeConnection;
82     protected @Mock @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistry;
83     protected @Mock @NonNullByDefault({}) TransformationServiceProvider transformationServiceProvider;
84
85     protected @NonNullByDefault({}) MqttChannelTypeProvider channelTypeProvider;
86
87     protected final Bridge bridgeThing = BridgeBuilder.create(BRIDGE_TYPE_UID, BRIDGE_UID).build();
88     protected final BrokerHandler bridgeHandler = spy(new BrokerHandler(bridgeThing));
89     protected final Thing haThing = ThingBuilder.create(HA_TYPE_UID, HA_UID).withBridge(BRIDGE_UID).build();
90     protected final ConcurrentMap<String, Set<MqttMessageSubscriber>> subscriptions = new ConcurrentHashMap<>();
91
92     private final JinjaTransformationService jinjaTransformationService = new JinjaTransformationService();
93
94     @BeforeEach
95     public void beforeEachAbstractHomeAssistantTests() {
96         when(thingTypeRegistry.getThingType(BRIDGE_TYPE_UID))
97                 .thenReturn(ThingTypeBuilder.instance(BRIDGE_TYPE_UID, BRIDGE_TYPE_LABEL).build());
98         when(thingTypeRegistry.getThingType(HA_TYPE_UID))
99                 .thenReturn(ThingTypeBuilder.instance(HA_TYPE_UID, HA_TYPE_LABEL).build());
100         when(transformationServiceProvider
101                 .getTransformationService(JinjaTransformationProfile.PROFILE_TYPE_UID.getId()))
102                 .thenReturn(jinjaTransformationService);
103
104         channelTypeProvider = spy(new MqttChannelTypeProvider(thingTypeRegistry));
105
106         setupConnection();
107
108         // Return the mocked connection object if the bridge handler is asked for it
109         when(bridgeHandler.getConnectionAsync()).thenReturn(CompletableFuture.completedFuture(bridgeConnection));
110
111         bridgeThing.setStatusInfo(new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.ONLINE.NONE, ""));
112         bridgeThing.setHandler(bridgeHandler);
113
114         haThing.setStatusInfo(new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.ONLINE.NONE, ""));
115     }
116
117     protected void setupConnection() {
118         doAnswer(invocation -> {
119             final var topic = (String) invocation.getArgument(0);
120             final var subscriber = (MqttMessageSubscriber) invocation.getArgument(1);
121
122             subscriptions.putIfAbsent(topic, ConcurrentHashMap.newKeySet());
123             Set<MqttMessageSubscriber> subscribers = subscriptions.get(topic);
124             Objects.requireNonNull(subscribers); // Invariant, thanks to putIfAbsent above. To make compiler happy
125             subscribers.add(subscriber);
126             return CompletableFuture.completedFuture(true);
127         }).when(bridgeConnection).subscribe(any(), any());
128
129         doAnswer(invocation -> {
130             final var topic = (String) invocation.getArgument(0);
131             final var subscriber = (MqttMessageSubscriber) invocation.getArgument(1);
132             final var topicSubscriptions = subscriptions.get(topic);
133
134             if (topicSubscriptions != null) {
135                 topicSubscriptions.remove(subscriber);
136             }
137             return CompletableFuture.completedFuture(true);
138         }).when(bridgeConnection).unsubscribe(any(), any());
139
140         doAnswer(invocation -> {
141             subscriptions.clear();
142             return CompletableFuture.completedFuture(true);
143         }).when(bridgeConnection).unsubscribeAll();
144
145         doReturn(CompletableFuture.completedFuture(true)).when(bridgeConnection).publish(any(), any(), anyInt(),
146                 anyBoolean());
147     }
148
149     /**
150      * @param relativePath path from src/test/java/org/openhab/binding/mqtt/homeassistant/internal
151      * @return path
152      */
153     @SuppressWarnings("null")
154     protected Path getResourcePath(String relativePath) {
155         try {
156             return Paths.get(AbstractHomeAssistantTests.class.getResource(relativePath).toURI());
157         } catch (URISyntaxException e) {
158             Assertions.fail(e);
159         }
160         throw new IllegalArgumentException();
161     }
162
163     protected String getResourceAsString(String relativePath) {
164         try {
165             return Files.readString(getResourcePath(relativePath));
166         } catch (IOException e) {
167             Assertions.fail(e);
168         }
169         throw new IllegalArgumentException();
170     }
171
172     protected byte[] getResourceAsByteArray(String relativePath) {
173         try {
174             return Files.readAllBytes(getResourcePath(relativePath));
175         } catch (IOException e) {
176             Assertions.fail(e);
177         }
178         throw new IllegalArgumentException();
179     }
180
181     protected static String configTopicToMqtt(String configTopic) {
182         return HandlerConfiguration.DEFAULT_BASETOPIC + "/" + configTopic + "/config";
183     }
184 }