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