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