Skip to content

Commit 5d7f8bd

Browse files
authored
Use junit5 engine vintage runner to run junit4 tests (#15949)
* Use junit5 and vintage runner, initial feasibility study. * Add missing licenses and junit platform configuration within the plugin. * Add changes entry.:
1 parent 7ca782c commit 5d7f8bd

16 files changed

Lines changed: 819 additions & 232 deletions

build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/TestsAndRandomizationPlugin.java

Lines changed: 24 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -20,55 +20,37 @@
2020
import com.carrotsearch.gradle.buildinfra.buildoptions.BuildOptionsPlugin;
2121
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
2222
import java.io.File;
23-
import java.io.IOException;
24-
import java.lang.classfile.ClassFile;
25-
import java.lang.classfile.ClassModel;
2623
import java.nio.file.Path;
2724
import java.util.LinkedHashSet;
2825
import java.util.List;
26+
import java.util.Map;
2927
import java.util.Random;
3028
import java.util.Set;
31-
import javax.inject.Inject;
3229
import org.apache.lucene.gradle.plugins.LuceneGradlePlugin;
3330
import org.apache.lucene.gradle.plugins.globals.LuceneBuildGlobalsExtension;
3431
import org.apache.tools.ant.taskdefs.condition.Os;
3532
import org.apache.tools.ant.types.Commandline;
36-
import org.gradle.api.Action;
3733
import org.gradle.api.GradleException;
3834
import org.gradle.api.JavaVersion;
3935
import org.gradle.api.Project;
36+
import org.gradle.api.artifacts.VersionCatalogsExtension;
4037
import org.gradle.api.file.Directory;
4138
import org.gradle.api.file.DirectoryProperty;
4239
import org.gradle.api.file.RegularFileProperty;
43-
import org.gradle.api.internal.file.RelativeFile;
44-
import org.gradle.api.internal.tasks.testing.ClassTestDefinition;
45-
import org.gradle.api.internal.tasks.testing.TestDefinitionProcessor;
46-
import org.gradle.api.internal.tasks.testing.TestFramework;
47-
import org.gradle.api.internal.tasks.testing.WorkerTestDefinitionProcessorFactory;
48-
import org.gradle.api.internal.tasks.testing.detection.TestFrameworkDetector;
49-
import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter;
50-
import org.gradle.api.internal.tasks.testing.junit.JUnitSpec;
51-
import org.gradle.api.internal.tasks.testing.junit.JUnitTestDefinitionProcessorFactory;
5240
import org.gradle.api.invocation.Gradle;
53-
import org.gradle.api.model.ObjectFactory;
5441
import org.gradle.api.plugins.JavaPlugin;
5542
import org.gradle.api.provider.Provider;
5643
import org.gradle.api.tasks.Delete;
5744
import org.gradle.api.tasks.InputFile;
5845
import org.gradle.api.tasks.Internal;
59-
import org.gradle.api.tasks.Nested;
6046
import org.gradle.api.tasks.PathSensitive;
6147
import org.gradle.api.tasks.PathSensitivity;
6248
import org.gradle.api.tasks.TaskContainer;
6349
import org.gradle.api.tasks.compile.JavaCompile;
6450
import org.gradle.api.tasks.testing.Test;
65-
import org.gradle.api.tasks.testing.TestFilter;
66-
import org.gradle.api.tasks.testing.junit.JUnitOptions;
6751
import org.gradle.api.tasks.testing.logging.TestExceptionFormat;
6852
import org.gradle.api.tasks.testing.logging.TestLogEvent;
69-
import org.gradle.internal.Factory;
7053
import org.gradle.process.CommandLineArgumentProvider;
71-
import org.gradle.process.internal.worker.WorkerProcessBuilder;
7254

7355
/** Sets up gradle's Test task configuration, including all kinds of randomized options */
7456
public class TestsAndRandomizationPlugin extends LuceneGradlePlugin {
@@ -444,19 +426,10 @@ public void apply(Project project) {
444426
task.setFailFast(true);
445427
}
446428

447-
task.setWorkingDir(testsCwd);
429+
// Use junit platform and junit-vintage to run the tests.
430+
configureJUnitPlatform(task);
448431

449-
// do not use any of the existing gradle frameworks.
450-
// see https://github.com/gradle/gradle/issues/36508
451-
task.getTestFrameworkProperty()
452-
.set(
453-
project
454-
.getObjects()
455-
.newInstance(
456-
LuceneTestFramework.class,
457-
new Object[] {
458-
task.getFilter(), task.getTemporaryDirFactory(), task.getDryRun()
459-
}));
432+
task.setWorkingDir(testsCwd);
460433

461434
task.setMinHeapSize(minHeapSizeOption.get());
462435
task.setMaxHeapSize(heapSizeOption.get());
@@ -591,6 +564,25 @@ public void apply(Project project) {
591564
});
592565
}
593566

