Skip to content

Commit d111712

Browse files
mpkorstanjemarcphilipp
authored andcommitted
Add test for race condition when starting workers
1 parent ba98383 commit d111712

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ConcurrentHierarchicalTestExecutorServiceTests.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.concurrent.CompletableFuture;
3333
import java.util.concurrent.CountDownLatch;
3434
import java.util.concurrent.locks.ReentrantLock;
35+
import java.util.stream.Stream;
3536

3637
import org.jspecify.annotations.NullMarked;
3738
import org.jspecify.annotations.Nullable;
@@ -275,6 +276,45 @@ void prioritizesTestsOverContainers() throws Exception {
275276
assertThat(child2.startTime).isBeforeOrEqualTo(child1.startTime);
276277
}
277278

279+
@Test
280+
void limitsWorkerThreadsToMaxPoolSize() throws Exception {
281+
service = new ConcurrentHierarchicalTestExecutorService(configuration(3, 3));
282+
283+
CountDownLatch latch = new CountDownLatch(3);
284+
Executable behavior = () -> {
285+
latch.countDown();
286+
latch.await();
287+
};
288+
var leaf1a = new TestTaskStub(ExecutionMode.CONCURRENT, behavior) //
289+
.withName("leaf1a").withLevel(3);
290+
var leaf1b = new TestTaskStub(ExecutionMode.CONCURRENT, behavior) //
291+
.withName("leaf1b").withLevel(3);
292+
var leaf2a = new TestTaskStub(ExecutionMode.CONCURRENT, behavior) //
293+
.withName("leaf2a").withLevel(3);
294+
var leaf2b = new TestTaskStub(ExecutionMode.CONCURRENT, behavior) //
295+
.withName("leaf2b").withLevel(3);
296+
297+
// When executed, there are 2 worker threads active and 1 available.
298+
// Both invokeAlls race each other trying to start 1 more.
299+
var child1 = new TestTaskStub(ExecutionMode.CONCURRENT,
300+
() -> requiredService().invokeAll(List.of(leaf1a, leaf1b))) //
301+
.withName("child1").withLevel(2);
302+
var child2 = new TestTaskStub(ExecutionMode.CONCURRENT,
303+
() -> requiredService().invokeAll(List.of(leaf2a, leaf2b))) //
304+
.withName("child2").withLevel(2);
305+
306+
var root = new TestTaskStub(ExecutionMode.SAME_THREAD,
307+
() -> requiredService().invokeAll(List.of(child1, child2))) //
308+
.withName("root").withLevel(1);
309+
310+
service.submit(root).get();
311+
312+
assertThat(List.of(root, child1, child2, leaf1a, leaf1b, leaf2a, leaf2b)) //
313+
.allSatisfy(TestTaskStub::assertExecutedSuccessfully);
314+
assertThat(Stream.of(leaf1a, leaf1b, leaf2a, leaf2b).map(TestTaskStub::executionThread).distinct()) //
315+
.hasSize(3);
316+
}
317+
278318
private static ExclusiveResource exclusiveResource() {
279319
return new ExclusiveResource("key", ExclusiveResource.LockMode.READ_WRITE);
280320
}
@@ -284,7 +324,11 @@ private ConcurrentHierarchicalTestExecutorService requiredService() {
284324
}
285325

286326
private static ParallelExecutionConfiguration configuration(int parallelism) {
287-
return new DefaultParallelExecutionConfiguration(parallelism, parallelism, 256 + parallelism, parallelism, 0,
327+
return configuration(parallelism, 256 + parallelism);
328+
}
329+
330+
private static ParallelExecutionConfiguration configuration(int parallelism, int maxPoolSize) {
331+
return new DefaultParallelExecutionConfiguration(parallelism, parallelism, maxPoolSize, parallelism, 0,
288332
__ -> true);
289333
}
290334

0 commit comments

Comments
 (0)