Skip to content

Commit 3c3ffba

Browse files
committed
Serialize tests during coverage calculation
This generically fixes hcoles/pitest#760 and #73 for all platform engines, removing the Jupiter specific work-around from #74 and serializing test execution during coverage calculation using locks. This way the tests can also properly run in parallel later on during mutant hunting.
1 parent 73391eb commit 3c3ffba

2 files changed

Lines changed: 30 additions & 4 deletions

File tree

src/main/java/org/pitest/junit5/JUnit5TestPluginFactory.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@
2727
public class JUnit5TestPluginFactory implements TestPluginFactory {
2828

2929
@Override
30-
public Configuration createTestFrameworkConfiguration(TestGroupConfig config,
31-
ClassByteArraySource source,
30+
public Configuration createTestFrameworkConfiguration(TestGroupConfig config,
31+
ClassByteArraySource source,
3232
Collection<String> excludedRunners,
3333
Collection<String> includedTestMethods) {
34-
System.setProperty("junit.jupiter.execution.parallel.enabled", "false");
3534
return new JUnit5Configuration(config, includedTestMethods);
3635
}
3736

src/main/java/org/pitest/junit5/JUnit5TestUnitFinder.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
import java.util.ArrayList;
1818
import java.util.Collection;
1919
import java.util.List;
20+
import java.util.Map;
21+
import java.util.concurrent.ConcurrentHashMap;
22+
import java.util.concurrent.locks.ReentrantLock;
2023

2124
import static java.util.Collections.emptyList;
2225
import static java.util.Collections.synchronizedList;
@@ -26,6 +29,7 @@
2629
import org.junit.platform.commons.PreconditionViolationException;
2730
import org.junit.platform.engine.Filter;
2831
import org.junit.platform.engine.TestExecutionResult;
32+
import org.junit.platform.engine.UniqueId;
2933
import org.junit.platform.engine.discovery.DiscoverySelectors;
3034
import org.junit.platform.engine.support.descriptor.MethodSource;
3135
import org.junit.platform.launcher.Launcher;
@@ -35,6 +39,7 @@
3539
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
3640
import org.junit.platform.launcher.core.LauncherFactory;
3741
import org.pitest.testapi.Description;
42+
import org.pitest.testapi.NullExecutionListener;
3843
import org.pitest.testapi.TestGroupConfig;
3944
import org.pitest.testapi.TestUnit;
4045
import org.pitest.testapi.TestUnitExecutionListener;
@@ -97,10 +102,14 @@ private class TestIdentifierListener implements TestExecutionListener {
97102
private final Class<?> testClass;
98103
private final TestUnitExecutionListener l;
99104
private final List<TestIdentifier> identifiers = synchronizedList(new ArrayList<>());
105+
private final boolean serializeExecution;
106+
private final Map<UniqueId, ReentrantLock> coverageSerializers = new ConcurrentHashMap<>();
107+
private final ReentrantLock rootCoverageSerializer = new ReentrantLock();
100108

101109
public TestIdentifierListener(Class<?> testClass, TestUnitExecutionListener l) {
102110
this.testClass = testClass;
103111
this.l = l;
112+
serializeExecution = !(l instanceof NullExecutionListener);
104113
}
105114

106115
List<TestIdentifier> getIdentifiers() {
@@ -117,12 +126,21 @@ public void executionStarted(TestIdentifier testIdentifier) {
117126
&& !includedTestMethods.contains(((MethodSource)testIdentifier.getSource().get()).getMethodName())) {
118127
return;
119128
}
129+
130+
if (serializeExecution) {
131+
testIdentifier
132+
.getParentIdObject()
133+
.map(coverageSerializers::get)
134+
.orElse(rootCoverageSerializer)
135+
.lock();
136+
coverageSerializers.put(testIdentifier.getUniqueIdObject(), new ReentrantLock());
137+
}
138+
120139
l.executionStarted(new Description(testIdentifier.getUniqueId(), testClass));
121140
identifiers.add(testIdentifier);
122141
}
123142
}
124143

125-
126144
@Override
127145
public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
128146
// Classes with failing BeforeAlls never start execution and identify as 'containers' not 'tests'
@@ -133,6 +151,15 @@ public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult
133151
l.executionFinished(new Description(testIdentifier.getUniqueId(), testClass), false);
134152
} else if (testIdentifier.isTest()) {
135153
l.executionFinished(new Description(testIdentifier.getUniqueId(), testClass), true);
154+
155+
if (serializeExecution) {
156+
coverageSerializers.remove(testIdentifier.getUniqueIdObject());
157+
testIdentifier
158+
.getParentIdObject()
159+
.map(coverageSerializers::get)
160+
.orElse(rootCoverageSerializer)
161+
.unlock();
162+
}
136163
}
137164
}
138165

0 commit comments

Comments
 (0)