001
014
015 package com.liferay.portal.kernel.test;
016
017 import com.liferay.portal.kernel.process.ClassPathUtil;
018 import com.liferay.portal.kernel.process.ProcessCallable;
019 import com.liferay.portal.kernel.process.ProcessException;
020 import com.liferay.portal.kernel.process.ProcessExecutor;
021 import com.liferay.portal.kernel.util.MethodKey;
022 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
023 import com.liferay.portal.kernel.util.StringBundler;
024 import com.liferay.portal.kernel.util.StringPool;
025 import com.liferay.portal.kernel.util.Validator;
026
027 import java.io.Serializable;
028
029 import java.lang.reflect.InvocationTargetException;
030 import java.lang.reflect.Method;
031
032 import java.util.ArrayList;
033 import java.util.List;
034 import java.util.concurrent.ExecutionException;
035 import java.util.concurrent.Future;
036
037 import org.junit.After;
038 import org.junit.Before;
039 import org.junit.runner.manipulation.Sorter;
040 import org.junit.runners.BlockJUnit4ClassRunner;
041 import org.junit.runners.model.FrameworkMethod;
042 import org.junit.runners.model.InitializationError;
043 import org.junit.runners.model.Statement;
044 import org.junit.runners.model.TestClass;
045
046
049 public class NewJVMJUnitTestRunner extends BlockJUnit4ClassRunner {
050
051 public NewJVMJUnitTestRunner(Class<?> clazz) throws InitializationError {
052 super(clazz);
053
054 _classPath = ClassPathUtil.getJVMClassPath(false);
055
056 sort(new Sorter(new DescriptionComparator()));
057 }
058
059 protected static void attachProcess(String message) {
060 if (!Boolean.getBoolean("attached")) {
061 ProcessExecutor.ProcessContext.attach(
062 message, 1000,
063 new ProcessExecutor.ShutdownHook() {
064
065 public boolean shutdown(
066 int shutdownCode, Throwable shutdownThrowable) {
067
068 System.exit(shutdownCode);
069
070 return true;
071 }
072
073 });
074
075 System.setProperty("attached", StringPool.TRUE);
076 }
077 }
078
079 protected List<String> createArguments(FrameworkMethod frameworkMethod) {
080 List<String> arguments = new ArrayList<String>();
081
082 String agentLine = System.getProperty("junit.cobertura.agent");
083
084 if (Validator.isNotNull(agentLine)) {
085 arguments.add(agentLine);
086 arguments.add("-Djunit.cobertura.agent=" + agentLine);
087 }
088
089 boolean coberturaParentDynamicallyInstrumented = Boolean.getBoolean(
090 "cobertura.parent.dynamically.instrumented");
091
092 if (coberturaParentDynamicallyInstrumented) {
093 arguments.add("-Dcobertura.parent.dynamically.instrumented=true");
094 }
095
096 boolean junitCodeCoverage = Boolean.getBoolean("junit.code.coverage");
097
098 if (junitCodeCoverage) {
099 arguments.add("-Djunit.code.coverage=true");
100 }
101
102 boolean junitDebug = Boolean.getBoolean("junit.debug");
103
104 if (junitDebug) {
105 arguments.add(_JPDA_OPTIONS);
106 arguments.add("-Djunit.debug=true");
107 }
108
109 arguments.add("-Djava.net.preferIPv4Stack=true");
110
111 String fileName = System.getProperty(
112 "net.sourceforge.cobertura.datafile");
113
114 if (fileName != null) {
115 arguments.add("-Dnet.sourceforge.cobertura.datafile=" + fileName);
116 }
117
118 return arguments;
119 }
120
121 @Override
122 protected Statement methodBlock(FrameworkMethod frameworkMethod) {
123 Thread currentThread = Thread.currentThread();
124
125 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
126
127 PortalClassLoaderUtil.setClassLoader(contextClassLoader);
128
129 TestClass testClass = getTestClass();
130
131 List<FrameworkMethod> beforeFrameworkMethods =
132 testClass.getAnnotatedMethods(Before.class);
133
134 List<FrameworkMethod> afterFrameworkMethods =
135 testClass.getAnnotatedMethods(After.class);
136
137 List<String> arguments = createArguments(frameworkMethod);
138
139 Class<?> clazz = testClass.getJavaClass();
140
141 return new RunInNewJVMStatment(
142 _classPath, arguments, clazz, beforeFrameworkMethods,
143 frameworkMethod, afterFrameworkMethods);
144 }
145
146 protected ProcessCallable<Serializable> processProcessCallable(
147 ProcessCallable<Serializable> processCallable,
148 MethodKey testMethodKey) {
149
150 return processCallable;
151 }
152
153 private static final String _JPDA_OPTIONS =
154 "-agentlib:jdwp=transport=dt_socket,address=8001,server=y,suspend=y";
155
156 private String _classPath;
157
158 private static class TestProcessCallable
159 implements ProcessCallable<Serializable> {
160
161 public TestProcessCallable(
162 String testClassName, List<MethodKey> beforeMethodKeys,
163 MethodKey testMethodKey, List<MethodKey> afterMethodKeys) {
164
165 _testClassName = testClassName;
166 _beforeMethodKeys = beforeMethodKeys;
167 _testMethodKey = testMethodKey;
168 _afterMethodKeys = afterMethodKeys;
169 }
170
171 public Serializable call() throws ProcessException {
172 attachProcess("Attached " + toString());
173
174 Thread currentThread = Thread.currentThread();
175
176 ClassLoader contextClassLoader =
177 currentThread.getContextClassLoader();
178
179 try {
180 Class<?> clazz = contextClassLoader.loadClass(_testClassName);
181
182 Object object = clazz.newInstance();
183
184 for (MethodKey beforeMethodKey : _beforeMethodKeys) {
185 beforeMethodKey = beforeMethodKey.transform(
186 contextClassLoader);
187
188 _invoke(beforeMethodKey, object);
189 }
190
191 MethodKey testMethodKey = _testMethodKey.transform(
192 contextClassLoader);
193
194 _invoke(testMethodKey, object);
195
196 for (MethodKey afterMethodKey : _afterMethodKeys) {
197 afterMethodKey = afterMethodKey.transform(
198 contextClassLoader);
199
200 _invoke(afterMethodKey, object);
201 }
202 }
203 catch (Exception e) {
204 throw new ProcessException(e);
205 }
206
207 return StringPool.BLANK;
208 }
209
210 @Override
211 public String toString() {
212 StringBundler sb = new StringBundler(4);
213
214 sb.append(_testClassName);
215 sb.append(StringPool.PERIOD);
216 sb.append(_testMethodKey.getMethodName());
217 sb.append("()");
218
219 return sb.toString();
220 }
221
222 private void _invoke(MethodKey methodKey, Object object)
223 throws Exception {
224
225 Method method = methodKey.getMethod();
226
227 method.invoke(object);
228 }
229
230 private static final long serialVersionUID = 1L;
231
232 private List<MethodKey> _afterMethodKeys;
233 private List<MethodKey> _beforeMethodKeys;
234 private String _testClassName;
235 private MethodKey _testMethodKey;
236
237 }
238
239 private class RunInNewJVMStatment extends Statement {
240
241 public RunInNewJVMStatment(
242 String classPath, List<String> arguments, Class<?> testClass,
243 List<FrameworkMethod> beforeFrameworkMethods,
244 FrameworkMethod testFrameworkMethod,
245 List<FrameworkMethod> afterFrameworkMethods) {
246
247 _classPath = classPath;
248 _arguments = arguments;
249 _testClassName = testClass.getName();
250
251 _beforeMethodKeys = new ArrayList<MethodKey>(
252 beforeFrameworkMethods.size());
253
254 for (FrameworkMethod frameworkMethod : beforeFrameworkMethods) {
255 _beforeMethodKeys.add(
256 new MethodKey(frameworkMethod.getMethod()));
257 }
258
259 _testMethodKey = new MethodKey(testFrameworkMethod.getMethod());
260
261 _afterMethodKeys = new ArrayList<MethodKey>(
262 afterFrameworkMethods.size());
263
264 for (FrameworkMethod frameworkMethod : afterFrameworkMethods) {
265 _afterMethodKeys.add(
266 new MethodKey(frameworkMethod.getMethod()));
267 }
268 }
269
270 @Override
271 public void evaluate() throws Throwable {
272 ProcessCallable<Serializable> processCallable =
273 new TestProcessCallable(
274 _testClassName, _beforeMethodKeys, _testMethodKey,
275 _afterMethodKeys);
276
277 processCallable = processProcessCallable(
278 processCallable, _testMethodKey);
279
280 Future<String> future = ProcessExecutor.execute(
281 _classPath, _arguments, processCallable);
282
283 try {
284 future.get();
285 }
286 catch (ExecutionException ee) {
287 Throwable cause = ee.getCause();
288
289 while ((cause instanceof ProcessException) ||
290 (cause instanceof InvocationTargetException)) {
291
292 cause = cause.getCause();
293 }
294
295 throw cause;
296 }
297 }
298
299 private List<MethodKey> _afterMethodKeys;
300 private List<String> _arguments;
301 private List<MethodKey> _beforeMethodKeys;
302 private String _classPath;
303 private String _testClassName;
304 private MethodKey _testMethodKey;
305
306 }
307
308 }