1 package org.apache.maven.surefire.junitcore;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.ExecutorService;
27 import java.util.concurrent.Executors;
28 import org.apache.maven.surefire.util.NestedRuntimeException;
29
30 import org.junit.runner.Computer;
31 import org.junit.runner.Runner;
32 import org.junit.runners.ParentRunner;
33 import org.junit.runners.Suite;
34 import org.junit.runners.model.InitializationError;
35 import org.junit.runners.model.RunnerBuilder;
36 import org.junit.runners.model.RunnerScheduler;
37
38
39
40
41 public class ConfigurableParallelComputer
42 extends Computer
43 {
44 private final boolean fClasses;
45
46 private final boolean fMethods;
47
48 private final boolean fixedPool;
49
50 private final ExecutorService fService;
51
52 private final List<AsynchronousRunner> nonBlockers =
53 Collections.synchronizedList( new ArrayList<AsynchronousRunner>() );
54
55
56 public ConfigurableParallelComputer()
57 {
58 this( true, true, Executors.newCachedThreadPool(), false );
59 }
60
61 public ConfigurableParallelComputer( boolean fClasses, boolean fMethods )
62 {
63 this( fClasses, fMethods, Executors.newCachedThreadPool(), false );
64 }
65
66 public ConfigurableParallelComputer( boolean fClasses, boolean fMethods, Integer numberOfThreads, boolean perCore )
67 {
68 this( fClasses, fMethods, Executors.newFixedThreadPool(
69 numberOfThreads * ( perCore ? Runtime.getRuntime().availableProcessors() : 1 ) ), true );
70 }
71
72 private ConfigurableParallelComputer( boolean fClasses, boolean fMethods, ExecutorService executorService,
73 boolean fixedPool )
74 {
75 this.fClasses = fClasses;
76 this.fMethods = fMethods;
77 fService = executorService;
78 this.fixedPool = fixedPool;
79 }
80
81 @SuppressWarnings( { "UnusedDeclaration" } )
82 public void close()
83 throws ExecutionException
84 {
85 for ( AsynchronousRunner nonBlocker : nonBlockers )
86 {
87 nonBlocker.waitForCompletion();
88 }
89
90 fService.shutdown();
91 try
92 {
93 fService.awaitTermination( 10, java.util.concurrent.TimeUnit.SECONDS );
94 }
95 catch ( InterruptedException e )
96 {
97 throw new NestedRuntimeException( e );
98 }
99 }
100
101 private Runner parallelize( Runner runner, RunnerScheduler runnerInterceptor )
102 {
103 if ( runner instanceof ParentRunner<?> )
104 {
105 ( (ParentRunner<?>) runner ).setScheduler( runnerInterceptor );
106 }
107 return runner;
108 }
109
110 private RunnerScheduler getMethodInterceptor()
111 {
112 if ( fClasses && fMethods )
113 {
114 final AsynchronousRunner blockingAsynchronousRunner = new AsynchronousRunner( fService );
115 nonBlockers.add( blockingAsynchronousRunner );
116 return blockingAsynchronousRunner;
117 }
118 return fMethods ? new AsynchronousRunner( fService ) : new SynchronousRunner();
119 }
120
121 private RunnerScheduler getClassInterceptor()
122 {
123 if ( fClasses )
124 {
125 return fMethods ? new SynchronousRunner() : new AsynchronousRunner( fService );
126 }
127 return new SynchronousRunner();
128 }
129
130 @Override
131 public Runner getSuite( RunnerBuilder builder, java.lang.Class<?>[] classes )
132 throws InitializationError
133 {
134 Runner suite = super.getSuite( builder, classes );
135 return fClasses ? parallelize( suite, getClassInterceptor() ) : suite;
136 }
137
138 @Override
139 protected Runner getRunner( RunnerBuilder builder, Class<?> testClass )
140 throws Throwable
141 {
142 Runner runner = super.getRunner( builder, testClass );
143 return fMethods && !isTestSuite( testClass ) ? parallelize( runner, getMethodInterceptor() ) : runner;
144 }
145
146 private boolean isTestSuite( Class<?> testClass )
147 {
148
149 final Suite.SuiteClasses annotation = testClass.getAnnotation( Suite.SuiteClasses.class );
150 return ( annotation != null );
151 }
152
153 @Override
154 public String toString()
155 {
156 return "ConfigurableParallelComputer{" + "classes=" + fClasses + ", methods=" + fMethods + ", fixedPool="
157 + fixedPool + '}';
158 }
159
160 }