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