View Javadoc
1   package org.apache.maven.surefire.junitcore.pc;
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 net.jcip.annotations.NotThreadSafe;
23  import org.apache.maven.surefire.junitcore.Logger;
24  import org.junit.After;
25  import org.junit.AfterClass;
26  import org.junit.Before;
27  import org.junit.BeforeClass;
28  import org.junit.Rule;
29  import org.junit.Test;
30  import org.junit.runner.Description;
31  import org.junit.runner.JUnitCore;
32  import org.junit.runner.Result;
33  import org.junit.runner.RunWith;
34  import org.junit.runners.Suite;
35  
36  import java.util.ArrayList;
37  import java.util.Arrays;
38  import java.util.Collection;
39  import java.util.Collections;
40  import java.util.Comparator;
41  import java.util.Date;
42  import java.util.Iterator;
43  import java.util.concurrent.ConcurrentLinkedQueue;
44  import java.util.concurrent.TimeUnit;
45  
46  import static org.hamcrest.core.AnyOf.anyOf;
47  import static org.hamcrest.core.Is.is;
48  import static org.hamcrest.core.IsNot.not;
49  import static org.apache.maven.surefire.junitcore.pc.RangeMatcher.between;
50  import static org.junit.Assert.*;
51  
52  /**
53   * @author Tibor Digana (tibor17)
54   * @since 2.16
55   */
56  public class ParallelComputerBuilderTest
57  {
58      private static final Object class1Lock = new Object();
59  
60      private static volatile boolean beforeShutdown;
61  
62      private static volatile Runnable shutdownTask;
63  
64      @Rule
65      public final Stopwatch runtime = new Stopwatch();
66  
67      private static void testKeepBeforeAfter( ParallelComputerBuilder builder, Class<?>... classes )
68      {
69          JUnitCore core = new JUnitCore();
70          for ( int round = 0; round < 5; round++ )
71          {
72              NothingDoingTest1.methods.clear();
73              Result result = core.run( builder.buildComputer(), classes );
74              assertTrue( result.wasSuccessful() );
75              Iterator<String> methods = NothingDoingTest1.methods.iterator();
76              for ( Class<?> clazz : classes )
77              {
78                  String a = clazz.getName() + "#a()";
79                  String b = clazz.getName() + "#b()";
80                  assertThat( methods.next(), is( "init" ) );
81                  assertThat( methods.next(), anyOf( is( a ), is( b ) ) );
82                  assertThat( methods.next(), anyOf( is( a ), is( b ) ) );
83                  assertThat( methods.next(), is( "deinit" ) );
84              }
85          }
86      }
87  
88      @Before
89      public void beforeTest()
90      {
91          Class1.maxConcurrentMethods = 0;
92          Class1.concurrentMethods = 0;
93          shutdownTask = null;
94          NotThreadSafeTest1.t = null;
95          NotThreadSafeTest2.t = null;
96          NotThreadSafeTest3.t = null;
97          NormalTest1.t = null;
98          NormalTest2.t = null;
99      }
100 
101     @Test
102     public void parallelMethodsReuseOneOrTwoThreads()
103     {
104         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
105         parallelComputerBuilder.useOnePool( 4 );
106 
107         // One thread because one suite: TestSuite, however the capacity is 5.
108         parallelComputerBuilder.parallelSuites( 5 );
109 
110         // Two threads because TestSuite has two classes, however the capacity is 5.
111         parallelComputerBuilder.parallelClasses( 5 );
112 
113         // One or two threads because one threads comes from '#useOnePool(4)'
114         // and next thread may be reused from finished class, however the capacity is 3.
115         parallelComputerBuilder.parallelMethods( 3 );
116 
117         assertFalse( parallelComputerBuilder.isOptimized() );
118 
119         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
120         Result result = new JUnitCore().run( computer, TestSuite.class );
121         long timeSpent = runtime.stop();
122 
123         assertThat( computer.suites.size(), is( 1 ) );
124         assertThat( computer.classes.size(), is( 0 ) );
125         assertThat( computer.nestedClasses.size(), is( 2 ) );
126         assertThat( computer.nestedSuites.size(), is( 0 ) );
127         assertFalse( computer.splitPool );
128         assertThat( computer.poolCapacity, is( 4 ) );
129         assertTrue( result.wasSuccessful() );
130         if ( Class1.maxConcurrentMethods == 1 )
131         {
132             assertThat( timeSpent, between( 1950, 2250 ) );
133         }
134         else if ( Class1.maxConcurrentMethods == 2 )
135         {
136             assertThat( timeSpent, between( 1450, 1750 ) );
137         }
138         else
139         {
140             fail();
141         }
142     }
143 
144     @Test
145     public void suiteAndClassInOnePool()
146     {
147         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
148         parallelComputerBuilder.useOnePool( 5 );
149         parallelComputerBuilder.parallelSuites( 5 );
150         parallelComputerBuilder.parallelClasses( 5 );
151         parallelComputerBuilder.parallelMethods( 3 );
152         assertFalse( parallelComputerBuilder.isOptimized() );
153 
154         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
155         Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
156         long timeSpent = runtime.stop();
157 
158         assertThat( computer.suites.size(), is( 1 ) );
159         assertThat( computer.classes.size(), is( 1 ) );
160         assertThat( computer.nestedClasses.size(), is( 2 ) );
161         assertThat( computer.nestedSuites.size(), is( 0 ) );
162         assertFalse( computer.splitPool );
163         assertThat( computer.poolCapacity, is( 5 ) );
164         assertTrue( result.wasSuccessful() );
165         assertThat( Class1.maxConcurrentMethods, is( 2 ) );
166         assertThat( timeSpent, anyOf( between( 1450, 1750 ), between( 1950, 2250 ), between( 2450, 2750 ) ) );
167     }
168 
169     @Test
170     public void onePoolWithUnlimitedParallelMethods()
171     {
172         // see ParallelComputerBuilder Javadoc
173         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
174         parallelComputerBuilder.useOnePool( 8 );
175         parallelComputerBuilder.parallelSuites( 2 );
176         parallelComputerBuilder.parallelClasses( 4 );
177         parallelComputerBuilder.parallelMethods();
178         assertFalse( parallelComputerBuilder.isOptimized() );
179 
180         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
181         Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
182         long timeSpent = runtime.stop();
183 
184         assertThat( computer.suites.size(), is( 1 ) );
185         assertThat( computer.classes.size(), is( 1 ) );
186         assertThat( computer.nestedClasses.size(), is( 2 ) );
187         assertThat( computer.nestedSuites.size(), is( 0 ) );
188         assertFalse( computer.splitPool );
189         assertThat( computer.poolCapacity, is( 8 ) );
190         assertTrue( result.wasSuccessful() );
191         assertThat( Class1.maxConcurrentMethods, is( 4 ) );
192         assertThat( timeSpent, between( 950, 1250 ) );
193     }
194 
195     @Test
196     public void underflowParallelism()
197     {
198         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
199         parallelComputerBuilder.useOnePool( 3 );
200 
201         // One thread because one suite: TestSuite.
202         parallelComputerBuilder.parallelSuites( 5 );
203 
204         // One thread because of the limitation which is bottleneck.
205         parallelComputerBuilder.parallelClasses( 1 );
206 
207         // One thread remains from '#useOnePool(3)'.
208         parallelComputerBuilder.parallelMethods( 3 );
209 
210         assertFalse( parallelComputerBuilder.isOptimized() );
211 
212         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
213         Result result = new JUnitCore().run( computer, TestSuite.class );
214         long timeSpent = runtime.stop();
215 
216         assertThat( computer.suites.size(), is( 1 ) );
217         assertThat( computer.classes.size(), is( 0 ) );
218         assertThat( computer.nestedClasses.size(), is( 2 ) );
219         assertThat( computer.nestedSuites.size(), is( 0 ) );
220         assertFalse( computer.splitPool );
221         assertThat( computer.poolCapacity, is( 3 ) );
222         assertTrue( result.wasSuccessful() );
223         assertThat( Class1.maxConcurrentMethods, is( 1 ) );
224         assertThat( timeSpent, between( 1950, 2250 ) );
225     }
226 
227     @Test
228     public void separatePoolsWithSuite()
229     {
230         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
231         parallelComputerBuilder.parallelSuites( 5 );
232         parallelComputerBuilder.parallelClasses( 5 );
233         parallelComputerBuilder.parallelMethods( 3 );
234         assertFalse( parallelComputerBuilder.isOptimized() );
235 
236         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
237         Result result = new JUnitCore().run( computer, TestSuite.class );
238         long timeSpent = runtime.stop();
239 
240         assertThat( computer.suites.size(), is( 1 ) );
241         assertThat( computer.classes.size(), is( 0 ) );
242         assertThat( computer.nestedClasses.size(), is( 2 ) );
243         assertThat( computer.nestedSuites.size(), is( 0 ) );
244         assertTrue( computer.splitPool );
245         assertThat( computer.poolCapacity, is( ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED ) );
246         assertTrue( result.wasSuccessful() );
247         assertThat( Class1.maxConcurrentMethods, is( 3 ) );
248         assertThat( timeSpent, between( 950, 1250 ) );
249     }
250 
251     @Test
252     public void separatePoolsWithSuiteAndClass()
253     {
254         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
255         parallelComputerBuilder.parallelSuites( 5 );
256         parallelComputerBuilder.parallelClasses( 5 );
257         parallelComputerBuilder.parallelMethods( 3 );
258         assertFalse( parallelComputerBuilder.isOptimized() );
259 
260         // 6 methods altogether.
261         // 2 groups with 3 threads.
262         // Each group takes 0.5s.
263         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
264         Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
265         long timeSpent = runtime.stop();
266 
267         assertThat( computer.suites.size(), is( 1 ) );
268         assertThat( computer.classes.size(), is( 1 ) );
269         assertThat( computer.nestedClasses.size(), is( 2 ) );
270         assertThat( computer.nestedSuites.size(), is( 0 ) );
271         assertTrue( computer.splitPool );
272         assertThat( computer.poolCapacity, is( ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED ) );
273         assertTrue( result.wasSuccessful() );
274         assertThat( Class1.maxConcurrentMethods, is( 3 ) );
275         assertThat( timeSpent, between( 950, 1250 ) );
276     }
277 
278     @Test
279     public void separatePoolsWithSuiteAndSequentialClasses()
280     {
281         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
282         parallelComputerBuilder.parallelSuites( 5 );
283         parallelComputerBuilder.parallelClasses( 1 );
284         parallelComputerBuilder.parallelMethods( 3 );
285         assertFalse( parallelComputerBuilder.isOptimized() );
286 
287         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
288         Result result = new JUnitCore().run( computer, TestSuite.class, Class1.class );
289         long timeSpent = runtime.stop();
290 
291         assertThat( computer.suites.size(), is( 1 ) );
292         assertThat( computer.classes.size(), is( 1 ) );
293         assertThat( computer.nestedClasses.size(), is( 2 ) );
294         assertThat( computer.nestedSuites.size(), is( 0 ) );
295         assertTrue( computer.splitPool );
296         assertThat( computer.poolCapacity, is( ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED ) );
297         assertTrue( result.wasSuccessful() );
298         assertThat( Class1.maxConcurrentMethods, is( 2 ) );
299         assertThat( timeSpent, between( 1450, 1750 ) );
300     }
301 
302     @Test( timeout = 2000 )
303     public void shutdown()
304     {
305         Result result = new ShutdownTest().run( false );
306         long timeSpent = runtime.stop();
307         assertTrue( result.wasSuccessful() );
308         assertTrue( beforeShutdown );
309         assertThat( timeSpent, between( 450, 1250 ) );
310     }
311 
312     @Test( timeout = 2000 )
313     public void shutdownWithInterrupt()
314     {
315         new ShutdownTest().run( true );
316         long timeSpent = runtime.stop();
317         assertTrue( beforeShutdown );
318         assertThat( timeSpent, between( 450, 1250 ) );
319     }
320 
321     @Test
322     public void nothingParallel()
323     {
324         JUnitCore core = new JUnitCore();
325         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() );
326         assertFalse( builder.isOptimized() );
327 
328         Result result = core.run( builder.buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class );
329         assertTrue( result.wasSuccessful() );
330 
331         result = core.run( builder.buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class );
332         assertTrue( result.wasSuccessful() );
333 
334         builder.useOnePool( 1 );
335         assertFalse( builder.isOptimized() );
336         result = core.run( builder.buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class );
337         assertTrue( result.wasSuccessful() );
338 
339         builder.useOnePool( 1 );
340         assertFalse( builder.isOptimized() );
341         result = core.run( builder.buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class );
342         assertTrue( result.wasSuccessful() );
343 
344         builder.useOnePool( 2 );
345         assertFalse( builder.isOptimized() );
346         result = core.run( builder.buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class );
347         assertTrue( result.wasSuccessful() );
348 
349         Class<?>[] classes = { NothingDoingTest1.class, NothingDoingSuite.class };
350 
351         builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses( 1 );
352         assertFalse( builder.isOptimized() );
353         result = core.run( builder.buildComputer(), classes );
354         assertTrue( result.wasSuccessful() );
355 
356         builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses();
357         assertFalse( builder.isOptimized() );
358         result = core.run( builder.buildComputer(), classes );
359         assertTrue( result.wasSuccessful() );
360 
361         classes = new Class<?>[]{ NothingDoingSuite.class, NothingDoingSuite.class, NothingDoingTest1.class,
362             NothingDoingTest2.class, NothingDoingTest3.class };
363 
364         builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses( 1 );
365         assertFalse( builder.isOptimized() );
366         result = core.run( builder.buildComputer(), classes );
367         assertTrue( result.wasSuccessful() );
368 
369         builder.useOnePool( 2 ).parallelSuites( 1 ).parallelClasses();
370         assertFalse( builder.isOptimized() );
371         result = core.run( builder.buildComputer(), classes );
372         assertTrue( result.wasSuccessful() );
373     }
374 
375     @Test
376     public void keepBeforeAfterOneClass()
377     {
378         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() );
379         builder.parallelMethods();
380         assertFalse( builder.isOptimized() );
381         testKeepBeforeAfter( builder, NothingDoingTest1.class );
382     }
383 
384     @Test
385     public void keepBeforeAfterTwoClasses()
386     {
387         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() );
388         builder.useOnePool( 5 ).parallelClasses( 1 ).parallelMethods( 2 );
389         assertFalse( builder.isOptimized() );
390         testKeepBeforeAfter( builder, NothingDoingTest1.class, NothingDoingTest2.class );
391     }
392 
393     @Test
394     public void keepBeforeAfterTwoParallelClasses()
395     {
396         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() );
397         builder.useOnePool( 8 ).parallelClasses( 2 ).parallelMethods( 2 );
398         assertFalse( builder.isOptimized() );
399         JUnitCore core = new JUnitCore();
400         NothingDoingTest1.methods.clear();
401         Class<?>[] classes = { NothingDoingTest1.class, NothingDoingTest2.class, NothingDoingTest3.class };
402         Result result = core.run( builder.buildComputer(), classes );
403         assertTrue( result.wasSuccessful() );
404         ArrayList<String> methods = new ArrayList<String>( NothingDoingTest1.methods );
405         assertThat( methods.size(), is( 12 ) );
406         assertThat( methods.subList( 9, 12 ), is( not( Arrays.asList( "deinit", "deinit", "deinit" ) ) ) );
407     }
408 
409     @Test
410     public void notThreadSafeTest()
411     {
412         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() )
413             .useOnePool( 6 ).optimize( true ).parallelClasses( 3 ).parallelMethods( 3 );
414         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) builder.buildComputer();
415         Result result = new JUnitCore().run( computer, NotThreadSafeTest1.class, NotThreadSafeTest2.class );
416         assertTrue( result.wasSuccessful() );
417         assertThat( result.getRunCount(), is( 2 ) );
418         assertNotNull( NotThreadSafeTest1.t );
419         assertNotNull( NotThreadSafeTest2.t );
420         assertSame( NotThreadSafeTest1.t, NotThreadSafeTest2.t );
421         assertThat( computer.notParallelRunners.size(), is( 2 ) );
422         assertTrue( computer.suites.isEmpty() );
423         assertTrue( computer.classes.isEmpty() );
424         assertTrue( computer.nestedClasses.isEmpty() );
425         assertTrue( computer.nestedSuites.isEmpty() );
426         assertFalse( computer.splitPool );
427         assertThat( computer.poolCapacity, is( 6 ) );
428     }
429 
430     @Test
431     public void mixedThreadSafety()
432     {
433         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() )
434             .useOnePool( 6 ).optimize( true ).parallelClasses( 3 ).parallelMethods( 3 );
435         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) builder.buildComputer();
436         Result result = new JUnitCore().run( computer, NotThreadSafeTest1.class, NormalTest1.class );
437         assertTrue( result.wasSuccessful() );
438         assertThat( result.getRunCount(), is( 2 ) );
439         assertNotNull( NotThreadSafeTest1.t );
440         assertNotNull( NormalTest1.t );
441         assertThat( NormalTest1.t.getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
442         assertNotSame( NotThreadSafeTest1.t, NormalTest1.t );
443         assertThat( computer.notParallelRunners.size(), is( 1 ) );
444         assertTrue( computer.suites.isEmpty() );
445         assertThat( computer.classes.size(), is( 1 ) );
446         assertTrue( computer.nestedClasses.isEmpty() );
447         assertTrue( computer.nestedSuites.isEmpty() );
448         assertFalse( computer.splitPool );
449         assertThat( computer.poolCapacity, is( 6 ) );
450     }
451 
452     @Test
453     public void notThreadSafeTestsInSuite()
454     {
455         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() )
456             .useOnePool( 5 ).parallelMethods( 3 );
457         assertFalse( builder.isOptimized() );
458         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) builder.buildComputer();
459         Result result = new JUnitCore().run( computer, NotThreadSafeTestSuite.class );
460         assertTrue( result.wasSuccessful() );
461         assertNotNull( NormalTest1.t );
462         assertNotNull( NormalTest2.t );
463         assertSame( NormalTest1.t, NormalTest2.t );
464         assertThat( NormalTest1.t.getName(), is( "maven-surefire-plugin@NotThreadSafe" ) );
465         assertThat( NormalTest2.t.getName(), is( "maven-surefire-plugin@NotThreadSafe" ) );
466         assertThat( computer.notParallelRunners.size(), is( 1 ) );
467         assertTrue( computer.suites.isEmpty() );
468         assertTrue( computer.classes.isEmpty() );
469         assertTrue( computer.nestedClasses.isEmpty() );
470         assertTrue( computer.nestedSuites.isEmpty() );
471         assertFalse( computer.splitPool );
472         assertThat( computer.poolCapacity, is( 5 ) );
473     }
474 
475     @Test
476     public void mixedThreadSafetyInSuite()
477     {
478         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() )
479             .useOnePool( 10 ).optimize( true ).parallelSuites( 2 ).parallelClasses( 3 ).parallelMethods( 3 );
480         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) builder.buildComputer();
481         Result result = new JUnitCore().run( computer, MixedSuite.class );
482         assertTrue( result.wasSuccessful() );
483         assertThat( result.getRunCount(), is( 2 ) );
484         assertNotNull( NotThreadSafeTest1.t );
485         assertNotNull( NormalTest1.t );
486         assertThat( NormalTest1.t.getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
487         assertNotSame( NotThreadSafeTest1.t, NormalTest1.t );
488         assertTrue( computer.notParallelRunners.isEmpty() );
489         assertThat( computer.suites.size(), is( 1 ) );
490         assertTrue( computer.classes.isEmpty() );
491         assertThat( computer.nestedClasses.size(), is( 1 ) );
492         assertTrue( computer.nestedSuites.isEmpty() );
493         assertFalse( computer.splitPool );
494         assertThat( computer.poolCapacity, is( 10 ) );
495     }
496 
497     @Test
498     public void inheritanceWithNotThreadSafe()
499     {
500         ParallelComputerBuilder builder = new ParallelComputerBuilder( new Logger() )
501             .useOnePool( 10 ).optimize( true ).parallelSuites( 2 ).parallelClasses( 3 ).parallelMethods( 3 );
502         ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) builder.buildComputer();
503         Result result = new JUnitCore().run( computer, OverMixedSuite.class );
504         assertTrue( result.wasSuccessful() );
505         assertThat( result.getRunCount(), is( 2 ) );
506         assertNotNull( NotThreadSafeTest3.t );
507         assertNotNull( NormalTest1.t );
508         assertThat( NormalTest1.t.getName(), is( "maven-surefire-plugin@NotThreadSafe" ) );
509         assertSame( NotThreadSafeTest3.t, NormalTest1.t );
510         assertThat( computer.notParallelRunners.size(), is( 1 ) );
511         assertTrue( computer.suites.isEmpty() );
512         assertTrue( computer.classes.isEmpty() );
513         assertTrue( computer.nestedClasses.isEmpty() );
514         assertTrue( computer.nestedSuites.isEmpty() );
515         assertFalse( computer.splitPool );
516         assertThat( computer.poolCapacity, is( 10 ) );
517     }
518 
519     @Test
520     public void beforeAfterThreadChanges()
521         throws InterruptedException
522     {
523         Collection<Thread> expectedThreads = jvmThreads();
524         ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() );
525         parallelComputerBuilder.parallelMethods( 3 );
526         ParallelComputer computer = parallelComputerBuilder.buildComputer();
527         Result result = new JUnitCore().run( computer, TestWithBeforeAfter.class );
528         assertTrue( result.wasSuccessful() );
529         TimeUnit.MILLISECONDS.sleep( 250 );
530         assertThat( jvmThreads(), is( expectedThreads ) );
531     }
532 
533     private static Collection<Thread> jvmThreads()
534     {
535         Thread[] t = new Thread[1000];
536         Thread.enumerate( t );
537         ArrayList<Thread> appThreads = new ArrayList<Thread>( t.length );
538         Collections.addAll( appThreads, t );
539         appThreads.removeAll( Collections.singleton( null ) );
540         Collections.sort( appThreads, new Comparator<Thread>()
541         {
542             public int compare( Thread t1, Thread t2 )
543             {
544                 return (int) Math.signum( t1.getId() - t2.getId() );
545             }
546         } );
547         return appThreads;
548     }
549 
550     private static class ShutdownTest
551     {
552         Result run( final boolean useInterrupt )
553         {
554             ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder( new Logger() )
555                 .useOnePool( 8 )
556                 .parallelSuites( 2 )
557                 .parallelClasses( 3 )
558                 .parallelMethods( 3 );
559 
560             assertFalse( parallelComputerBuilder.isOptimized() );
561 
562             final ParallelComputerBuilder.PC computer =
563                 (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
564             shutdownTask = new Runnable()
565             {
566                 public void run()
567                 {
568                     Collection<Description> startedTests = computer.describeStopped( useInterrupt ).getTriggeredTests();
569                     assertThat( startedTests.size(), is( not( 0 ) ) );
570                 }
571             };
572             return new JUnitCore().run( computer, TestSuite.class, Class2.class, Class3.class );
573         }
574     }
575 
576     public static class Class1
577     {
578         static volatile int concurrentMethods = 0;
579 
580         static volatile int maxConcurrentMethods = 0;
581 
582         @Test
583         public void test1()
584             throws InterruptedException
585         {
586             synchronized ( class1Lock )
587             {
588                 ++concurrentMethods;
589                 class1Lock.wait( 500 );
590                 maxConcurrentMethods = Math.max( maxConcurrentMethods, concurrentMethods-- );
591             }
592         }
593 
594         @Test
595         public void test2()
596             throws InterruptedException
597         {
598             test1();
599             Runnable shutdownTask = ParallelComputerBuilderTest.shutdownTask;
600             if ( shutdownTask != null )
601             {
602                 beforeShutdown = true;
603                 shutdownTask.run();
604             }
605         }
606     }
607 
608     public static class Class2
609         extends Class1
610     {
611     }
612 
613     public static class Class3
614         extends Class1
615     {
616     }
617 
618     public static class NothingDoingTest1
619     {
620         static final Collection<String> methods = new ConcurrentLinkedQueue<String>();
621 
622         @BeforeClass
623         public static void init()
624         {
625             methods.add( "init" );
626         }
627 
628         @AfterClass
629         public static void deinit()
630         {
631             methods.add( "deinit" );
632         }
633 
634         @Test
635         public void a()
636             throws InterruptedException
637         {
638             Thread.sleep( 5 );
639             methods.add( getClass().getName() + "#a()" );
640         }
641 
642         @Test
643         public void b()
644             throws InterruptedException
645         {
646             Thread.sleep( 5 );
647             methods.add( getClass().getName() + "#b()" );
648         }
649     }
650 
651     public static class NothingDoingTest2
652         extends NothingDoingTest1
653     {
654     }
655 
656     public static class NothingDoingTest3
657         extends NothingDoingTest1
658     {
659     }
660 
661     @RunWith( Suite.class )
662     @Suite.SuiteClasses( { NothingDoingTest1.class, NothingDoingTest2.class } )
663     public static class NothingDoingSuite
664     {
665     }
666 
667     @RunWith( Suite.class )
668     @Suite.SuiteClasses( { Class2.class, Class1.class } )
669     public static class TestSuite
670     {
671     }
672 
673     @NotThreadSafe
674     public static class NotThreadSafeTest1
675     {
676         static volatile Thread t;
677 
678         @BeforeClass
679         public static void beforeSuite()
680         {
681             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
682         }
683 
684         @AfterClass
685         public static void afterSuite()
686         {
687             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
688         }
689 
690         @Test
691         public void test()
692         {
693             t = Thread.currentThread();
694             assertThat( t.getName(), is( "maven-surefire-plugin@NotThreadSafe" ) );
695         }
696     }
697 
698     @NotThreadSafe
699     public static class NotThreadSafeTest2
700     {
701         static volatile Thread t;
702 
703         @BeforeClass
704         public static void beforeSuite()
705         {
706             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
707         }
708 
709         @AfterClass
710         public static void afterSuite()
711         {
712             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
713         }
714 
715         @Test
716         public void test()
717         {
718             t = Thread.currentThread();
719             assertThat( t.getName(), is( "maven-surefire-plugin@NotThreadSafe" ) );
720         }
721     }
722 
723     @NotThreadSafe
724     public static class NotThreadSafeTest3
725     {
726         static volatile Thread t;
727 
728         @Test
729         public void test()
730         {
731             t = Thread.currentThread();
732             assertThat( t.getName(), is( "maven-surefire-plugin@NotThreadSafe" ) );
733         }
734     }
735 
736     @RunWith( Suite.class )
737     @Suite.SuiteClasses( { NormalTest1.class, NormalTest2.class } )
738     @NotThreadSafe
739     public static class NotThreadSafeTestSuite
740     {
741         @BeforeClass
742         public static void beforeSuite()
743         {
744             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
745         }
746 
747         @AfterClass
748         public static void afterSuite()
749         {
750             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
751         }
752     }
753 
754     public static class NormalTest1
755     {
756         static volatile Thread t;
757 
758         @Test
759         public void test()
760         {
761             t = Thread.currentThread();
762         }
763     }
764 
765     public static class NormalTest2
766     {
767         static volatile Thread t;
768 
769         @Test
770         public void test()
771         {
772             t = Thread.currentThread();
773         }
774     }
775 
776     @RunWith( Suite.class )
777     @Suite.SuiteClasses( { NotThreadSafeTest1.class, NormalTest1.class } )
778     public static class MixedSuite
779     {
780         @BeforeClass
781         public static void beforeSuite()
782         {
783             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
784         }
785 
786         @AfterClass
787         public static void afterSuite()
788         {
789             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
790         }
791     }
792 
793     @RunWith( Suite.class )
794     @Suite.SuiteClasses( { NotThreadSafeTest3.class, NormalTest1.class } )
795     @NotThreadSafe
796     public static class OverMixedSuite
797     {
798         @BeforeClass
799         public static void beforeSuite()
800         {
801             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
802         }
803 
804         @AfterClass
805         public static void afterSuite()
806         {
807             assertThat( Thread.currentThread().getName(), is( not( "maven-surefire-plugin@NotThreadSafe" ) ) );
808         }
809     }
810 
811     public static class TestWithBeforeAfter
812     {
813         @BeforeClass
814         public static void beforeClass()
815             throws InterruptedException
816         {
817             System.out.println( new Date() + " BEG: beforeClass" );
818             TimeUnit.SECONDS.sleep( 1 );
819             System.out.println( new Date() + " END: beforeClass" );
820         }
821 
822         @Before
823         public void before()
824             throws InterruptedException
825         {
826             System.out.println( new Date() + " BEG: before" );
827             TimeUnit.SECONDS.sleep( 1 );
828             System.out.println( new Date() + " END: before" );
829         }
830 
831         @Test
832         public void test()
833             throws InterruptedException
834         {
835             System.out.println( new Date() + " BEG: test" );
836             TimeUnit.SECONDS.sleep( 1 );
837             System.out.println( new Date() + " END: test" );
838         }
839 
840         @After
841         public void after()
842             throws InterruptedException
843         {
844             System.out.println( new Date() + " BEG: after" );
845             TimeUnit.SECONDS.sleep( 1 );
846             System.out.println( new Date() + " END: after" );
847         }
848 
849         @AfterClass
850         public static void afterClass()
851             throws InterruptedException
852         {
853             System.out.println( new Date() + " BEG: afterClass" );
854             TimeUnit.SECONDS.sleep( 1 );
855             System.out.println( new Date() + " END: afterClass" );
856         }
857     }
858 }