]> git.basschouten.com Git - openhab-addons.git/blob
4b85990353c446c099e30d5bd217b50469662295
[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.io.hueemulation.internal.rest;
14
15 import static org.mockito.ArgumentMatchers.*;
16 import static org.mockito.Mockito.when;
17
18 import java.io.IOException;
19 import java.net.InetSocketAddress;
20 import java.net.ServerSocket;
21 import java.net.URI;
22 import java.util.Dictionary;
23 import java.util.Hashtable;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.ScheduledExecutorService;
28 import java.util.concurrent.TimeoutException;
29 import java.util.logging.Level;
30 import java.util.logging.Logger;
31
32 import org.eclipse.jetty.client.HttpClient;
33 import org.eclipse.jetty.client.api.ContentResponse;
34 import org.eclipse.jetty.client.util.StringContentProvider;
35 import org.eclipse.jetty.http.HttpHeader;
36 import org.eclipse.jetty.http.HttpMethod;
37 import org.glassfish.grizzly.http.server.HttpServer;
38 import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
39 import org.glassfish.jersey.logging.LoggingFeature;
40 import org.glassfish.jersey.logging.LoggingFeature.Verbosity;
41 import org.glassfish.jersey.server.ResourceConfig;
42 import org.mockito.Mock;
43 import org.mockito.Mockito;
44 import org.mockito.MockitoAnnotations;
45 import org.openhab.core.events.EventPublisher;
46 import org.openhab.core.items.MetadataRegistry;
47 import org.openhab.core.net.NetworkAddressService;
48 import org.openhab.core.storage.Storage;
49 import org.openhab.core.storage.StorageService;
50 import org.openhab.io.hueemulation.internal.ConfigStore;
51 import org.openhab.io.hueemulation.internal.rest.mocks.ConfigStoreWithoutMetadata;
52 import org.openhab.io.hueemulation.internal.rest.mocks.DummyMetadataRegistry;
53 import org.openhab.io.hueemulation.internal.rest.mocks.DummyUsersStorage;
54 import org.osgi.service.cm.ConfigurationAdmin;
55
56 /**
57  * We have no OSGi framework in the background. This class resolves
58  * dependencies between the different classes and mocks common services like the configAdmin.
59  * <p>
60  * The {@link UserManagement} rest components is always
61  * setup and started in this common test setup, because all other rest components require
62  * user authentication.
63  *
64  * @author David Graeff - Initial contribution
65  */
66 public class CommonSetup {
67
68     public String basePath;
69     public HttpClient client;
70     public ConfigStore cs;
71     public HttpServer server;
72
73     UserManagement userManagement;
74
75     AutoCloseable mocksCloseable;
76
77     @Mock
78     EventPublisher eventPublisher;
79
80     @Mock
81     ConfigurationAdmin configAdmin;
82
83     @Mock
84     ScheduledExecutorService scheduler;
85
86     @Mock
87     org.osgi.service.cm.Configuration configAdminConfig;
88
89     @Mock
90     NetworkAddressService networkAddressService;
91
92     MetadataRegistry metadataRegistry = new DummyMetadataRegistry();
93
94     StorageService storageService = new StorageService() {
95         @Override
96         public <T> Storage<T> getStorage(String name, ClassLoader classLoader) {
97             return getStorage(name);
98         }
99
100         @SuppressWarnings("unchecked")
101         @Override
102         public <T> Storage<T> getStorage(String name) {
103             if ("hueEmulationUsers".equals(name)) {
104                 return (Storage<T>) new DummyUsersStorage();
105             }
106             throw new IllegalStateException();
107         }
108     };
109
110     public CommonSetup(boolean withMetadata) throws IOException {
111         mocksCloseable = MockitoAnnotations.openMocks(this);
112
113         when(configAdmin.getConfiguration(anyString())).thenReturn(configAdminConfig);
114         when(configAdmin.getConfiguration(anyString(), any())).thenReturn(configAdminConfig);
115         Dictionary<String, Object> mockProperties = new Hashtable<>();
116         when(configAdminConfig.getProperties()).thenReturn(mockProperties);
117         when(networkAddressService.getPrimaryIpv4HostAddress()).thenReturn("127.0.0.1");
118
119         // If anything is scheduled, immediately run it instead
120         when(scheduler.schedule(any(Runnable.class), anyLong(), any())).thenAnswer(answer -> {
121             ((Runnable) answer.getArgument(0)).run();
122             return null;
123         });
124
125         if (withMetadata) {
126             cs = new ConfigStore(networkAddressService, configAdmin, metadataRegistry, scheduler);
127         } else {
128             cs = new ConfigStoreWithoutMetadata(networkAddressService, configAdmin, scheduler);
129         }
130         cs.activate(Map.of("uuid", "a668dc9b-7172-49c3-832f-acb07dda2a20"));
131         cs.switchFilter = Set.of("Switchable");
132         cs.whiteFilter = Set.of("Switchable");
133         cs.colorFilter = Set.of("ColorLighting");
134
135         userManagement = Mockito.spy(new UserManagement(storageService, cs));
136
137         try (ServerSocket serverSocket = new ServerSocket()) {
138             serverSocket.bind(new InetSocketAddress(0));
139             basePath = "http://localhost:" + serverSocket.getLocalPort() + "/api";
140         }
141     }
142
143     /**
144      * Start the http server to serve all registered jax-rs resources. Also setup a client for testing, see
145      * {@link #client}.
146      *
147      * @param rc A resource config. Add objects and object instance resources to your needs. Example:
148      *            "new ResourceConfig().registerInstances(configurationAccess)"
149      */
150     public void start(ResourceConfig resourceConfig) {
151         ResourceConfig rc = resourceConfig.registerInstances(userManagement).register(new LoggingFeature(
152                 Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.OFF, Verbosity.HEADERS_ONLY, 10));
153
154         Logger log2 = Logger.getLogger("org.glassfish");
155         log2.setLevel(Level.OFF);
156
157         server = GrizzlyHttpServerFactory.createHttpServer(URI.create(basePath), rc);
158         client = new HttpClient();
159         try {
160             client.start();
161         } catch (Exception e) {
162             throw new IllegalStateException("Failed to start HttpClient", e);
163         }
164     }
165
166     public void dispose() throws Exception {
167         if (client != null) {
168             client.stop();
169         }
170         if (server != null) {
171             server.shutdownNow();
172         }
173
174         mocksCloseable.close();
175     }
176
177     public ContentResponse sendDelete(String path) throws InterruptedException, TimeoutException, ExecutionException {
178         return client.newRequest(basePath + path).method(HttpMethod.DELETE).send();
179     }
180
181     public ContentResponse sendGet() throws InterruptedException, TimeoutException, ExecutionException {
182         return client.newRequest(basePath).method(HttpMethod.GET).send();
183     }
184
185     public ContentResponse sendGet(String path) throws InterruptedException, TimeoutException, ExecutionException {
186         return client.newRequest(basePath + path).method(HttpMethod.GET).send();
187     }
188
189     public ContentResponse sendPost(String content) throws InterruptedException, TimeoutException, ExecutionException {
190         return client.newRequest(basePath).method(HttpMethod.POST).header(HttpHeader.CONTENT_TYPE, "application/json")
191                 .content(new StringContentProvider(content)).send();
192     }
193
194     public ContentResponse sendPost(String path, String content)
195             throws InterruptedException, TimeoutException, ExecutionException {
196         return client.newRequest(basePath + path).method(HttpMethod.POST)
197                 .header(HttpHeader.CONTENT_TYPE, "application/json").content(new StringContentProvider(content)).send();
198     }
199
200     public ContentResponse sendPut(String path, String content)
201             throws InterruptedException, TimeoutException, ExecutionException {
202         return client.newRequest(basePath + path).method(HttpMethod.PUT)
203                 .header(HttpHeader.CONTENT_TYPE, "application/json").content(new StringContentProvider(content)).send();
204     }
205 }