Skip to content

Commit

Permalink
Expose historical feature metadata to rest tests (#102110)
Browse files Browse the repository at this point in the history
This introduces a new getHistoricalFeatures() method on ESRestTestCase
which returns a map of historical feature version mappings loaded from
FeatureSpecification implementations from any plugins/modules in use
by the current test suite. The mappings are generated by a new Gradle
task at build time, and then injected into the test runtime as a
System property.
  • Loading branch information
mark-vieira committed Nov 14, 2023
1 parent f12afe4 commit 5d37962
Show file tree
Hide file tree
Showing 13 changed files with 402 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Expand All @@ -58,11 +58,11 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
id 'java'
id 'elasticsearch.global-build-info'
}
apply plugin:'elasticsearch.build'
group = 'org.acme'
description = "some example project"
repositories {
maven {
name = "local-test"
Expand All @@ -73,7 +73,7 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
}
mavenCentral()
}
dependencies {
jarHell 'org.elasticsearch:elasticsearch-core:current'
}
Expand All @@ -89,7 +89,7 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
* Side Public License, v 1.
*/
package org.elasticsearch;
public class SampleClass {
}
""".stripIndent()
Expand Down Expand Up @@ -117,7 +117,7 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
noticeFile.set(file("NOTICE"))
"""
when:
def result = gradleRunner("assemble").build()
def result = gradleRunner("assemble", "-x", "generateHistoricalFeaturesMetadata").build()
then:
result.task(":assemble").outcome == TaskOutcome.SUCCESS
file("build/distributions/hello-world.jar").exists()
Expand Down Expand Up @@ -146,7 +146,7 @@ class BuildPluginFuncTest extends AbstractGradleFuncTest {
}
licenseFile.set(file("LICENSE"))
noticeFile.set(file("NOTICE"))
tasks.named("forbiddenApisMain").configure {enabled = false }
tasks.named('checkstyleMain').configure { enabled = false }
tasks.named('loggerUsageCheck').configure { enabled = false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
id 'elasticsearch.java'
id 'elasticsearch.publish'
}
version = "1.0"
group = 'org.acme'
description = "custom project description"
Expand Down Expand Up @@ -92,11 +92,11 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
id 'elasticsearch.publish'
id 'com.github.johnrengelman.shadow'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.slf4j:log4j-over-slf4j:1.7.30'
shadow 'org.slf4j:slf4j-api:1.7.30'
Expand All @@ -110,8 +110,8 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
}
}
version = "1.0"
group = 'org.acme'
description = 'some description'
group = 'org.acme'
description = 'some description'
"""

when:
Expand Down Expand Up @@ -179,7 +179,7 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
}
dependencies {
shadow project(":someLib")
shadow project(":someLib")
}
publishing {
repositories {
Expand All @@ -192,10 +192,10 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
allprojects {
apply plugin: 'elasticsearch.java'
version = "1.0"
group = 'org.acme'
group = 'org.acme'
}
description = 'some description'
description = 'some description'
"""

when:
Expand Down Expand Up @@ -263,31 +263,31 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
id 'elasticsearch.publish'
id 'com.github.johnrengelman.shadow'
}
esplugin {
name = 'hello-world-plugin'
classname 'org.acme.HelloWorldPlugin'
description = "custom project description"
}
publishing {
repositories {
maven {
url = "\$buildDir/repo"
}
}
}
// requires elasticsearch artifact available
tasks.named('bundlePlugin').configure { enabled = false }
licenseFile.set(file('license.txt'))
noticeFile.set(file('notice.txt'))
version = "1.0"
group = 'org.acme'
group = 'org.acme'
"""

when:
def result = gradleRunner('assemble', '--stacktrace').build()
def result = gradleRunner('assemble', '--stacktrace', '-x', 'generateHistoricalFeaturesMetadata').build()

then:
result.task(":generatePom").outcome == TaskOutcome.SUCCESS
Expand Down Expand Up @@ -348,19 +348,19 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
id 'elasticsearch.internal-es-plugin'
id 'elasticsearch.publish'
}
esplugin {
name = 'hello-world-plugin'
classname 'org.acme.HelloWorldPlugin'
description = "custom project description"
}
// requires elasticsearch artifact available
tasks.named('bundlePlugin').configure { enabled = false }
licenseFile.set(file('license.txt'))
noticeFile.set(file('notice.txt'))
version = "2.0"
group = 'org.acme'
group = 'org.acme'
"""

