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