blob: 4cedfb6817490c60b9d9081d8d354b5f2dbf39ed [file] [log] [blame]
Pierre De Rop3a00a212015-03-01 09:27:46 +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.itest.util;
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.junit.Assert;
30import junit.framework.TestCase;
31
32import org.apache.felix.dm.Component;
33import org.apache.felix.dm.ComponentExecutorFactory;
34import org.apache.felix.dm.DependencyManager;
35import org.osgi.framework.Bundle;
36import org.osgi.framework.BundleContext;
37import org.osgi.framework.BundleException;
38import org.osgi.framework.Constants;
39import org.osgi.framework.FrameworkEvent;
40import org.osgi.framework.FrameworkListener;
41import org.osgi.framework.FrameworkUtil;
42import org.osgi.framework.ServiceReference;
43import org.osgi.framework.ServiceRegistration;
44import org.osgi.service.log.LogService;
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.
65 protected ServiceRegistration logService;
66
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.
74 private ServiceRegistration m_componentExecutorFactoryReg;
75
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));
88 logService = context.registerService(LogService.class.getName(), this, props);
89 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() throws InterruptedException {
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 */
133 protected ServiceRegistration register(Ensure e, String name) {
134 Hashtable<String, String> props = new Hashtable<String, String>();
135 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
233 public void log(ServiceReference sr, int level, String message) {
234 checkError(level, null);
235 if (LOG_LEVEL >= level) {
236 StringBuilder sb = new StringBuilder();
237 sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
238 sb.append(message);
239 System.out.println(sb.toString());
240 }
241 }
242
243 public void log(ServiceReference sr, int level, String message, Throwable exception) {
244 checkError(level, exception);
245 if (LOG_LEVEL >= level) {
246 StringBuilder sb = new StringBuilder();
247 sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
248 sb.append(message);
249 parse(sb, exception);
250 System.out.println(sb.toString());
251 }
252 }
253
254 protected boolean errorsLogged() {
255 return m_errorsLogged;
256 }
257
258 private void parse(StringBuilder sb, Throwable t) {
259 if (t != null) {
260 sb.append(" - ");
261 StringWriter buffer = new StringWriter();
262 PrintWriter pw = new PrintWriter(buffer);
263 t.printStackTrace(pw);
264 sb.append(buffer.toString());
265 m_errorsLogged = true;
266 }
267 }
268
269 private String getLevel(int level) {
270 switch (level) {
271 case LogService.LOG_DEBUG :
272 return "DEBUG";
273 case LogService.LOG_ERROR :
274 return "ERROR";
275 case LogService.LOG_INFO :
276 return "INFO";
277 case LogService.LOG_WARNING :
278 return "WARN";
279 default :
280 return "";
281 }
282 }
283
284 private void checkError(int level, Throwable exception) {
285 if (level <= LOG_ERROR) {
286 m_errorsLogged = true;
287 }
288 if (exception != null) {
289 m_errorsLogged = true;
290 }
291 }
292
293 public void frameworkEvent(FrameworkEvent event) {
294 int eventType = event.getType();
295 String msg = getFrameworkEventMessage(eventType);
296 int level = (eventType == FrameworkEvent.ERROR) ? LOG_ERROR : LOG_WARNING;
297 if (msg != null) {
298 log(level, msg, event.getThrowable());
299 } else {
300 log(level, "Unknown fwk event: " + event);
301 }
302 }
303
304 private String getFrameworkEventMessage(int event) {
305 switch (event) {
306 case FrameworkEvent.ERROR :
307 return "FrameworkEvent: ERROR";
308 case FrameworkEvent.INFO :
309 return "FrameworkEvent INFO";
310 case FrameworkEvent.PACKAGES_REFRESHED :
311 return "FrameworkEvent: PACKAGE REFRESHED";
312 case FrameworkEvent.STARTED :
313 return "FrameworkEvent: STARTED";
314 case FrameworkEvent.STARTLEVEL_CHANGED :
315 return "FrameworkEvent: STARTLEVEL CHANGED";
316 case FrameworkEvent.WARNING :
317 return "FrameworkEvent: WARNING";
318 default :
319 return null;
320 }
321 }
322
323 protected void warn(String msg, Object ... params) {
324 if (LOG_LEVEL >= LogService.LOG_WARNING) {
325 log(LogService.LOG_WARNING, params.length > 0 ? String.format(msg, params) : msg);
326 }
327 }
328
329 @SuppressWarnings("unused")
330 protected void info(String msg, Object ... params) {
331 if (LOG_LEVEL >= LogService.LOG_INFO) {
332 log(LogService.LOG_INFO, params.length > 0 ? String.format(msg, params) : msg);
333 }
334 }
335
336 @SuppressWarnings("unused")
337 protected void debug(String msg, Object ... params) {
338 if (LOG_LEVEL >= LogService.LOG_DEBUG) {
339 log(LogService.LOG_DEBUG, params.length > 0 ? String.format(msg, params) : msg);
340 }
341 }
342
343 protected void error(String msg, Object ... params) {
344 log(LogService.LOG_ERROR, params.length > 0 ? String.format(msg, params) : msg);
345 }
346
347 protected void error(String msg, Throwable err, Object ... params) {
348 log(LogService.LOG_ERROR, params.length > 0 ? String.format(msg, params) : msg, err);
349 }
350
351 protected void error(Throwable err) {
352 log(LogService.LOG_ERROR, "error", err);
353 }
354}