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