1 package org.apache.maven.surefire.booter;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.surefire.shared.utils.io.FileUtils;
23 import org.junit.After;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.junit.internal.runners.model.ReflectiveCallable;
27 import org.junit.internal.runners.statements.ExpectException;
28 import org.junit.internal.runners.statements.Fail;
29 import org.junit.internal.runners.statements.RunAfters;
30 import org.junit.internal.runners.statements.RunBefores;
31 import org.junit.runner.notification.RunNotifier;
32 import org.junit.runners.BlockJUnit4ClassRunner;
33 import org.junit.runners.model.FrameworkMethod;
34 import org.junit.runners.model.InitializationError;
35 import org.junit.runners.model.Statement;
36 import org.junit.runners.model.TestClass;
37
38 import java.io.File;
39 import java.io.IOException;
40 import java.lang.annotation.Annotation;
41 import java.net.MalformedURLException;
42 import java.net.URL;
43 import java.net.URLClassLoader;
44 import java.util.Collection;
45 import java.util.HashSet;
46 import java.util.List;
47
48 import static java.io.File.pathSeparator;
49
50
51
52
53
54
55
56 public class NewClassLoaderRunner
57 extends BlockJUnit4ClassRunner
58 {
59 private Class<?> cls;
60
61 public NewClassLoaderRunner( Class<?> clazz )
62 throws InitializationError
63 {
64 super( clazz );
65 }
66
67 @Override
68 protected void runChild( FrameworkMethod method, RunNotifier notifier )
69 {
70 ClassLoader backup = Thread.currentThread().getContextClassLoader();
71 try
72 {
73 TestClassLoader loader = new TestClassLoader();
74 Thread.currentThread().setContextClassLoader( loader );
75 cls = getFromTestClassLoader( getTestClass().getName(), loader );
76 method = new FrameworkMethod( cls.getMethod( method.getName() ) );
77 super.runChild( method, notifier );
78 }
79 catch ( NoSuchMethodException e )
80 {
81 throw new IllegalStateException( e );
82 }
83 finally
84 {
85 Thread.currentThread().setContextClassLoader( backup );
86 }
87 }
88
89 @Override
90 protected Statement methodBlock( FrameworkMethod method )
91 {
92 try
93 {
94 Object test = new ReflectiveCallable()
95 {
96 @Override
97 protected Object runReflectiveCall()
98 throws Throwable
99 {
100 return createTest();
101 }
102 }.run();
103
104 Statement statement = methodInvoker( method, test );
105 statement = possiblyExpectingExceptions( method, test, statement );
106 statement = withBefores( method, test, statement );
107 statement = withAfters( method, test, statement );
108 return statement;
109 }
110 catch ( Throwable e )
111 {
112 return new Fail( e );
113 }
114 }
115
116 @Override
117 @SuppressWarnings( "unchecked" )
118 protected Statement possiblyExpectingExceptions( FrameworkMethod method, Object test, Statement next )
119 {
120 try
121 {
122 Class<? extends Annotation> t =
123 (Class<? extends Annotation>) Thread.currentThread().getContextClassLoader().loadClass(
124 Test.class.getName() );
125 Annotation annotation = method.getAnnotation( t );
126 Class<? extends Throwable> exp =
127 (Class<? extends Throwable>) t.getMethod( "expected" ).invoke( annotation );
128 boolean isException = exp != null && !Test.None.class.getName().equals( exp.getName() );
129 return isException ? new ExpectException( next, exp ) : next;
130 }
131 catch ( Exception e )
132 {
133 throw new IllegalStateException( e );
134 }
135 }
136
137 @Override
138 @SuppressWarnings( "unchecked" )
139 protected Statement withBefores( FrameworkMethod method, Object target, Statement statement )
140 {
141 try
142 {
143 Class<? extends Annotation> before =
144 (Class<? extends Annotation>) Thread.currentThread().getContextClassLoader().loadClass(
145 Before.class.getName() );
146 List<FrameworkMethod> befores = new TestClass( target.getClass() ).getAnnotatedMethods( before );
147 return befores.isEmpty() ? statement : new RunBefores( statement, befores, target );
148 }
149 catch ( ClassNotFoundException e )
150 {
151 throw new IllegalStateException( e );
152 }
153 }
154
155 @Override
156 @SuppressWarnings( "unchecked" )
157 protected Statement withAfters( FrameworkMethod method, Object target, Statement statement )
158 {
159 try
160 {
161 Class<? extends Annotation> after =
162 (Class<? extends Annotation>) Thread.currentThread().getContextClassLoader().loadClass(
163 After.class.getName() );
164 List<FrameworkMethod> afters = new TestClass( target.getClass() ).getAnnotatedMethods( after );
165 return afters.isEmpty() ? statement : new RunAfters( statement, afters, target );
166 }
167 catch ( ClassNotFoundException e )
168 {
169 throw new IllegalStateException( e );
170 }
171 }
172
173 @Override
174 protected Object createTest()
175 throws Exception
176 {
177 return cls == null ? super.createTest() : cls.getConstructor().newInstance();
178 }
179
180 private static Class<?> getFromTestClassLoader( String clazz, TestClassLoader loader )
181 {
182 try
183 {
184 return Class.forName( clazz, true, loader );
185 }
186 catch ( ClassNotFoundException e )
187 {
188 throw new IllegalStateException( e );
189 }
190 }
191
192 private static class TestClassLoader
193 extends URLClassLoader
194 {
195 TestClassLoader()
196 {
197 super( toClassPath(), null );
198 }
199
200
201
202
203
204
205 private static URL[] toClassPath()
206 {
207 try
208 {
209 Collection<URL> cp = toPathList();
210 if ( cp.isEmpty() )
211 {
212
213 cp = toPathList( System.getProperty( "java.class.path" ) );
214 }
215 return cp.toArray( new URL[cp.size()] );
216 }
217 catch ( IOException e )
218 {
219 return new URL[0];
220 }
221 }
222
223 private static Collection<URL> toPathList( String path ) throws MalformedURLException
224 {
225 Collection<URL> classPath = new HashSet<>();
226 for ( String file : path.split( pathSeparator ) )
227 {
228 classPath.add( new File( file ).toURL() );
229 }
230 return classPath;
231 }
232
233 private static Collection<URL> toPathList()
234 {
235 Collection<URL> classPath = new HashSet<>();
236 try
237 {
238 String[] files = FileUtils.fileRead( new File( "target/test-classpath/cp.txt" ), "UTF-8" )
239 .split( pathSeparator );
240 for ( String file : files )
241 {
242 File f = new File( file );
243 File dir = f.getParentFile();
244 classPath.add( ( dir.getName().equals( "target" ) ? new File( dir, "classes" ) : f ).toURL() );
245 }
246 classPath.add( new File( "target/classes" ).toURL() );
247 classPath.add( new File( "target/test-classes" ).toURL() );
248 }
249 catch ( IOException e )
250 {
251
252 classPath.clear();
253 }
254 return classPath;
255 }
256 }
257 }