when:
Expand Down Expand Up @@ -420,9 +420,9 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
apply plugin:'elasticsearch.publish'
version = "1.0"
group = 'org.acme'
group = 'org.acme'
description = "just a test project"
ext.projectLicenses.set(['The Apache Software License, Version 2.0': 'http://www.apache.org/licenses/LICENSE-2.0'])
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.elasticsearch.gradle.internal.conventions.util.Util;
import org.elasticsearch.gradle.internal.info.BuildParams;
import org.elasticsearch.gradle.internal.precommit.JarHellPrecommitPlugin;
import org.elasticsearch.gradle.internal.test.HistoricalFeaturesMetadataPlugin;
import org.elasticsearch.gradle.plugin.PluginBuildPlugin;
import org.elasticsearch.gradle.plugin.PluginPropertiesExtension;
import org.elasticsearch.gradle.testclusters.ElasticsearchCluster;
Expand All @@ -36,6 +37,7 @@ public void apply(Project project) {
project.getPluginManager().apply(PluginBuildPlugin.class);
project.getPluginManager().apply(JarHellPrecommitPlugin.class);
project.getPluginManager().apply(ElasticsearchJavaPlugin.class);
project.getPluginManager().apply(HistoricalFeaturesMetadataPlugin.class);
// Clear default dependencies added by public PluginBuildPlugin as we add our
// own project dependencies for internal builds
// TODO remove once we removed default dependencies from PluginBuildPlugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.elasticsearch.gradle.internal.info.GlobalBuildInfoPlugin;
import org.elasticsearch.gradle.internal.precommit.InternalPrecommitTasks;
import org.elasticsearch.gradle.internal.snyk.SnykDependencyMonitoringGradlePlugin;
import org.elasticsearch.gradle.internal.test.HistoricalFeaturesMetadataPlugin;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
Expand Down Expand Up @@ -61,6 +62,7 @@ public void apply(final Project project) {
project.getPluginManager().apply(ElasticsearchJavadocPlugin.class);
project.getPluginManager().apply(DependenciesInfoPlugin.class);
project.getPluginManager().apply(SnykDependencyMonitoringGradlePlugin.class);
project.getPluginManager().apply(HistoricalFeaturesMetadataPlugin.class);
InternalPrecommitTasks.create(project, true);
configureLicenseAndNotice(project);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

package org.elasticsearch.gradle.internal.test;

import org.elasticsearch.gradle.dependencies.CompileOnlyResolvePlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.type.ArtifactTypeDefinition;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskProvider;

import java.util.Map;

/**
* Extracts historical feature metadata into a machine-readable format for use in backward compatibility testing.
*/
public class HistoricalFeaturesMetadataPlugin implements Plugin<Project> {
public static final String HISTORICAL_FEATURES_JSON = "historical-features.json";
public static final String FEATURES_METADATA_TYPE = "features-metadata-json";
public static final String FEATURES_METADATA_CONFIGURATION = "featuresMetadata";

@Override
public void apply(Project project) {
Configuration featureMetadataExtractorConfig = project.getConfigurations().create("featuresMetadataExtractor", c -> {
// Don't bother adding this dependency if the project doesn't exist which simplifies testing
if (project.findProject(":test:metadata-extractor") != null) {
c.defaultDependencies(d -> d.add(project.getDependencies().project(Map.of("path", ":test:metadata-extractor"))));
}
});

SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);

TaskProvider<HistoricalFeaturesMetadataTask> generateTask = project.getTasks()
.register("generateHistoricalFeaturesMetadata", HistoricalFeaturesMetadataTask.class, task -> {
task.setClasspath(
featureMetadataExtractorConfig.plus(mainSourceSet.getRuntimeClasspath())
.plus(project.getConfigurations().getByName(CompileOnlyResolvePlugin.RESOLVEABLE_COMPILE_ONLY_CONFIGURATION_NAME))
);
task.getOutputFile().convention(project.getLayout().getBuildDirectory().file(HISTORICAL_FEATURES_JSON));
});

Configuration featuresMetadataArtifactConfig = project.getConfigurations().create(FEATURES_METADATA_CONFIGURATION, c -> {
c.setCanBeResolved(false);
c.setCanBeConsumed(true);
c.attributes(a -> { a.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, FEATURES_METADATA_TYPE); });
});

project.getArtifacts().add(featuresMetadataArtifactConfig.getName(), generateTask);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

package org.elasticsearch.gradle.internal.test;

import org.elasticsearch.gradle.LoggedExec;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.gradle.process.ExecOperations;
import org.gradle.workers.WorkAction;
import org.gradle.workers.WorkParameters;
import org.gradle.workers.WorkerExecutor;

import javax.inject.Inject;

@CacheableTask
public abstract class HistoricalFeaturesMetadataTask extends DefaultTask {
private FileCollection classpath;

@OutputFile
public abstract RegularFileProperty getOutputFile();

@Classpath
public FileCollection getClasspath() {
return classpath;
}

public void setClasspath(FileCollection classpath) {
this.classpath = classpath;
}

@Inject
public abstract WorkerExecutor getWorkerExecutor();

@TaskAction
public void execute() {
getWorkerExecutor().noIsolation().submit(HistoricalFeaturesMetadataWorkAction.class, params -> {
params.getClasspath().setFrom(getClasspath());
params.getOutputFile().set(getOutputFile());
});
}

public interface HistoricalFeaturesWorkParameters extends WorkParameters {
ConfigurableFileCollection getClasspath();

RegularFileProperty getOutputFile();
}

public abstract static class HistoricalFeaturesMetadataWorkAction implements WorkAction<HistoricalFeaturesWorkParameters> {
private final ExecOperations execOperations;

@Inject
public HistoricalFeaturesMetadataWorkAction(ExecOperations execOperations) {
this.execOperations = execOperations;
}

@Override
public void execute() {
LoggedExec.javaexec(execOperations, spec -> {
spec.getMainClass().set("org.elasticsearch.extractor.features.HistoricalFeaturesMetadataExtractor");
spec.classpath(getParameters().getClasspath());
spec.args(getParameters().getOutputFile().get().getAsFile().getAbsolutePath());
});
}
}
}

0 comments on commit 5d37962

Please sign in to comment.