567+
private static void configureJUnitPlatform(Test task) {
568+
task.useJUnitPlatform();
569+
var junitPlatformBundle =
570+
task.getProject()
571+
.getExtensions()
572+
.findByType(VersionCatalogsExtension.class)
573+
.named("deps")
574+
.findBundle("junitplatform");
575+
task.getProject()
576+
.getDependencies()
577+
.addProvider(
578+
"moduleTestRuntimeOnly",
579+
junitPlatformBundle.orElseThrow(),
580+
config -> {
581+
config.exclude(Map.of("group", "org.hamcrest"));
582+
config.exclude(Map.of("group", "junit"));
583+
});
584+
}
585+
594586
public abstract static class TestOutputsExtension {
595587
abstract DirectoryProperty getTestOutputsDir();
596588
}
@@ -643,114 +635,4 @@ private static boolean addVectorizationOptions(
643635

644636
return defaultVectorizationOption.get();
645637
}
646-
647-
public abstract static class LuceneTestFramework implements TestFramework {
648-
private final DefaultTestFilter filter;
649-
private final Factory<File> testTaskTemporaryDir;
650-
private final Provider<Boolean> dryRun;
651-
private TestFrameworkDetector detector =
652-
new TestFrameworkDetector() {
653-
private TestDefinitionProcessor<? super ClassTestDefinition> testDefinitionProcessor;
654-
655-
@Override
656-
public void startDetection(
657-
TestDefinitionProcessor<? super ClassTestDefinition> testDefinitionProcessor) {
658-
this.testDefinitionProcessor = testDefinitionProcessor;
659-
}
660-
661-
@Override
662-
public boolean processTestClass(RelativeFile testClassFile) {
663-
var cc =
664-
ClassFile.of(
665-
ClassFile.ConstantPoolSharingOption.NEW_POOL,
666-
ClassFile.DebugElementsOption.DROP_DEBUG,
667-
ClassFile.LineNumbersOption.DROP_LINE_NUMBERS,
668-
ClassFile.StackMapsOption.DROP_STACK_MAPS);
669-
670-
try {
671-
ClassModel parsed = cc.parse(testClassFile.getFile().toPath());
672-
String internalName = parsed.thisClass().asInternalName().replace('/', '.');
673-
testDefinitionProcessor.processTestDefinition(new ClassTestDefinition(internalName));
674-
} catch (Exception e) {
675-
throw new RuntimeException(e);
676-
}
677-
678-
return true;
679-
}
680-
681-
@Override
682-
public void setTestClasses(List<File> testClasses) {}
683-
684-
@Override
685-
public void setTestClasspath(List<File> classpath) {}
686-
};
687-
688-
@Inject
689-
public LuceneTestFramework(
690-
DefaultTestFilter filter, Factory<File> testTaskTemporaryDir, Provider<Boolean> dryRun) {
691-
this.filter = filter;
692-
this.testTaskTemporaryDir = testTaskTemporaryDir;
693-
this.dryRun = dryRun;
694-
}
695-
696-
@Inject
697-
protected abstract ObjectFactory getObjectFactory();
698-
699-
@Override
700-
public TestFramework copyWithFilters(TestFilter newTestFilters) {
701-
var newTestFramework =
702-
this.getObjectFactory()
703-
.newInstance(
704-
LuceneTestFramework.class,
705-
new Object[] {newTestFilters, this.testTaskTemporaryDir, this.dryRun});
706-
newTestFramework.getOptions().copyFrom(this.getOptions());
707-
return newTestFramework;
708-
}
709-
710-
@Override
711-
public WorkerTestDefinitionProcessorFactory<?> getProcessorFactory() {
712-
this.validateOptions();
713-
return new JUnitTestDefinitionProcessorFactory(
714-
new JUnitSpec(
715-
this.filter.toSpec(),
716-
this.getOptions().getIncludeCategories(),
717-
this.getOptions().getExcludeCategories(),
718-
this.dryRun.get()));
719-
}
720-
721-
@Override
722-
public Action<WorkerProcessBuilder> getWorkerConfigurationAction() {
723-
return (workerProcessBuilder) -> {
724-
workerProcessBuilder.sharedPackages(new String[] {"junit.framework"});
725-
workerProcessBuilder.sharedPackages(new String[] {"junit.extensions"});
726-
workerProcessBuilder.sharedPackages(new String[] {"org.junit"});
727-
};
728-
}
729-
730-
@Override
731-
@Nested
732-
public abstract JUnitOptions getOptions();
733-
734-
@Override
735-
public TestFrameworkDetector getDetector() {
736-
return detector;
737-
}
738-
739-
@Override
740-
public void close() throws IOException {
741-
this.detector = null;
742-
}
743-
744-
private void validateOptions() {
745-
if (!this.getOptions().getIncludeCategories().isEmpty()
746-
|| !this.getOptions().getExcludeCategories().isEmpty()) {
747-
throw new RuntimeException("Include and exclude categories are not supported in Lucene.");
748-
}
749-
}
750-
751-
@Override
752-
public String getDisplayName() {
753-
return "JUnit";
754-
}
755-
}
756638
}

