blob: 8501f3a5ce548be3df9399b24a735cb87436c6ee [file] [log] [blame]
Pierre De Ropfaca2892016-01-31 23:27:05 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.dm.lambda.itest;
20
21import java.io.PrintWriter;
22import java.io.StringWriter;
23import java.util.Hashtable;
24import java.util.concurrent.Executor;
25import java.util.concurrent.ExecutorService;
26import java.util.concurrent.Executors;
27import java.util.concurrent.TimeUnit;
28
29import org.apache.felix.dm.Component;
30import org.apache.felix.dm.ComponentExecutorFactory;
31import org.apache.felix.dm.DependencyManager;
32import org.junit.Assert;
33import org.osgi.framework.Bundle;
34import org.osgi.framework.BundleContext;
35import org.osgi.framework.BundleException;
36import org.osgi.framework.Constants;
37import org.osgi.framework.FrameworkEvent;
38import org.osgi.framework.FrameworkListener;
39import org.osgi.framework.FrameworkUtil;
40import org.osgi.framework.ServiceReference;
41import org.osgi.framework.ServiceRegistration;
42import org.osgi.service.log.LogService;
43
44import junit.framework.TestCase;
45
46/**
47 * Base class for all integration tests.
48 *
49 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
50 */
51public abstract class TestBase extends TestCase implements LogService, FrameworkListener {
52 // Default OSGI log service level.
53 protected final static int LOG_LEVEL = LogService.LOG_WARNING;
54
55 // optional thread pool used by parallel dependency managers
56 private volatile ExecutorService m_threadPool;
57
58 // flag used to check if the threadpool must be used for a given test.
59 protected volatile boolean m_parallel;
60
61 // Flag used to check if some errors have been logged during the execution of a given test.
62 private volatile boolean m_errorsLogged;
63
64 // We implement OSGI log service.
Pierre De Rop6e8f9212016-02-20 21:44:59 +000065 protected ServiceRegistration<LogService> logService;
Pierre De Ropfaca2892016-01-31 23:27:05 +000066
67 // Our bundle context
68 protected BundleContext context;
69
70 // Our dependency manager used to create test components.
71 protected volatile DependencyManager m_dm;
72
73 // The Registration for the DM threadpool.
Pierre De Rop6e8f9212016-02-20 21:44:59 +000074 private ServiceRegistration<?> m_componentExecutorFactoryReg;
Pierre De Ropfaca2892016-01-31 23:27:05 +000075
76 public TestBase() {
77 }
78
79 protected void setParallel() {
80 m_parallel = true;
81 }
82
83 public void setUp() throws Exception {
84 warn("Setting up test " + getClass().getName());
85 context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
86 Hashtable<String, Object> props = new Hashtable<>();
87 props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
Pierre De Rop6e8f9212016-02-20 21:44:59 +000088 logService = context.registerService(LogService.class, this, props);
Pierre De Ropfaca2892016-01-31 23:27:05 +000089 context.addFrameworkListener(this);
90 m_dm = new DependencyManager(context);
91 if (m_parallel) {
92 warn("Using threadpool ...");
93 m_threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
94 m_componentExecutorFactoryReg = context.registerService(ComponentExecutorFactory.class.getName(),
95 new ComponentExecutorFactory() {
96 @Override
97 public Executor getExecutorFor(Component component) {
98 return m_threadPool;
99 }
100 },
101 null);
102 }
103 }
104
105 public void tearDown() throws Exception {
106 warn("Tearing down test " + getClass().getName());
107 logService.unregister();
108 context.removeFrameworkListener(this);
109 clearComponents();
110 if (m_parallel && m_componentExecutorFactoryReg != null) {
111 m_componentExecutorFactoryReg.unregister();
112 m_threadPool.shutdown();
113 try {
114 m_threadPool.awaitTermination(60, TimeUnit.SECONDS);
115 } catch (InterruptedException e) {
116 }
117 }
118 Assert.assertFalse(errorsLogged());
119 }
120
121 protected DependencyManager getDM() {
122 return m_dm;
123 }
124
125 protected void clearComponents() {
126 m_dm.clear();
127 warn("All component cleared.");
128 }
129
130 /**
131 * Creates and provides an Ensure object with a name service property into the OSGi service registry.
132 */
Pierre De Rop6e8f9212016-02-20 21:44:59 +0000133 protected ServiceRegistration<?> register(Ensure e, String name) {
134 Hashtable<String, String> props = new Hashtable<>();
Pierre De Ropfaca2892016-01-31 23:27:05 +0000135 props.put("name", name);
136 return context.registerService(Ensure.class.getName(), e, props);
137 }
138
139 /**
140 * Helper method used to stop a given bundle.
141 *
142 * @param symbolicName
143 * the symbolic name of the bundle to be stopped.
144 */
145 protected void stopBundle(String symbolicName) {
146 // Stop the test.annotation bundle
147 boolean found = false;
148 for (Bundle b : context.getBundles()) {
149 if (b.getSymbolicName().equals(symbolicName)) {
150 try {
151 found = true;
152 b.stop();
153 } catch (BundleException e) {
154 e.printStackTrace();
155 }
156 }
157 }
158 if (!found) {
159 throw new IllegalStateException("bundle " + symbolicName + " not found");
160 }
161 }
162
163 /**
164 * Helper method used to start a given bundle.
165 *
166 * @param symbolicName
167 * the symbolic name of the bundle to be started.
168 */
169 protected void startBundle(String symbolicName) {
170 // Stop the test.annotation bundle
171 boolean found = false;
172 for (Bundle b : context.getBundles()) {
173 if (b.getSymbolicName().equals(symbolicName)) {
174 try {
175 found = true;
176 b.start();
177 } catch (BundleException e) {
178 e.printStackTrace();
179 }
180 }
181 }
182 if (!found) {
183 throw new IllegalStateException("bundle " + symbolicName + " not found");
184 }
185 }
186
187 /**
188 * Helper method used to get a given bundle.
189 *
190 * @param symbolicName
191 * the symbolic name of the bundle to get.
192 */
193 protected Bundle getBundle(String symbolicName) {
194 for (Bundle b : context.getBundles()) {
195 if (b.getSymbolicName().equals(symbolicName)) {
196 return b;
197 }
198 }
199 throw new IllegalStateException("bundle " + symbolicName + " not found");
200 }
201
202 /**
203 * Suspend the current thread for a while.
204 *
205 * @param n
206 * the number of milliseconds to wait for.
207 */
208 protected void sleep(int ms) {
209 try {
210 Thread.sleep(ms);
211 } catch (InterruptedException e) {
212 }
213 }
214
215 public void log(int level, String message) {
216 checkError(level, null);
217 if (LOG_LEVEL >= level) {
218 System.out.println(getLevel(level) + " - " + Thread.currentThread().getName() + " : " + message);
219 }
220 }
221
222 public void log(int level, String message, Throwable exception) {
223 checkError(level, exception);
224 if (LOG_LEVEL >= level) {
225 StringBuilder sb = new StringBuilder();
226 sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
227 sb.append(message);
228 parse(sb, exception);
229 System.out.println(sb.toString());
230 }
231 }
232
Pierre De Rop6e8f9212016-02-20 21:44:59 +0000233 @SuppressWarnings("rawtypes")
Pierre De Ropfaca2892016-01-31 23:27:05 +0000234 public void log(ServiceReference sr, int level, String message) {
235 checkError(level, null);
236 if (LOG_LEVEL >= level) {
237 StringBuilder sb = new StringBuilder();
238 sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
239 sb.append(message);
240 System.out.println(sb.toString());
241 }
242 }
243
Pierre De Rop6e8f9212016-02-20 21:44:59 +0000244 @SuppressWarnings("rawtypes")
Pierre De Ropfaca2892016-01-31 23:27:05 +0000245 public void log(ServiceReference sr, int level, String message, Throwable exception) {
246 checkError(level, exception);
247 if (LOG_LEVEL >= level) {
248 StringBuilder sb = new StringBuilder();
249 sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
250 sb.append(message);
251 parse(sb, exception);
252 System.out.println(sb.toString());
253 }
254 }
255
256 protected boolean errorsLogged() {
257 return m_errorsLogged;
258 }
259
260 private void parse(StringBuilder sb, Throwable t) {
261 if (t != null) {
262 sb.append(" - ");
263 StringWriter buffer = new StringWriter();
264 PrintWriter pw = new PrintWriter(buffer);
265 t.printStackTrace(pw);
266 sb.append(buffer.toString());
267 m_errorsLogged = true;
268 }
269 }
270
271 private String getLevel(int level) {
272 switch (level) {
273 case LogService.LOG_DEBUG :
274 return "DEBUG";
275 case LogService.LOG_ERROR :
276 return "ERROR";
277 case LogService.LOG_INFO :
278 return "INFO";
279 case LogService.LOG_WARNING :
280 return "WARN";
281 default :
282 return "";
283 }
284 }
285
286 private void checkError(int level, Throwable exception) {
287 if (level <= LOG_ERROR) {
288 m_errorsLogged = true;
289 }
290 if (exception != null) {
291 m_errorsLogged = true;
292 }
293 }
294
295 public void frameworkEvent(FrameworkEvent event) {
296 int eventType = event.getType();
297 String msg = getFrameworkEventMessage(eventType);
298 int level = (eventType == FrameworkEvent.ERROR) ? LOG_ERROR : LOG_WARNING;
299 if (msg != null) {
300 log(level, msg, event.getThrowable());
301 } else {
302 log(level, "Unknown fwk event: " + event);
303 }
304 }
305
306 private String getFrameworkEventMessage(int event) {
307 switch (event) {
308 case FrameworkEvent.ERROR :
309 return "FrameworkEvent: ERROR";
310 case FrameworkEvent.INFO :
311 return "FrameworkEvent INFO";
312 case FrameworkEvent.PACKAGES_REFRESHED :
313 return "FrameworkEvent: PACKAGE REFRESHED";
314 case FrameworkEvent.STARTED :
315 return "FrameworkEvent: STARTED";
316 case FrameworkEvent.STARTLEVEL_CHANGED :
317 return "FrameworkEvent: STARTLEVEL CHANGED";
318 case FrameworkEvent.WARNING :
319 return "FrameworkEvent: WARNING";
320 default :
321 return null;
322 }
323 }
324
325 protected void warn(String msg, Object ... params) {
326 if (LOG_LEVEL >= LogService.LOG_WARNING) {
327 log(LogService.LOG_WARNING, params.length > 0 ? String.format(msg, params) : msg);
328 }
329 }
330
331 @SuppressWarnings("unused")
332 protected void info(String msg, Object ... params) {
333 if (LOG_LEVEL >= LogService.LOG_INFO) {
334 log(LogService.LOG_INFO, params.length > 0 ? String.format(msg, params) : msg);
335 }
336 }
337
338 @SuppressWarnings("unused")
339 protected void debug(String msg, Object ... params) {
340 if (LOG_LEVEL >= LogService.LOG_DEBUG) {
341 log(LogService.LOG_DEBUG, params.length > 0 ? String.format(msg, params) : msg);
342 }
343 }
344
345 protected void error(String msg, Object ... params) {
346 log(LogService.LOG_ERROR, params.length > 0 ? String.format(msg, params) : msg);
347 }
348
349 protected void error(String msg, Throwable err, Object ... params) {
350 log(LogService.LOG_ERROR, params.length > 0 ? String.format(msg, params) : msg, err);
351 }
352
353 protected void error(Throwable err) {
354 log(LogService.LOG_ERROR, "error", err);
355 }
356}