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