View Javadoc

1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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   * @author Kristian Rosenvold
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 }