2 * Copyright (c) 2010-2023 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.io.hueemulation.internal.rest;
15 import static org.mockito.ArgumentMatchers.*;
16 import static org.mockito.Mockito.when;
18 import java.io.IOException;
19 import java.net.InetSocketAddress;
20 import java.net.ServerSocket;
22 import java.util.Collections;
23 import java.util.Dictionary;
24 import java.util.Hashtable;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.ScheduledExecutorService;
27 import java.util.concurrent.TimeoutException;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
31 import org.eclipse.jetty.client.HttpClient;
32 import org.eclipse.jetty.client.api.ContentResponse;
33 import org.eclipse.jetty.client.util.StringContentProvider;
34 import org.eclipse.jetty.http.HttpHeader;
35 import org.eclipse.jetty.http.HttpMethod;
36 import org.glassfish.grizzly.http.server.HttpServer;
37 import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
38 import org.glassfish.jersey.logging.LoggingFeature;
39 import org.glassfish.jersey.logging.LoggingFeature.Verbosity;
40 import org.glassfish.jersey.server.ResourceConfig;
41 import org.mockito.Mock;
42 import org.mockito.Mockito;
43 import org.mockito.MockitoAnnotations;
44 import org.openhab.core.events.EventPublisher;
45 import org.openhab.core.items.MetadataRegistry;
46 import org.openhab.core.net.NetworkAddressService;
47 import org.openhab.core.storage.Storage;
48 import org.openhab.core.storage.StorageService;
49 import org.openhab.io.hueemulation.internal.ConfigStore;
50 import org.openhab.io.hueemulation.internal.rest.mocks.ConfigStoreWithoutMetadata;
51 import org.openhab.io.hueemulation.internal.rest.mocks.DummyMetadataRegistry;
52 import org.openhab.io.hueemulation.internal.rest.mocks.DummyUsersStorage;
53 import org.osgi.service.cm.ConfigurationAdmin;
56 * We have no OSGi framework in the background. This class resolves
57 * dependencies between the different classes and mocks common services like the configAdmin.
59 * The {@link UserManagement} rest components is always
60 * setup and started in this common test setup, because all other rest components require
61 * user authentication.
63 * @author David Graeff - Initial contribution
65 public class CommonSetup {
67 public String basePath;
68 public HttpClient client;
69 public ConfigStore cs;
70 public HttpServer server;
72 UserManagement userManagement;
74 AutoCloseable mocksCloseable;
77 EventPublisher eventPublisher;
80 ConfigurationAdmin configAdmin;
83 ScheduledExecutorService scheduler;
86 org.osgi.service.cm.Configuration configAdminConfig;
89 NetworkAddressService networkAddressService;
91 MetadataRegistry metadataRegistry = new DummyMetadataRegistry();
93 StorageService storageService = new StorageService() {
95 public <T> Storage<T> getStorage(String name, ClassLoader classLoader) {
96 return getStorage(name);
99 @SuppressWarnings("unchecked")
101 public <T> Storage<T> getStorage(String name) {
102 if ("hueEmulationUsers".equals(name)) {
103 return (Storage<T>) new DummyUsersStorage();
105 throw new IllegalStateException();
109 public CommonSetup(boolean withMetadata) throws IOException {
110 mocksCloseable = MockitoAnnotations.openMocks(this);
112 when(configAdmin.getConfiguration(anyString())).thenReturn(configAdminConfig);
113 when(configAdmin.getConfiguration(anyString(), any())).thenReturn(configAdminConfig);
114 Dictionary<String, Object> mockProperties = new Hashtable<>();
115 when(configAdminConfig.getProperties()).thenReturn(mockProperties);
116 when(networkAddressService.getPrimaryIpv4HostAddress()).thenReturn("127.0.0.1");
118 // If anything is scheduled, immediately run it instead
119 when(scheduler.schedule(any(Runnable.class), anyLong(), any())).thenAnswer(answer -> {
120 ((Runnable) answer.getArgument(0)).run();
125 cs = new ConfigStore(networkAddressService, configAdmin, metadataRegistry, scheduler);
127 cs = new ConfigStoreWithoutMetadata(networkAddressService, configAdmin, scheduler);
129 cs.activate(Collections.singletonMap("uuid", "a668dc9b-7172-49c3-832f-acb07dda2a20"));
130 cs.switchFilter = Collections.singleton("Switchable");
131 cs.whiteFilter = Collections.singleton("Switchable");
132 cs.colorFilter = Collections.singleton("ColorLighting");
134 userManagement = Mockito.spy(new UserManagement(storageService, cs));
136 try (ServerSocket serverSocket = new ServerSocket()) {
137 serverSocket.bind(new InetSocketAddress(0));
138 basePath = "http://localhost:" + serverSocket.getLocalPort() + "/api";
143 * Start the http server to serve all registered jax-rs resources. Also setup a client for testing, see
146 * @param rc A resource config. Add objects and object instance resources to your needs. Example:
147 * "new ResourceConfig().registerInstances(configurationAccess)"
149 public void start(ResourceConfig resourceConfig) {
150 ResourceConfig rc = resourceConfig.registerInstances(userManagement).register(new LoggingFeature(
151 Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.OFF, Verbosity.HEADERS_ONLY, 10));
153 Logger log2 = Logger.getLogger("org.glassfish");
154 log2.setLevel(Level.OFF);
156 server = GrizzlyHttpServerFactory.createHttpServer(URI.create(basePath), rc);
157 client = new HttpClient();
160 } catch (Exception e) {
161 throw new IllegalStateException("Failed to start HttpClient", e);
165 public void dispose() throws Exception {
166 if (client != null) {
169 if (server != null) {
170 server.shutdownNow();
173 mocksCloseable.close();
176 public ContentResponse sendDelete(String path) throws InterruptedException, TimeoutException, ExecutionException {
177 return client.newRequest(basePath + path).method(HttpMethod.DELETE).send();
180 public ContentResponse sendGet() throws InterruptedException, TimeoutException, ExecutionException {
181 return client.newRequest(basePath).method(HttpMethod.GET).send();
184 public ContentResponse sendGet(String path) throws InterruptedException, TimeoutException, ExecutionException {
185 return client.newRequest(basePath + path).method(HttpMethod.GET).send();
188 public ContentResponse sendPost(String content) throws InterruptedException, TimeoutException, ExecutionException {
189 return client.newRequest(basePath).method(HttpMethod.POST).header(HttpHeader.CONTENT_TYPE, "application/json")
190 .content(new StringContentProvider(content)).send();
193 public ContentResponse sendPost(String path, String content)
194 throws InterruptedException, TimeoutException, ExecutionException {
195 return client.newRequest(basePath + path).method(HttpMethod.POST)
196 .header(HttpHeader.CONTENT_TYPE, "application/json").content(new StringContentProvider(content)).send();
199 public ContentResponse sendPut(String path, String content)
200 throws InterruptedException, TimeoutException, ExecutionException {
201 return client.newRequest(basePath + path).method(HttpMethod.PUT)
202 .header(HttpHeader.CONTENT_TYPE, "application/json").content(new StringContentProvider(content)).send();