Skip to content

Commit 9a4fbbe

Browse files
authored
Create plugin for internalClusterTest task (#56312)
This commit creates a new gradle plugin to provide a separate task name and source set for running ESIntegTestCase tests. The only project converted to use the new plugin in this PR is server, as an example. The remaining cases in x-pack will be handled in followups. backport of #55896
1 parent ea4904f commit 9a4fbbe

File tree

357 files changed

+283
-104
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

357 files changed

+283
-104
lines changed

TESTING.asciidoc

Lines changed: 2 additions & 2 deletions

buildSrc/src/main/java/org/elasticsearch/gradle/precommit/TestingConventionsTasks.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import groovy.lang.Closure;
2222
import org.elasticsearch.gradle.util.GradleUtils;
23+
import org.elasticsearch.gradle.util.Util;
2324
import org.gradle.api.DefaultTask;
2425
import org.gradle.api.NamedDomainObjectContainer;
2526
import org.gradle.api.Task;
@@ -46,9 +47,12 @@
4647
import java.nio.file.Path;
4748
import java.nio.file.StandardOpenOption;
4849
import java.nio.file.attribute.BasicFileAttributes;
50+
import java.util.Arrays;
4951
import java.util.Collections;
5052
import java.util.HashMap;
53+
import java.util.List;
5154
import java.util.Map;
55+
import java.util.Objects;
5256
import java.util.Set;
5357
import java.util.function.Predicate;
5458
import java.util.stream.Collectors;
@@ -62,6 +66,8 @@ public class TestingConventionsTasks extends DefaultTask {
6266

6367
private final NamedDomainObjectContainer<TestingConventionRule> naming;
6468

69+
private List<String> tasks = null;
70+
6571
public TestingConventionsTasks() {
6672
setDescription("Tests various testing conventions");
6773
// Run only after everything is compiled
@@ -74,15 +80,16 @@ public Map<String, Set<File>> getClassFilesPerEnabledTask() {
7480
return getProject().getTasks()
7581
.withType(Test.class)
7682
.stream()
83+
.filter(t -> tasks == null || tasks.contains(t.getName()))
7784
.filter(Task::getEnabled)
7885
.collect(Collectors.toMap(Task::getPath, task -> task.getCandidateClassFiles().getFiles()));
7986
}
8087

8188
@Input
8289
public Map<String, File> getTestClassNames() {
8390
if (testClassNames == null) {
84-
testClassNames = GradleUtils.getJavaSourceSets(getProject())
85-
.getByName("test")
91+
testClassNames = Util.getJavaTestSourceSet(getProject())
92+
.get()
8693
.getOutput()
8794
.getClassesDirs()
8895
.getFiles()
@@ -108,6 +115,10 @@ public void naming(Closure<TestingConventionRule> action) {
108115
naming.configure(action);
109116
}
110117

118+
public void setTasks(String... tasks) {
119+
this.tasks = Arrays.asList(tasks);
120+
}
121+
111122
@Input
112123
public Set<String> getMainClassNamedLikeTests() {
113124
SourceSetContainer javaSourceSets = GradleUtils.getJavaSourceSets(getProject());
@@ -319,6 +330,7 @@ private boolean seemsLikeATest(Class<?> clazz) {
319330
}
320331

321332
private boolean implementsNamingConvention(Class<?> clazz) {
333+
Objects.requireNonNull(clazz);
322334
return implementsNamingConvention(clazz.getName());
323335
}
324336

@@ -349,13 +361,7 @@ private FileCollection getTestsClassPath() {
349361
// the classes these don't influence the checks done by this task.
350362
// A side effect is that we could mark as up-to-date with missing dependencies, but these will be found when
351363
// running the tests.
352-
return getProject().files(
353-
getProject().getConfigurations().getByName("testRuntime").resolve(),
354-
GradleUtils.getJavaSourceSets(getProject())
355-
.stream()
356-
.flatMap(sourceSet -> sourceSet.getOutput().getClassesDirs().getFiles().stream())
357-
.collect(Collectors.toList())
358-
);
364+
return Util.getJavaTestSourceSet(getProject()).get().getRuntimeClasspath();
359365
}
360366

361367
private Map<String, File> walkPathAndLoadClasses(File testRoot) {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.gradle.test;
21+
22+
import org.elasticsearch.gradle.util.GradleUtils;
23+
import org.gradle.api.Plugin;
24+
import org.gradle.api.Project;
25+
import org.gradle.api.tasks.SourceSet;
26+
27+
public class InternalClusterTestPlugin implements Plugin<Project> {
28+
29+
public static final String SOURCE_SET_NAME = "internalClusterTest";
30+
31+
@Override
32+
public void apply(Project project) {
33+
GradleUtils.addTestSourceSet(project, SOURCE_SET_NAME);
34+
35+
// TODO: fix usages of IT tests depending on Tests methods so this extension is not necessary
36+
GradleUtils.extendSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME, SOURCE_SET_NAME);
37+
38+
// add alias task that is easier to type
39+
project.getTasks().register("icTest").configure(alias -> alias.dependsOn(SOURCE_SET_NAME));
40+
}
41+
}

buildSrc/src/main/java/org/elasticsearch/gradle/util/GradleUtils.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,34 @@
1818
*/
1919
package org.elasticsearch.gradle.util;
2020

21+
import org.elasticsearch.gradle.ElasticsearchJavaPlugin;
2122
import org.gradle.api.Action;
2223
import org.gradle.api.GradleException;
2324
import org.gradle.api.NamedDomainObjectContainer;
2425
import org.gradle.api.PolymorphicDomainObjectContainer;
2526
import org.gradle.api.Project;
2627
import org.gradle.api.Task;
2728
import org.gradle.api.UnknownTaskException;
29+
import org.gradle.api.artifacts.Configuration;
30+
import org.gradle.api.plugins.JavaBasePlugin;
2831
import org.gradle.api.plugins.JavaPluginConvention;
2932
import org.gradle.api.provider.Provider;
3033
import org.gradle.api.services.BuildService;
3134
import org.gradle.api.services.BuildServiceRegistration;
3235
import org.gradle.api.services.BuildServiceRegistry;
36+
import org.gradle.api.tasks.SourceSet;
3337
import org.gradle.api.tasks.SourceSetContainer;
3438
import org.gradle.api.tasks.TaskContainer;
3539
import org.gradle.api.tasks.TaskProvider;
40+
import org.gradle.api.tasks.testing.Test;
41+
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
42+
import org.gradle.plugins.ide.idea.model.IdeaModel;
3643

44+
import java.util.Arrays;
45+
import java.util.List;
46+
import java.util.Map;
3747
import java.util.Optional;
48+
import java.util.function.Function;
3849

3950
public abstract class GradleUtils {
4051

@@ -120,4 +131,79 @@ public static <T extends BuildService<?>> Provider<T> getBuildService(BuildServi
120131

121132
return (Provider<T>) registration.getService();
122133
}
134+
135+
/**
136+
* Add a source set and task of the same name that runs tests.
137+
*
138+
* IDEs are also configured if setup, and the test task is added to check. The new test source
139+
* set extends from the normal test source set to allow sharing of utilities.
140+
*
141+
* @return A task provider for the newly created test task
142+
*/
143+
public static TaskProvider<?> addTestSourceSet(Project project, String sourceSetName) {
144+
project.getPluginManager().apply(ElasticsearchJavaPlugin.class);
145+
146+
// create our test source set and task
147+
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
148+
SourceSet testSourceSet = sourceSets.create(sourceSetName);
149+
TaskProvider<Test> testTask = project.getTasks().register(sourceSetName, Test.class);
150+
testTask.configure(task -> {
151+
task.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
152+
task.setTestClassesDirs(testSourceSet.getOutput().getClassesDirs());
153+
task.setClasspath(testSourceSet.getRuntimeClasspath());
154+
});
155+
156+
Configuration testCompileConfig = project.getConfigurations().getByName(testSourceSet.getCompileClasspathConfigurationName());
157+
Configuration testRuntimeConfig = project.getConfigurations().getByName(testSourceSet.getRuntimeClasspathConfigurationName());
158+
testSourceSet.setCompileClasspath(testCompileConfig);
159+
testSourceSet.setRuntimeClasspath(project.getObjects().fileCollection().from(testSourceSet.getOutput(), testRuntimeConfig));
160+
161+
extendSourceSet(project, SourceSet.MAIN_SOURCE_SET_NAME, sourceSetName);
162+
163+
// setup IDEs
164+
String runtimeClasspathName = testSourceSet.getRuntimeClasspathConfigurationName();
165+
Configuration runtimeClasspathConfiguration = project.getConfigurations().getByName(runtimeClasspathName);
166+
project.getPluginManager().withPlugin("idea", p -> {
167+
IdeaModel idea = project.getExtensions().getByType(IdeaModel.class);
168+
idea.getModule().setTestSourceDirs(testSourceSet.getJava().getSrcDirs());
169+
idea.getModule().getScopes().put("TEST", Map.of("plus", List.of(runtimeClasspathConfiguration)));
170+
});
171+
project.getPluginManager().withPlugin("eclipse", p -> {
172+
EclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);
173+
eclipse.getClasspath().setSourceSets(List.of(testSourceSet));
174+
eclipse.getClasspath().getPlusConfigurations().add(runtimeClasspathConfiguration);
175+
});
176+
177+
// add to the check task
178+
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME).configure(check -> check.dependsOn(testTask));
179+
180+
return testTask;
181+
}
182+
183+
/**
184+
* Extend the configurations of one source set from another.
185+
*/
186+
public static void extendSourceSet(Project project, String parentSourceSetName, String childSourceSetName) {
187+
final List<Function<SourceSet, String>> configNameFunctions = Arrays.asList(
188+
SourceSet::getCompileConfigurationName,
189+
SourceSet::getImplementationConfigurationName,
190+
SourceSet::getRuntimeConfigurationName,
191+
SourceSet::getRuntimeOnlyConfigurationName
192+
);
193+
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
194+
SourceSet parent = sourceSets.getByName(parentSourceSetName);
195+
SourceSet child = sourceSets.getByName(childSourceSetName);
196+
197+
for (Function<SourceSet, String> configNameFunction : configNameFunctions) {
198+
String parentConfigName = configNameFunction.apply(parent);
199+
String childConfigName = configNameFunction.apply(child);
200+
Configuration parentConfig = project.getConfigurations().getByName(parentConfigName);
201+
Configuration childConfig = project.getConfigurations().getByName(childConfigName);
202+
childConfig.extendsFrom(parentConfig);
203+
}
204+
205+
// tie this new test source set to the main and test source sets
206+
child.setCompileClasspath(project.getObjects().fileCollection().from(child.getCompileClasspath(), parent.getOutput()));
207+
child.setRuntimeClasspath(project.getObjects().fileCollection().from(child.getRuntimeClasspath(), parent.getOutput()));
208+
}
123209
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#
2+
# Licensed to Elasticsearch under one or more contributor
3+
# license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright
5+
# ownership. Elasticsearch licenses this file to you under
6+
# the Apache License, Version 2.0 (the "License"); you may
7+
# not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
20+
implementation-class=org.elasticsearch.gradle.test.InternalClusterTestPlugin

docs/java-api/index.asciidoc

Lines changed: 1 addition & 1 deletion

server/build.gradle

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import org.elasticsearch.gradle.info.BuildParams
2222
apply plugin: 'elasticsearch.build'
2323
apply plugin: 'nebula.optional-base'
2424
apply plugin: 'nebula.maven-base-publish'
25+
apply plugin: 'elasticsearch.internal-cluster-test'
2526

2627
publishing {
2728
publications {
@@ -133,10 +134,15 @@ dependencies {
133134

134135
testCompile 'com.google.jimfs:jimfs:1.1'
135136
testCompile 'com.google.guava:guava:18.0'
137+
138+
internalClusterTestCompile(project(":test:framework")) {
139+
exclude group: 'org.elasticsearch', module: 'server'
140+
}
136141
}
137142

138143
compileJava.options.compilerArgs << "-Xlint:-cast,-rawtypes,-unchecked"
139144
compileTestJava.options.compilerArgs << "-Xlint:-cast,-rawtypes,-unchecked"
145+
compileInternalClusterTestJava.options.compilerArgs << "-Xlint:-cast,-rawtypes,-unchecked"
140146

141147
// Until this project is always being formatted with spotless, we need to
142148
// guard against `spotless()` not existing.
@@ -173,6 +179,7 @@ testingConventions {
173179
baseClass "org.elasticsearch.test.ESSingleNodeTestCase"
174180
}
175181
}
182+
tasks = ['test']
176183
}
177184

178185
task generateModulesList {
@@ -330,18 +337,12 @@ dependencyLicenses {
330337
}
331338
}
332339

333-
334-
task integTest(type: Test) {
335-
description = 'Multi-node tests'
336-
mustRunAfter test
337-
338-
include '**/*IT.class'
340+
tasks.named('internalClusterTest').configure {
341+
if (org.elasticsearch.gradle.info.BuildParams.isSnapshotBuild() == false) {
342+
systemProperty 'es.datastreams_feature_enabled', 'true'
343+
}
339344
}
340345

341-
check.dependsOn integTest
342-
343-
task internalClusterTest {
344-
dependsOn integTest
346+
licenseHeaders {
347+
excludes << 'org/elasticsearch/client/documentation/placeholder.txt'
345348
}
346-
347-
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)