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