gradle/libs.versions.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ jmh-annprocess = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.
8383
jmh-core = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
8484
jts = { module = "org.locationtech.jts:jts-core", version.ref = "jts" }
8585
junit = { module = "junit:junit", version.ref = "junit" }
86+
junitplatform-launcher = "org.junit.platform:junit-platform-launcher:6.0.3"
87+
junitplatform-vintage = "org.junit.vintage:junit-vintage-engine:6.0.3"
8688
morfologik-polish = { module = "org.carrot2:morfologik-polish", version.ref = "morfologik" }
8789
morfologik-stemming = { module = "org.carrot2:morfologik-stemming", version.ref = "morfologik" }
8890
morfologik-ukrainian = { module = "ua.net.nlp:morfologik-ukrainian-search", version.ref = "morfologik-ukrainian" }
@@ -95,6 +97,12 @@ spatial4j = { module = "org.locationtech.spatial4j:spatial4j", version.ref = "sp
9597
xerces = { module = "xerces:xercesImpl", version.ref = "xerces" }
9698
zstd = { module = "com.github.luben:zstd-jni", version.ref = "zstd" }
9799

100+
[bundles]
101+
junitplatform = [
102+
"junitplatform-launcher",
103+
"junitplatform-vintage",
104+
]
105+
98106
[plugins]
99107
benmanes-versions = "com.github.ben-manes.versions:0.53.0"
100108
carrotsearch-buildopts = "com.carrotsearch.gradle.opts:0.2.1"

lucene/CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ Other
224224
* GITHUB#15867: Use StackWalker without method info for caller checks in internal classes and tests.
225225
(Uwe Schindler)
226226

227+
* GITHUB#15949: Use junit5 engine vintage runner to run junit4 tests. (Dawid Weiss)
228+
227229
======================= Lucene 10.5.0 =======================
228230

229231
API Changes

0 commit comments

Comments
 (0)