2 * Copyright (c) 2010-2024 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.homeassistant.internal.discovery;
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.hamcrest.MatcherAssert.assertThat;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.concurrent.CopyOnWriteArrayList;
22 import java.util.concurrent.CountDownLatch;
23 import java.util.concurrent.TimeUnit;
24 import java.util.stream.Stream;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.junit.jupiter.api.BeforeEach;
29 import org.junit.jupiter.api.Test;
30 import org.junit.jupiter.api.extension.ExtendWith;
31 import org.mockito.junit.jupiter.MockitoExtension;
32 import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
33 import org.openhab.binding.mqtt.homeassistant.internal.AbstractHomeAssistantTests;
34 import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
35 import org.openhab.core.config.discovery.DiscoveryListener;
36 import org.openhab.core.config.discovery.DiscoveryResult;
37 import org.openhab.core.config.discovery.DiscoveryService;
38 import org.openhab.core.thing.Thing;
39 import org.openhab.core.thing.ThingTypeUID;
40 import org.openhab.core.thing.ThingUID;
43 * Tests for {@link HomeAssistantDiscovery}
45 * @author Anton Kharuzhy - Initial contribution
47 @SuppressWarnings({ "unchecked" })
48 @ExtendWith(MockitoExtension.class)
50 public class HomeAssistantDiscoveryTests extends AbstractHomeAssistantTests {
51 private @NonNullByDefault({}) HomeAssistantDiscovery discovery;
54 public void beforeEach() {
55 discovery = new TestHomeAssistantDiscovery(channelTypeProvider);
59 public void testComponentNameSummary() {
61 HomeAssistantDiscovery.getComponentNamesSummary(
62 Stream.of("Sensor", "Switch", "Sensor", "Foobar", "Foobar", "Foobar")), //
63 is("3x Foobar, 2x Sensor, Switch"));
67 public void testOneThingDiscovery() throws Exception {
68 var discoveryListener = new LatchDiscoveryListener();
69 var latch = discoveryListener.createWaitForThingsDiscoveredLatch(1);
71 // When discover one thing with two channels
72 discovery.addDiscoveryListener(discoveryListener);
73 discovery.receivedMessage(HA_UID, bridgeConnection,
74 "homeassistant/climate/0x847127fffe11dd6a_climate_zigbee2mqtt/config",
75 getResourceAsByteArray("component/configTS0601ClimateThermostat.json"));
76 discovery.receivedMessage(HA_UID, bridgeConnection,
77 "homeassistant/switch/0x847127fffe11dd6a_auto_lock_zigbee2mqtt/config",
78 getResourceAsByteArray("component/configTS0601AutoLock.json"));
80 // Then one thing found
81 assert latch.await(3, TimeUnit.SECONDS);
82 var discoveryResults = discoveryListener.getDiscoveryResults();
83 assertThat(discoveryResults.size(), is(1));
84 var result = discoveryResults.get(0);
85 assertThat(result.getBridgeUID(), is(HA_UID));
86 assertThat(result.getProperties().get(Thing.PROPERTY_MODEL_ID),
87 is("Radiator valve with thermostat (TS0601_thermostat)"));
88 assertThat(result.getProperties().get(Thing.PROPERTY_VENDOR), is("TuYa"));
89 assertThat(result.getProperties().get(Thing.PROPERTY_FIRMWARE_VERSION), is("Zigbee2MQTT 1.18.2"));
90 assertThat(result.getProperties().get(HandlerConfiguration.PROPERTY_BASETOPIC), is("homeassistant"));
91 assertThat(result.getLabel(), is("th1 (Climate Control, Switch)"));
92 assertThat((List<String>) result.getProperties().get(HandlerConfiguration.PROPERTY_TOPICS), hasItems(
93 "climate/0x847127fffe11dd6a_climate_zigbee2mqtt", "switch/0x847127fffe11dd6a_auto_lock_zigbee2mqtt"));
96 private static class TestHomeAssistantDiscovery extends HomeAssistantDiscovery {
97 public TestHomeAssistantDiscovery(MqttChannelTypeProvider typeProvider) {
98 this.typeProvider = typeProvider;
102 private static class LatchDiscoveryListener implements DiscoveryListener {
103 private final CopyOnWriteArrayList<DiscoveryResult> discoveryResults = new CopyOnWriteArrayList<>();
104 private @Nullable CountDownLatch latch;
107 public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
108 discoveryResults.add(result);
115 public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
119 public @Nullable Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
120 @Nullable Collection<ThingTypeUID> thingTypeUIDs, @Nullable ThingUID bridgeUID) {
121 return Collections.emptyList();
124 public CopyOnWriteArrayList<DiscoveryResult> getDiscoveryResults() {
125 return discoveryResults;
128 public CountDownLatch createWaitForThingsDiscoveredLatch(int count) {
129 final var newLatch = new CountDownLatch(count);