]> git.basschouten.com Git - openhab-addons.git/blob
c227f1fc8dc20978d4898eec8ef07fa050c658d7
[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.upnpcontrol.internal.handler;
14
15 import static org.eclipse.jdt.annotation.Checks.requireNonNull;
16 import static org.mockito.ArgumentMatchers.*;
17 import static org.mockito.Mockito.*;
18
19 import java.io.File;
20 import java.nio.file.Path;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.ScheduledExecutorService;
25 import java.util.concurrent.TimeUnit;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.junit.jupiter.api.extension.ExtendWith;
30 import org.junit.jupiter.api.io.TempDir;
31 import org.mockito.Mock;
32 import org.mockito.junit.jupiter.MockitoExtension;
33 import org.mockito.junit.jupiter.MockitoSettings;
34 import org.mockito.quality.Strictness;
35 import org.openhab.binding.upnpcontrol.internal.UpnpDynamicCommandDescriptionProvider;
36 import org.openhab.binding.upnpcontrol.internal.UpnpDynamicStateDescriptionProvider;
37 import org.openhab.binding.upnpcontrol.internal.config.UpnpControlBindingConfiguration;
38 import org.openhab.binding.upnpcontrol.internal.config.UpnpControlConfiguration;
39 import org.openhab.core.config.core.Configuration;
40 import org.openhab.core.io.transport.upnp.UpnpIOService;
41 import org.openhab.core.thing.Thing;
42 import org.openhab.core.thing.ThingStatus;
43 import org.openhab.core.thing.binding.ThingHandlerCallback;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * Base class for {@link UpnpServerHandlerTest} and {@link UpnpRendererHandlerTest}.
49  *
50  * @author Mark Herwege - Initial contribution
51  */
52 @SuppressWarnings({ "null" })
53 @ExtendWith(MockitoExtension.class)
54 @MockitoSettings(strictness = Strictness.LENIENT)
55 @NonNullByDefault
56 public class UpnpHandlerTest {
57
58     private final Logger logger = LoggerFactory.getLogger(UpnpHandlerTest.class);
59
60     private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
61
62     protected @Nullable UpnpHandler handler;
63
64     @Mock
65     protected @Nullable Thing thing;
66
67     @Mock
68     protected @Nullable UpnpIOService upnpIOService;
69
70     @Mock
71     protected @Nullable UpnpDynamicStateDescriptionProvider upnpStateDescriptionProvider;
72
73     @Mock
74     protected @Nullable UpnpDynamicCommandDescriptionProvider upnpCommandDescriptionProvider;
75
76     protected UpnpControlBindingConfiguration configuration = new UpnpControlBindingConfiguration();
77
78     @Mock
79     protected @Nullable Configuration config;
80
81     // Use temporary folder for favorites and playlists testing
82     @TempDir
83     public @Nullable Path tempFolder;
84
85     @Mock
86     @Nullable
87     protected ScheduledExecutorService scheduler;
88
89     @Mock
90     protected @Nullable ThingHandlerCallback callback;
91
92     public void setUp() {
93         // don't test for multi-threading, so avoid using extra threads
94         implementAsDirectExecutor(requireNonNull(scheduler));
95
96         String path = tempFolder.toString();
97         if (!(path.endsWith(File.separator) || path.endsWith("/"))) {
98             path = path + File.separator;
99         }
100         configuration.path = path;
101
102         // stub thing methods
103         when(thing.getConfiguration()).thenReturn(requireNonNull(config));
104         when(thing.getStatus()).thenReturn(ThingStatus.OFFLINE);
105
106         // stub upnpIOService methods for initialize
107         when(upnpIOService.isRegistered(any())).thenReturn(true);
108
109         Map<String, String> result = new HashMap<>();
110         result.put("ConnectionID", "0");
111         result.put("AVTransportID", "0");
112         result.put("RcsID", "0");
113         when(upnpIOService.invokeAction(any(), eq("ConnectionManager"), eq("GetCurrentConnectionInfo"), anyMap()))
114                 .thenReturn(result);
115
116         // stub config for initialize
117         when(config.as(UpnpControlConfiguration.class)).thenReturn(new UpnpControlConfiguration());
118     }
119
120     protected void initHandler(UpnpHandler handler) {
121         handler.setCallback(callback);
122         handler.upnpScheduler = requireNonNull(scheduler);
123
124         // No timeouts for responses, as we don't actually communicate with a UPnP device
125         handler.config.responseTimeout = 0;
126
127         doReturn("12345").when(handler).getUDN();
128     }
129
130     /**
131      * Mock the {@link ScheduledExecutorService}, so all testing is done in the current thread. We do not test
132      * request/response with a real media server, so do not need the executor to avoid long running processes.
133      * As an exception, we will schedule one off futures with 500ms delay, as this is related to internal
134      * synchronization
135      * logic.
136      *
137      * @param executor
138      */
139     private void implementAsDirectExecutor(ScheduledExecutorService executor) {
140         doAnswer(invocation -> {
141             ((Runnable) invocation.getArguments()[0]).run();
142             return null;
143         }).when(executor).submit(any(Runnable.class));
144         doAnswer(invocation -> {
145             ((Runnable) invocation.getArguments()[0]).run();
146             return null;
147         }).when(executor).scheduleWithFixedDelay(any(Runnable.class), eq(0L), anyLong(), any(TimeUnit.class));
148         doAnswer(invocation -> {
149             return SCHEDULER.schedule((Runnable) invocation.getArguments()[0], 500, TimeUnit.MILLISECONDS);
150         }).when(executor).schedule(any(Runnable.class), anyLong(), any(TimeUnit.class));
151     }
152
153     public void tearDown() {
154         logger.info("-----------------------------------------------------------------------------------");
155     }
156 }