1 package org.apache.maven.surefire.junitcore.pc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.junit.AfterClass;
23 import org.junit.Before;
24 import org.junit.BeforeClass;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.runner.JUnitCore;
28 import org.junit.runner.Result;
29 import org.junit.runner.RunWith;
30 import org.junit.runners.Suite;
31
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.Iterator;
36 import java.util.concurrent.ConcurrentLinkedQueue;
37
38 import static org.junit.Assert.assertFalse;
39 import static org.junit.Assert.assertThat;
40 import static org.junit.Assert.assertTrue;
41 import static org.junit.Assert.fail;
42 import static org.hamcrest.core.AnyOf.anyOf;
43 import static org.hamcrest.core.Is.is;
44 import static org.hamcrest.core.IsNot.not;
45 import static org.apache.maven.surefire.junitcore.pc.RangeMatcher.between;
46
47
48
49
50
51 public class ParallelComputerBuilderTest {
52 @Rule
53 public final Stopwatch runtime = new Stopwatch();
54
55 @Before
56 public void beforeTest() {
57 Class1.maxConcurrentMethods = 0;
58 Class1.concurrentMethods = 0;
59 shutdownTask = null;
60 }
61
62 @Test
63 public void parallelMethodsReuseOneOrTwoThreads() {
64 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
65 parallelComputerBuilder.useOnePool(4);
66
67
68 parallelComputerBuilder.parallelSuites(5);
69
70
71 parallelComputerBuilder.parallelClasses(5);
72
73
74
75 parallelComputerBuilder.parallelMethods(3);
76
77 ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
78 Result result = new JUnitCore().run(computer, TestSuite.class);
79 long timeSpent = runtime.stop();
80
81 assertThat(computer.suites.size(), is(1));
82 assertThat(computer.classes.size(), is(0));
83 assertThat(computer.nestedClasses.size(), is(2));
84 assertThat(computer.nestedSuites.size(), is(0));
85 assertFalse(computer.splitPool);
86 assertThat(computer.poolCapacity, is(4));
87 assertTrue(result.wasSuccessful());
88 if (Class1.maxConcurrentMethods == 1) {
89 assertThat(timeSpent, between(1950, 2250));
90 } else if (Class1.maxConcurrentMethods == 2) {
91 assertThat(timeSpent, between(1450, 1750));
92 } else {
93 fail();
94 }
95 }
96
97 @Test
98 public void suiteAndClassInOnePool() {
99 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
100 parallelComputerBuilder.useOnePool(5);
101 parallelComputerBuilder.parallelSuites(5);
102 parallelComputerBuilder.parallelClasses(5);
103 parallelComputerBuilder.parallelMethods(3);
104
105 ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
106 Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
107 long timeSpent = runtime.stop();
108
109 assertThat(computer.suites.size(), is(1));
110 assertThat(computer.classes.size(), is(1));
111 assertThat(computer.nestedClasses.size(), is(2));
112 assertThat(computer.nestedSuites.size(), is(0));
113 assertFalse(computer.splitPool);
114 assertThat(computer.poolCapacity, is(5));
115 assertTrue(result.wasSuccessful());
116 assertThat(Class1.maxConcurrentMethods, is(2));
117 assertThat(timeSpent, anyOf(between(1450, 1750), between(1950, 2250), between(2450, 2750)));
118 }
119
120 @Test
121 public void onePoolWithUnlimitedParallelMethods() {
122
123 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
124 parallelComputerBuilder.useOnePool(8);
125 parallelComputerBuilder.parallelSuites(2);
126 parallelComputerBuilder.parallelClasses(4);
127 parallelComputerBuilder.parallelMethods();
128
129 ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
130 Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
131 long timeSpent = runtime.stop();
132
133 assertThat(computer.suites.size(), is(1));
134 assertThat(computer.classes.size(), is(1));
135 assertThat(computer.nestedClasses.size(), is(2));
136 assertThat(computer.nestedSuites.size(), is(0));
137 assertFalse(computer.splitPool);
138 assertThat(computer.poolCapacity, is(8));
139 assertTrue(result.wasSuccessful());
140 assertThat(Class1.maxConcurrentMethods, is(4));
141 assertThat(timeSpent, between(950, 1250));
142 }
143
144 @Test
145 public void underflowParallelism()
146 {
147 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
148 parallelComputerBuilder.useOnePool( 3 );
149
150
151 parallelComputerBuilder.parallelSuites( 5 );
152
153
154 parallelComputerBuilder.parallelClasses( 1 );
155
156
157 parallelComputerBuilder.parallelMethods( 3 );
158
159 ParallelComputerBuilder.PC computer = ( ParallelComputerBuilder.PC ) parallelComputerBuilder.buildComputer();
160 Result result = new JUnitCore().run( computer, TestSuite.class );
161 long timeSpent = runtime.stop();
162
163 assertThat( computer.suites.size(), is( 1 ) );
164 assertThat( computer.classes.size(), is( 0 ) );
165 assertThat( computer.nestedClasses.size(), is( 2 ) );
166 assertThat( computer.nestedSuites.size(), is( 0 ) );
167 assertFalse( computer.splitPool );
168 assertThat( computer.poolCapacity, is( 3 ) );
169 assertTrue( result.wasSuccessful() );
170 assertThat( Class1.maxConcurrentMethods, is( 1 ) );
171 assertThat( timeSpent, between( 1950, 2250 ) );
172 }
173
174 @Test
175 public void separatePoolsWithSuite() {
176 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
177 parallelComputerBuilder.parallelSuites(5);
178 parallelComputerBuilder.parallelClasses(5);
179 parallelComputerBuilder.parallelMethods(3);
180
181 ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
182 Result result = new JUnitCore().run(computer, TestSuite.class);
183 long timeSpent = runtime.stop();
184
185 assertThat(computer.suites.size(), is(1));
186 assertThat(computer.classes.size(), is(0));
187 assertThat(computer.nestedClasses.size(), is(2));
188 assertThat(computer.nestedSuites.size(), is(0));
189 assertTrue(computer.splitPool);
190 assertThat(computer.poolCapacity, is(ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED));
191 assertTrue(result.wasSuccessful());
192 assertThat(Class1.maxConcurrentMethods, is(3));
193 assertThat(timeSpent, between(950, 1250));
194 }
195
196 @Test
197 public void separatePoolsWithSuiteAndClass() {
198 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
199 parallelComputerBuilder.parallelSuites(5);
200 parallelComputerBuilder.parallelClasses(5);
201 parallelComputerBuilder.parallelMethods(3);
202
203
204
205
206 ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
207 Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
208 long timeSpent = runtime.stop();
209
210 assertThat(computer.suites.size(), is(1));
211 assertThat(computer.classes.size(), is(1));
212 assertThat(computer.nestedClasses.size(), is(2));
213 assertThat(computer.nestedSuites.size(), is(0));
214 assertTrue(computer.splitPool);
215 assertThat(computer.poolCapacity, is(ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED));
216 assertTrue(result.wasSuccessful());
217 assertThat(Class1.maxConcurrentMethods, is(3));
218 assertThat(timeSpent, between(950, 1250));
219 }
220
221 @Test
222 public void separatePoolsWithSuiteAndSequentialClasses() {
223 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder();
224 parallelComputerBuilder.parallelSuites(5);
225 parallelComputerBuilder.parallelClasses(1);
226 parallelComputerBuilder.parallelMethods(3);
227
228 ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
229 Result result = new JUnitCore().run(computer, TestSuite.class, Class1.class);
230 long timeSpent = runtime.stop();
231
232 assertThat(computer.suites.size(), is(1));
233 assertThat(computer.classes.size(), is(1));
234 assertThat(computer.nestedClasses.size(), is(2));
235 assertThat(computer.nestedSuites.size(), is(0));
236 assertTrue(computer.splitPool);
237 assertThat(computer.poolCapacity, is(ParallelComputerBuilder.TOTAL_POOL_SIZE_UNDEFINED));
238 assertTrue(result.wasSuccessful());
239 assertThat(Class1.maxConcurrentMethods, is(2));
240 assertThat(timeSpent, between(1450, 1750));
241 }
242
243 private static class ShutdownTest {
244 Result run(final boolean useInterrupt) {
245 ParallelComputerBuilder parallelComputerBuilder = new ParallelComputerBuilder().useOnePool(8);
246 parallelComputerBuilder.parallelSuites(2);
247 parallelComputerBuilder.parallelClasses(3);
248 parallelComputerBuilder.parallelMethods(3);
249
250 final ParallelComputerBuilder.PC computer = (ParallelComputerBuilder.PC) parallelComputerBuilder.buildComputer();
251 shutdownTask = new Runnable() {
252 public void run() {
253 Collection<org.junit.runner.Description> startedTests = computer.shutdown(useInterrupt);
254 assertThat(startedTests.size(), is(not(0)));
255 }
256 };
257 return new JUnitCore().run(computer, TestSuite.class, Class2.class, Class3.class);
258 }
259 }
260
261 @Test(timeout = 2000)
262 public void shutdown() {
263 Result result = new ShutdownTest().run(false);
264 long timeSpent = runtime.stop();
265 assertTrue(result.wasSuccessful());
266 assertTrue(beforeShutdown);
267 assertThat(timeSpent, between(450, 1250));
268 }
269
270 @Test(timeout = 2000)
271 public void shutdownWithInterrupt() {
272 new ShutdownTest().run(true);
273 long timeSpent = runtime.stop();
274 assertTrue(beforeShutdown);
275 assertThat(timeSpent, between(450, 1250));
276 }
277
278 @Test
279 public void nothingParallel() {
280 JUnitCore core = new JUnitCore();
281 ParallelComputerBuilder builder = new ParallelComputerBuilder();
282
283 Result result = core.run(builder.buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class);
284 assertTrue(result.wasSuccessful());
285
286 result = core.run(builder.buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class);
287 assertTrue(result.wasSuccessful());
288
289 result = core.run(builder.useOnePool(1).buildComputer(), NothingDoingTest1.class, NothingDoingTest2.class);
290 assertTrue(result.wasSuccessful());
291
292 result = core.run(builder.useOnePool(1).buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class);
293 assertTrue(result.wasSuccessful());
294
295 result = core.run(builder.useOnePool(2).buildComputer(), NothingDoingTest1.class, NothingDoingSuite.class);
296 assertTrue(result.wasSuccessful());
297
298 Class<?>[] classes = {NothingDoingTest1.class, NothingDoingSuite.class};
299
300 result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses(1).buildComputer(), classes);
301 assertTrue(result.wasSuccessful());
302
303 result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses().buildComputer(), classes);
304 assertTrue(result.wasSuccessful());
305
306 classes = new Class<?>[]{NothingDoingSuite.class, NothingDoingSuite.class,
307 NothingDoingTest1.class, NothingDoingTest2.class, NothingDoingTest3.class};
308
309 result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses(1).buildComputer(), classes);
310 assertTrue(result.wasSuccessful());
311
312 result = core.run(builder.useOnePool(2).parallelSuites(1).parallelClasses().buildComputer(), classes);
313 assertTrue(result.wasSuccessful());
314 }
315
316 private static void testKeepBeforeAfter(ParallelComputerBuilder builder, Class<?>... classes) {
317 JUnitCore core = new JUnitCore();
318 for (int round = 0; round < 5; round++) {
319 NothingDoingTest1.methods.clear();
320 Result result = core.run(builder.buildComputer(), classes);
321 assertTrue(result.wasSuccessful());
322 Iterator<String> methods = NothingDoingTest1.methods.iterator();
323 for (Class<?> clazz : classes) {
324 String a = clazz.getName() + "#a()";
325 String b = clazz.getName() + "#b()";
326 assertThat(methods.next(), is("init"));
327 assertThat(methods.next(), anyOf(is(a), is(b)));
328 assertThat(methods.next(), anyOf(is(a), is(b)));
329 assertThat(methods.next(), is("deinit"));
330 }
331 }
332 }
333
334 @Test
335 public void keepBeforeAfterOneClass() {
336 ParallelComputerBuilder builder = new ParallelComputerBuilder();
337 builder.parallelMethods();
338 testKeepBeforeAfter(builder, NothingDoingTest1.class);
339 }
340
341 @Test
342 public void keepBeforeAfterTwoClasses() {
343 ParallelComputerBuilder builder = new ParallelComputerBuilder();
344 builder.useOnePool(5).parallelClasses(1).parallelMethods(2);
345 testKeepBeforeAfter(builder, NothingDoingTest1.class, NothingDoingTest2.class);
346 }
347
348 @Test
349 public void keepBeforeAfterTwoParallelClasses() {
350 ParallelComputerBuilder builder = new ParallelComputerBuilder();
351 builder.useOnePool(8).parallelClasses(2).parallelMethods(2);
352 JUnitCore core = new JUnitCore();
353 NothingDoingTest1.methods.clear();
354 Class<?>[] classes = {NothingDoingTest1.class, NothingDoingTest2.class, NothingDoingTest3.class};
355 Result result = core.run(builder.buildComputer(), classes);
356 assertTrue(result.wasSuccessful());
357 ArrayList<String> methods = new ArrayList<String>(NothingDoingTest1.methods);
358 assertThat(methods.size(), is(12));
359 assertThat(methods.subList(9, 12), is(not(Arrays.asList("deinit", "deinit", "deinit"))));
360 }
361
362 private static volatile boolean beforeShutdown;
363 private static volatile Runnable shutdownTask;
364
365 public static class Class1 {
366 static volatile int concurrentMethods = 0;
367 static volatile int maxConcurrentMethods = 0;
368
369 @Test
370 public void test1() throws InterruptedException {
371 synchronized (Class1.class) {
372 ++concurrentMethods;
373 Class1.class.wait(500);
374 maxConcurrentMethods = Math.max(maxConcurrentMethods, concurrentMethods--);
375 }
376 }
377
378 @Test
379 public void test2() throws InterruptedException {
380 test1();
381 Runnable shutdownTask = ParallelComputerBuilderTest.shutdownTask;
382 if (shutdownTask != null) {
383 beforeShutdown = true;
384 shutdownTask.run();
385 }
386 }
387 }
388
389 public static class Class2 extends Class1 {
390 }
391
392 public static class Class3 extends Class1 {
393 }
394
395 @RunWith(Suite.class)
396 @Suite.SuiteClasses({Class2.class, Class1.class})
397 public class TestSuite {
398 }
399
400 public static class NothingDoingTest1 {
401 static final Collection<String> methods = new ConcurrentLinkedQueue<String>();
402
403 @BeforeClass
404 public static void init() {
405 methods.add("init");
406 }
407
408 @Test
409 public void a() throws InterruptedException {
410 Thread.sleep(5);
411 methods.add(getClass().getName() + "#a()");
412 }
413
414 @Test
415 public void b() throws InterruptedException {
416 Thread.sleep(5);
417 methods.add(getClass().getName() + "#b()");
418 }
419
420 @AfterClass
421 public static void deinit() {
422 methods.add("deinit");
423 }
424 }
425
426 public static class NothingDoingTest2 extends NothingDoingTest1 {
427 }
428
429 public static class NothingDoingTest3 extends NothingDoingTest1 {
430 }
431
432 @RunWith(Suite.class)
433 @Suite.SuiteClasses({NothingDoingTest1.class, NothingDoingTest2.class})
434 public static class NothingDoingSuite {
435 }
436 }