]> git.basschouten.com Git - openhab-addons.git/blob
f5d35deb03d6912ecbd7ef8df1000c8c97b2498f
[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.modbus.tests;
14
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.hamcrest.core.Is.is;
18 import static org.hamcrest.core.IsInstanceOf.instanceOf;
19 import static org.junit.jupiter.api.Assertions.*;
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.Mockito.*;
22
23 import java.util.ArrayList;
24 import java.util.Dictionary;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Hashtable;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import org.eclipse.jdt.annotation.NonNull;
33 import org.eclipse.jdt.annotation.NonNullByDefault;
34 import org.eclipse.jdt.annotation.Nullable;
35 import org.junit.jupiter.api.AfterEach;
36 import org.junit.jupiter.api.BeforeEach;
37 import org.junit.jupiter.api.extension.ExtendWith;
38 import org.mockito.Mock;
39 import org.mockito.Mockito;
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.modbus.internal.ModbusHandlerFactory;
44 import org.openhab.core.events.Event;
45 import org.openhab.core.events.EventFilter;
46 import org.openhab.core.events.EventSubscriber;
47 import org.openhab.core.i18n.UnitProvider;
48 import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface;
49 import org.openhab.core.io.transport.modbus.ModbusManager;
50 import org.openhab.core.items.Item;
51 import org.openhab.core.items.ItemProvider;
52 import org.openhab.core.items.ItemRegistry;
53 import org.openhab.core.items.ManagedItemProvider;
54 import org.openhab.core.items.events.ItemStateEvent;
55 import org.openhab.core.library.CoreItemFactory;
56 import org.openhab.core.test.java.JavaOSGiTest;
57 import org.openhab.core.thing.ChannelUID;
58 import org.openhab.core.thing.ManagedThingProvider;
59 import org.openhab.core.thing.Thing;
60 import org.openhab.core.thing.ThingProvider;
61 import org.openhab.core.thing.binding.ThingHandler;
62 import org.openhab.core.thing.binding.ThingHandlerFactory;
63 import org.openhab.core.thing.link.AbstractLink;
64 import org.openhab.core.thing.link.ItemChannelLink;
65 import org.openhab.core.thing.link.ItemChannelLinkProvider;
66 import org.openhab.core.thing.link.ItemChannelLinkRegistry;
67 import org.openhab.core.thing.link.ManagedItemChannelLinkProvider;
68 import org.openhab.core.thing.type.ChannelTypeUID;
69 import org.openhab.core.transform.TransformationService;
70 import org.openhab.core.types.State;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 /**
75  * @author Sami Salonen - Initial contribution
76  */
77 @ExtendWith(MockitoExtension.class)
78 @MockitoSettings(strictness = Strictness.LENIENT)
79 @NonNullByDefault
80 public abstract class AbstractModbusOSGiTest extends JavaOSGiTest {
81
82     /**
83      * When Mockito is used for mocking {@link ThingHandler}s it has to be able to load the {@link ChannelTypeUID}
84      * class. Bnd will add the package to the generated manifest when the class is referenced here.
85      */
86     static void mockitoPackageImport() {
87         ChannelTypeUID.class.getClass();
88     }
89
90     private static class StateSubscriber implements EventSubscriber {
91
92         private final Logger logger = LoggerFactory.getLogger(StateSubscriber.class);
93
94         public Map<String, List<State>> stateUpdates = new HashMap<>();
95
96         @Override
97         public Set<@NonNull String> getSubscribedEventTypes() {
98             return Set.of(ItemStateEvent.TYPE);
99         }
100
101         @Override
102         public @Nullable EventFilter getEventFilter() {
103             return null;
104         }
105
106         @Override
107         public void receive(Event event) {
108             // Expecting only state updates in the tests
109             assertThat(event, is(instanceOf(ItemStateEvent.class)));
110             ItemStateEvent stateEvent = (ItemStateEvent) event;
111             logger.trace("Captured event: {} of type {}. Payload: {}", event,
112                     stateEvent.getItemState().getClass().getSimpleName(), event.getPayload());
113             stateUpdates.computeIfAbsent(stateEvent.getItemName(), item -> new ArrayList<>())
114                     .add(stateEvent.getItemState());
115         }
116     }
117
118     private final Logger logger = LoggerFactory.getLogger(AbstractModbusOSGiTest.class);
119
120     protected @Mock @NonNullByDefault({}) ModbusManager mockedModbusManager;
121     protected @Mock @NonNullByDefault({}) UnitProvider mockedUnitProvider;
122     protected @NonNullByDefault({}) ModbusManager realModbusManager;
123     protected @NonNullByDefault({}) ManagedThingProvider thingProvider;
124     protected @NonNullByDefault({}) ManagedItemProvider itemProvider;
125     protected @NonNullByDefault({}) ManagedItemChannelLinkProvider itemChannelLinkProvider;
126     protected @NonNullByDefault({}) ItemRegistry itemRegistry;
127     protected @NonNullByDefault({}) ItemChannelLinkRegistry itemChannelLinkRegistry;
128     protected @NonNullByDefault({}) CoreItemFactory coreItemFactory;
129
130     private Set<Item> addedItems = new HashSet<>();
131     private Set<Thing> addedThings = new HashSet<>();
132     private Set<ItemChannelLink> addedLinks = new HashSet<>();
133     private StateSubscriber stateSubscriber = new StateSubscriber();
134
135     protected @Mock @NonNullByDefault({}) ModbusCommunicationInterface comms;
136
137     /**
138      * Before each test, configure mocked services
139      */
140     @BeforeEach
141     public void setUpAbstractModbusOSGiTest() {
142         logger.debug("setUpAbstractModbusOSGiTest BEGIN");
143         registerVolatileStorageService();
144         registerService(mockedModbusManager);
145         registerService(stateSubscriber);
146
147         swapModbusManagerToMocked();
148
149         thingProvider = getService(ThingProvider.class, ManagedThingProvider.class);
150         assertThat("Could not get ManagedThingProvider", thingProvider, is(notNullValue()));
151         itemProvider = getService(ItemProvider.class, ManagedItemProvider.class);
152         assertThat("Could not get ManagedItemProvider", itemProvider, is(notNullValue()));
153         itemChannelLinkProvider = getService(ItemChannelLinkProvider.class, ManagedItemChannelLinkProvider.class);
154         assertThat("Could not get ManagedItemChannelLinkProvider", itemChannelLinkProvider, is(notNullValue()));
155         itemRegistry = getService(ItemRegistry.class);
156         assertThat("Could not get ItemRegistry", itemRegistry, is(notNullValue()));
157         itemChannelLinkRegistry = getService(ItemChannelLinkRegistry.class);
158         assertThat("Could not get ItemChannelLinkRegistry", itemChannelLinkRegistry, is(notNullValue()));
159
160         coreItemFactory = new CoreItemFactory(mockedUnitProvider);
161
162         // Clean slate for all tests
163         reset(mockedModbusManager);
164
165         stateSubscriber.stateUpdates.clear();
166         logger.debug("setUpAbstractModbusOSGiTest END");
167     }
168
169     @AfterEach
170     public void tearDownAbstractModbusOSGiTest() throws Exception {
171         logger.debug("tearDownAbstractModbusOSGiTest BEGIN");
172         swapModbusManagerToReal();
173         for (Item item : addedItems) {
174             assertNotNull(itemProvider.remove(item.getName()));
175         }
176         for (Thing thing : addedThings) {
177             disposeThing(thing);
178         }
179         for (ItemChannelLink link : addedLinks) {
180             logger.debug("Unlinking {} <-> {}", link.getItemName(), link.getLinkedUID());
181             assertNotNull(itemChannelLinkProvider.remove(link.getUID()));
182         }
183         logger.debug("tearDownAbstractModbusOSGiTest END");
184     }
185
186     protected void addThing(Thing thing) {
187         assertThat(addedThings.contains(thing), not(equalTo(true)));
188         ThingHandler mockHandler = thing.getHandler();
189         if (mockHandler != null) {
190             // If there is a handler attached to fresh thing, it should be mocked (this pattern is used with some tests)
191             assertThat(Mockito.mockingDetails(thing.getHandler()).isMock(), is(equalTo(true)));
192         }
193
194         thingProvider.add(thing);
195         waitForAssert(() -> assertThat(thing.getHandler(), notNullValue()));
196         assertThat(thing.getConfiguration(), is(notNullValue()));
197         addedThings.add(thing);
198         if (mockHandler != null) {
199             // Re-attach mock handler
200             ThingHandler realHandlerInitedByCore = thing.getHandler();
201             assertNotNull(realHandlerInitedByCore);
202             assertNotSame(realHandlerInitedByCore, mockHandler);
203             realHandlerInitedByCore.dispose();
204             thing.setHandler(mockHandler);
205         }
206     }
207
208     protected void disposeThing(Thing thing) {
209         thingProvider.remove(thing.getUID());
210     }
211
212     protected void addItem(Item item) {
213         assertThat(addedItems.contains(item), not(equalTo(true)));
214         itemProvider.add(item);
215         addedItems.add(item);
216     }
217
218     protected void linkItem(String itemName, ChannelUID channelUID) {
219         logger.debug("Linking {} <-> {}", itemName, channelUID);
220         ItemChannelLink link = new ItemChannelLink(itemName, channelUID);
221         assertThat(addedLinks.contains(link), not(equalTo(true)));
222         itemChannelLinkProvider.add(link);
223         waitForAssert(() -> assertThat(itemChannelLinkRegistry.get(AbstractLink.getIDFor(itemName, channelUID)),
224                 is(notNullValue())));
225         addedLinks.add(link);
226     }
227
228     protected @Nullable List<State> getStateUpdates(String itemName) {
229         return stateSubscriber.stateUpdates.get(itemName);
230     }
231
232     protected void mockTransformation(String name, TransformationService service) {
233         Dictionary<String, Object> params = new Hashtable<>();
234         params.put("openhab.transform", name);
235         registerService(service, params);
236     }
237
238     protected void mockCommsToModbusManager() {
239         assert comms != null;
240         doReturn(comms).when(mockedModbusManager).newModbusCommunicationInterface(any(), any());
241     }
242
243     protected void swapModbusManagerToMocked() {
244         assertNull(realModbusManager);
245         realModbusManager = getService(ModbusManager.class);
246         assertThat("Could not get ModbusManager", realModbusManager, is(notNullValue()));
247         assertThat("Could not get ModbusManagerImpl", realModbusManager.getClass().getSimpleName(),
248                 is(equalTo("ModbusManagerImpl")));
249         assertNotNull(realModbusManager);
250
251         ModbusHandlerFactory modbusHandlerFactory = getService(ThingHandlerFactory.class, ModbusHandlerFactory.class);
252         assertThat("Could not get ModbusHandlerFactory", modbusHandlerFactory, is(notNullValue()));
253         assertNotNull(modbusHandlerFactory);
254         modbusHandlerFactory.unsetModbusManager(realModbusManager);
255         modbusHandlerFactory.setModbusManager(mockedModbusManager);
256     }
257
258     protected void swapModbusManagerToReal() {
259         assertNotNull(realModbusManager);
260         ModbusHandlerFactory modbusHandlerFactory = getService(ThingHandlerFactory.class, ModbusHandlerFactory.class);
261         assertThat("Could not get ModbusHandlerFactory", modbusHandlerFactory, is(notNullValue()));
262         assertNotNull(modbusHandlerFactory);
263         modbusHandlerFactory.unsetModbusManager(mockedModbusManager);
264         modbusHandlerFactory.setModbusManager(realModbusManager);
265     }
266 }