Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce yamlTest task and source set #55833

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@

import groovy.lang.Closure;
import org.elasticsearch.gradle.util.GradleUtils;
import org.elasticsearch.gradle.util.Util;
import org.gradle.api.DefaultTask;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.Input;
Expand Down Expand Up @@ -81,15 +83,30 @@ public Map<String, Set<File>> getClassFilesPerEnabledTask() {
@Input
public Map<String, File> getTestClassNames() {
if (testClassNames == null) {
testClassNames = GradleUtils.getJavaSourceSets(getProject())
.getByName("test")
// add standard test source sets class files
testClassNames = Util.getJavaTestSourceSet(getProject())
.get()
.getOutput()
.getClassesDirs()
.getFiles()
.stream()
.filter(File::exists)
.flatMap(testRoot -> walkPathAndLoadClasses(testRoot).entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

// add yaml test source sets if they exist
if (Util.getYamlTestSourceSet(getProject()).isPresent()) {
Map<String, File> yamlTestClassNames = Util.getYamlTestSourceSet(getProject())
.get()
.getOutput()
.getClassesDirs()
.getFiles()
.stream()
.filter(File::exists)
.flatMap(testRoot -> walkPathAndLoadClasses(testRoot).entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
testClassNames.putAll(yamlTestClassNames);
}
}
return testClassNames;
}
Expand Down Expand Up @@ -349,8 +366,11 @@ private FileCollection getTestsClassPath() {
// the classes these don't influence the checks done by this task.
// A side effect is that we could mark as up-to-date with missing dependencies, but these will be found when
// running the tests.
Configuration yamlTestRuntime = getProject().getConfigurations().findByName("yamlTestRuntime");
Configuration testRuntime = getProject().getConfigurations().getByName("testRuntime");
return getProject().files(
getProject().getConfigurations().getByName("testRuntime").resolve(),
testRuntime.resolve(),
yamlTestRuntime != null ? yamlTestRuntime.resolve() : null,
GradleUtils.getJavaSourceSets(getProject())
.stream()
.flatMap(sourceSet -> sourceSet.getOutput().getClassesDirs().getFiles().stream())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import org.elasticsearch.gradle.VersionProperties;
import org.elasticsearch.gradle.info.BuildParams;
import org.elasticsearch.gradle.util.GradleUtils;
import org.elasticsearch.gradle.util.Util;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
Expand All @@ -41,6 +41,8 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -109,7 +111,8 @@ public FileTree getInputDir() {

@OutputDirectory
public File getOutputDir() {
return new File(getTestSourceSet().getOutput().getResourcesDir(), REST_API_PREFIX);
assert Util.getSingleTestSourceSet(getProject()).isPresent();
return new File(Util.getSingleTestSourceSet(getProject()).get().getOutput().getResourcesDir(), REST_API_PREFIX);
}

@TaskAction
Expand All @@ -131,7 +134,8 @@ void copy() {
);
project.copy(c -> {
c.from(project.zipTree(coreConfig.getSingleFile()));
c.into(getTestSourceSet().getOutput().getResourcesDir()); // this ends up as the same dir as outputDir
// this ends up as the same dir as outputDir
c.into(Objects.requireNonNull(Util.getSingleTestSourceSet(getProject()).orElseThrow().getOutput().getResourcesDir()));
if (includeCore.get().isEmpty()) {
c.include(REST_API_PREFIX + "/**");
} else {
Expand Down Expand Up @@ -178,31 +182,26 @@ private boolean projectHasYamlRestTests() {
}

private File getTestSourceResourceDir() {
SourceSet testSources = getTestSourceSet();
if (testSources == null) {
return null;
}
Set<File> resourceDir = testSources.getResources()
.getSrcDirs()
.stream()
.filter(f -> f.isDirectory() && f.getParentFile().getName().equals("test") && f.getName().equals("resources"))
.collect(Collectors.toSet());
assert resourceDir.size() <= 1;
if (resourceDir.size() == 0) {
Optional<SourceSet> testSourceSet = Util.getSingleTestSourceSet(getProject());
if (testSourceSet.isPresent()) {
SourceSet testSources = testSourceSet.get();
Set<File> resourceDir = testSources.getResources()
.getSrcDirs()
.stream()
.filter(f -> f.isDirectory() && f.getParentFile().getName().equals("test") && f.getName().equals("resources"))
.collect(Collectors.toSet());
assert resourceDir.size() <= 1;
if (resourceDir.size() == 0) {
return null;
}
return resourceDir.iterator().next();
} else {
return null;
}
return resourceDir.iterator().next();
}

private File getTestOutputResourceDir() {
SourceSet testSources = getTestSourceSet();
if (testSources == null) {
return null;
}
return testSources.getOutput().getResourcesDir();
}

private SourceSet getTestSourceSet() {
return GradleUtils.getJavaSourceSets(getProject()).findByName("test");
Optional<SourceSet> testSourceSet = Util.getSingleTestSourceSet(getProject());
return testSourceSet.map(sourceSet -> sourceSet.getOutput().getResourcesDir()).orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import org.elasticsearch.gradle.VersionProperties;
import org.elasticsearch.gradle.info.BuildParams;
import org.elasticsearch.gradle.util.GradleUtils;
import org.elasticsearch.gradle.util.Util;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
Expand All @@ -31,14 +31,14 @@
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.util.PatternFilterable;
import org.gradle.api.tasks.util.PatternSet;
import org.gradle.internal.Factory;

import javax.inject.Inject;
import java.io.File;
import java.util.Objects;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -103,7 +103,8 @@ public FileTree getInputDir() {

@OutputDirectory
public File getOutputDir() {
return new File(getTestSourceSet().getOutput().getResourcesDir(), REST_TEST_PREFIX);
assert Util.getSingleTestSourceSet(getProject()).isPresent();
return new File(Util.getSingleTestSourceSet(getProject()).get().getOutput().getResourcesDir(), REST_TEST_PREFIX);
}

@TaskAction
Expand All @@ -127,7 +128,8 @@ void copy() {
);
project.copy(c -> {
c.from(project.zipTree(coreConfig.getSingleFile()));
c.into(getTestSourceSet().getOutput().getResourcesDir()); // this ends up as the same dir as outputDir
// this ends up as the same dir as outputDir
c.into(Objects.requireNonNull(Util.getSingleTestSourceSet(getProject()).orElseThrow().getOutput().getResourcesDir()));
c.include(
includeCore.get().stream().map(prefix -> REST_TEST_PREFIX + "/" + prefix + "*/**").collect(Collectors.toList())
);
Expand All @@ -144,8 +146,4 @@ void copy() {
});
}
}

private SourceSet getTestSourceSet() {
return GradleUtils.getJavaSourceSets(getProject()).findByName("test");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.gradle.test.rest;

import org.elasticsearch.gradle.plugin.PluginPropertiesExtension;
import org.elasticsearch.gradle.test.RestIntegTestTask;
import org.elasticsearch.gradle.testclusters.RestTestRunnerTask;
import org.elasticsearch.gradle.testclusters.TestClustersPlugin;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.bundling.Zip;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
import org.gradle.plugins.ide.idea.model.IdeaModel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
* Apply this plugin to run the YAML based REST tests. This will adda
*/
public class YamlTestPlugin implements Plugin<Project> {

@Override
public void apply(Project project) {

if (project.getPluginManager().hasPlugin("elasticsearch.build") == false
&& project.getPluginManager().hasPlugin("elasticsearch.standalone-rest-test") == false) {
throw new InvalidUserDataException(
"elasticsearch.build or elasticsearch.standalone-rest-test plugin " + "must be applied before the YAML test plugin"
);
}

// project.getPluginManager().apply(JavaPlugin.class); // for the Java based runner
project.getPluginManager().apply(TestClustersPlugin.class); // to spin up the external cluster
project.getPluginManager().apply(RestResourcesPlugin.class); // to copy around the yaml tests and json spec

// create source set
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
SourceSet yamlTestSourceSet = sourceSets.create("yamlTest");

// create task
RestIntegTestTask yamlTestTask = project.getTasks()
.create("yamlTest", RestIntegTestTask.class, task -> { task.dependsOn(project.getTasks().getByName("copyRestApiSpecsTask")); });
yamlTestTask.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
yamlTestTask.setDescription("Runs the YAML based REST tests against an external cluster");

// setup task dependency
project.getDependencies().add("yamlTestCompile", project.project(":test:framework"));

// ensure correct dependency and execution order
project.getTasks().getByName("check").dependsOn(yamlTestTask);
Task testTask = project.getTasks().findByName("test");
if (testTask != null) {
yamlTestTask.mustRunAfter(testTask);
}
yamlTestTask.mustRunAfter(project.getTasks().getByName("precommit"));

// setup the runner
RestTestRunnerTask runner = (RestTestRunnerTask) project.getTasks().getByName(yamlTestTask.getName() + "Runner");
runner.setTestClassesDirs(yamlTestSourceSet.getOutput().getClassesDirs());
runner.setClasspath(yamlTestSourceSet.getRuntimeClasspath());

// if this a module or plugin, it may have an associated zip file with it's contents, add that to the test cluster
boolean isModule = project.getPath().startsWith(":modules:");
Zip bundle = (Zip) project.getTasks().findByName("bundlePlugin");
if (bundle != null) {
yamlTestTask.dependsOn(bundle);
if (isModule) {
runner.getClusters().forEach(c -> c.module(bundle.getArchiveFile()));
} else {
runner.getClusters().forEach(c -> c.plugin(project.getObjects().fileProperty().value(bundle.getArchiveFile())));
}
}

// es-plugins may declare dependencies on additional modules, add those to the test cluster too.
project.afterEvaluate(p -> {
PluginPropertiesExtension pluginPropertiesExtension = project.getExtensions().findByType(PluginPropertiesExtension.class);
if (pluginPropertiesExtension != null) { // not all projects are defined as plugins
pluginPropertiesExtension.getExtendedPlugins().forEach(pluginName -> {
Project extensionProject = project.getProject().findProject(":modules:" + pluginName);
if (extensionProject != null) { // extension plugin may be defined, but not required to be a module
Zip extensionBundle = (Zip) extensionProject.getTasks().getByName("bundlePlugin");
yamlTestTask.dependsOn(extensionBundle);
runner.getClusters().forEach(c -> c.module(extensionBundle.getArchiveFile()));
}
});
}
});

// setup eclipse
EclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);
List<SourceSet> eclipseSourceSets = StreamSupport.stream(eclipse.getClasspath().getSourceSets().spliterator(), false)
.collect(Collectors.toList());
eclipseSourceSets.add(yamlTestSourceSet);
eclipse.getClasspath().setSourceSets(eclipseSourceSets);
List<Configuration> plusConfiguration = new ArrayList<>(eclipse.getClasspath().getPlusConfigurations());
plusConfiguration.add(project.getConfigurations().getByName("yamlTestRuntimeClasspath"));
eclipse.getClasspath().setPlusConfigurations(plusConfiguration);

// setup intellij
IdeaModel idea = project.getExtensions().getByType(IdeaModel.class);
idea.getModule().getTestSourceDirs().addAll(yamlTestSourceSet.getJava().getSrcDirs());
idea.getModule()
.getScopes()
.put("TEST", Map.of("plus", Collections.singletonList(project.getConfigurations().getByName("yamlTestRuntimeClasspath"))));
}
}
28 changes: 26 additions & 2 deletions buildSrc/src/main/java/org/elasticsearch/gradle/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public static FileTree getJavaMainSourceResources(Project project, Action<? supe
*/
@Nullable
public static FileTree getJavaTestSourceResources(Project project, Action<? super PatternFilterable> filter) {
final Optional<FileTree> testFileTree = getJavaTestSourceSet(project).map(SourceSet::getResources).map(FileTree::getAsFileTree);
final Optional<FileTree> testFileTree = getSingleTestSourceSet(project).map(SourceSet::getResources).map(FileTree::getAsFileTree);
return testFileTree.map(files -> files.matching(filter)).orElse(null);
}

Expand All @@ -113,7 +113,7 @@ public static FileTree getJavaTestSourceResources(Project project, Action<? supe
*/
@Nullable
public static FileTree getJavaTestAndMainSourceResources(Project project, Action<? super PatternFilterable> filter) {
final Optional<FileTree> testFileTree = getJavaTestSourceSet(project).map(SourceSet::getResources).map(FileTree::getAsFileTree);
final Optional<FileTree> testFileTree = getSingleTestSourceSet(project).map(SourceSet::getResources).map(FileTree::getAsFileTree);
final Optional<FileTree> mainFileTree = getJavaMainSourceSet(project).map(SourceSet::getResources).map(FileTree::getAsFileTree);
if (testFileTree.isPresent() && mainFileTree.isPresent()) {
return testFileTree.get().plus(mainFileTree.get()).matching(filter);
Expand All @@ -126,15 +126,39 @@ public static FileTree getJavaTestAndMainSourceResources(Project project, Action
}

/**
* Returns the source set for either the YamlTests or the standard test source set. Preference goes to YamlTest source set if it exists.
*
* @param project The project to look for test Java resources.
* @return An Optional that contains the Java test SourceSet if it exists.
*/
public static Optional<SourceSet> getSingleTestSourceSet(Project project) {
if (getYamlTestSourceSet(project).isPresent()) {
return getYamlTestSourceSet(project);
} else {
return getJavaTestSourceSet(project);
}
}

/**
* @param project The project to look for test Java sources.
* @return An Optional that contains the Java test SourceSet if it exists.
*/
public static Optional<SourceSet> getJavaTestSourceSet(Project project) {
return project.getConvention().findPlugin(JavaPluginConvention.class) == null
? Optional.empty()
: Optional.ofNullable(GradleUtils.getJavaSourceSets(project).findByName(SourceSet.TEST_SOURCE_SET_NAME));
}

/**
* @param project The project to look for yaml test sources.
* @return An Optional that contains the yaml test SourceSet if it exists.
*/
public static Optional<SourceSet> getYamlTestSourceSet(Project project) {
return project.getConvention().findPlugin(JavaPluginConvention.class) == null
? Optional.empty()
: Optional.ofNullable(GradleUtils.getJavaSourceSets(project).findByName("yamlTest"));
}

/**
* @param project The project to look for main Java resources.
* @return An Optional that contains the Java main SourceSet if it exists.
Expand Down
Loading