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