diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixtureExtension.java b/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixtureExtension.java index b4ddcf0bed183..1521b7971333b 100644 --- a/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixtureExtension.java +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixtureExtension.java @@ -18,20 +18,65 @@ */ package org.elasticsearch.gradle.testfixtures; +import org.gradle.api.GradleException; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.Project; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + public class TestFixtureExtension { private final Project project; final NamedDomainObjectContainer fixtures; + final Map serviceToProjectUseMap = new HashMap<>(); public TestFixtureExtension(Project project) { this.project = project; this.fixtures = project.container(Project.class); } + public void useFixture() { + useFixture(this.project.getPath()); + } + public void useFixture(String path) { + addFixtureProject(path); + serviceToProjectUseMap.put(path, this.project.getPath()); + } + + public void useFixture(String path, String serviceName) { + addFixtureProject(path); + String key = getServiceNameKey(path, serviceName); + serviceToProjectUseMap.put(key, this.project.getPath()); + + Optional otherProject = this.findOtherProjectUsingService(key); + if (otherProject.isPresent()) { + throw new GradleException( + "Projects " + otherProject.get() + " and " + this.project.getPath() + " both claim the "+ serviceName + + " service defined in the docker-compose.yml of " + path + "This is not supported because it breaks " + + "running in parallel. Configure dedicated services for each project and use those instead." + ); + } + } + + private String getServiceNameKey(String fixtureProjectPath, String serviceName) { + return fixtureProjectPath + "::" + serviceName; + } + + private Optional findOtherProjectUsingService(String serviceName) { + return this.project.getRootProject().getAllprojects().stream() + .filter(p -> p.equals(this.project) == false) + .filter(p -> p.getExtensions().findByType(TestFixtureExtension.class) != null) + .map(project -> project.getExtensions().getByType(TestFixtureExtension.class)) + .flatMap(ext -> ext.serviceToProjectUseMap.entrySet().stream()) + .filter(entry -> entry.getKey().equals(serviceName)) + .map(Map.Entry::getValue) + .findAny(); + } + + private void addFixtureProject(String path) { Project fixtureProject = this.project.findProject(path); if (fixtureProject == null) { throw new IllegalArgumentException("Could not find test fixture " + fixtureProject); @@ -42,6 +87,20 @@ public void useFixture(String path) { ); } fixtures.add(fixtureProject); + // Check for exclusive access + Optional otherProject = this.findOtherProjectUsingService(path); + if (otherProject.isPresent()) { + throw new GradleException("Projects " + otherProject.get() + " and " + this.project.getPath() + " both " + + "claim all services from " + path + ". This is not supported because it breaks running in parallel. " + + "Configure specific services in docker-compose.yml for each and add the service name to `useFixture`" + ); + } } + boolean isServiceRequired(String serviceName, String fixtureProject) { + if (serviceToProjectUseMap.containsKey(fixtureProject)) { + return true; + } + return serviceToProjectUseMap.containsKey(getServiceNameKey(fixtureProject, serviceName)); + } } diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixturesPlugin.java b/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixturesPlugin.java index 556e938875e26..93c91cbee51d3 100644 --- a/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixturesPlugin.java +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/testfixtures/TestFixturesPlugin.java @@ -20,6 +20,7 @@ import com.avast.gradle.dockercompose.ComposeExtension; import com.avast.gradle.dockercompose.DockerComposePlugin; +import com.avast.gradle.dockercompose.ServiceInfo; import com.avast.gradle.dockercompose.tasks.ComposeUp; import org.elasticsearch.gradle.OS; import org.elasticsearch.gradle.SystemPropertyCommandLineArgumentProvider; @@ -58,9 +59,6 @@ public void apply(Project project) { ext.set("testFixturesDir", testfixturesDir); if (project.file(DOCKER_COMPOSE_YML).exists()) { - // the project that defined a test fixture can also use it - extension.fixtures.add(project); - Task buildFixture = project.getTasks().create("buildFixture"); Task pullFixture = project.getTasks().create("pullFixture"); Task preProcessFixture = project.getTasks().create("preProcessFixture"); @@ -106,6 +104,7 @@ public void apply(Project project) { configureServiceInfoForTask( postProcessFixture, project, + false, (name, port) -> postProcessFixture.getExtensions() .getByType(ExtraPropertiesExtension.class).set(name, port) ); @@ -144,6 +143,7 @@ public void apply(Project project) { configureServiceInfoForTask( task, fixtureProject, + true, (name, host) -> task.getExtensions().getByType(SystemPropertyCommandLineArgumentProvider.class).systemProperty(name, host) ); @@ -165,14 +165,23 @@ private void conditionTaskByType(TaskContainer tasks, TestFixtureExtension exten ); } - private void configureServiceInfoForTask(Task task, Project fixtureProject, BiConsumer consumer) { + private void configureServiceInfoForTask( + Task task, Project fixtureProject, boolean enableFilter, BiConsumer consumer + ) { // Configure ports for the tests as system properties. // We only know these at execution time so we need to do it in doFirst + TestFixtureExtension extension = task.getProject().getExtensions().getByType(TestFixtureExtension.class); task.doFirst(new Action() { @Override public void execute(Task theTask) { fixtureProject.getExtensions().getByType(ComposeExtension.class).getServicesInfos() - .forEach((service, infos) -> { + .entrySet().stream() + .filter(entry -> enableFilter == false || + extension.isServiceRequired(entry.getKey(), fixtureProject.getPath()) + ) + .forEach(entry -> { + String service = entry.getKey(); + ServiceInfo infos = entry.getValue(); infos.getTcpPorts() .forEach((container, host) -> { String name = "test.fixtures." + service + ".tcp." + container; diff --git a/distribution/docker/build.gradle b/distribution/docker/build.gradle index 7bf973e7edc92..e4f0a04d4e9df 100644 --- a/distribution/docker/build.gradle +++ b/distribution/docker/build.gradle @@ -6,6 +6,8 @@ import org.elasticsearch.gradle.testfixtures.TestFixturesPlugin apply plugin: 'elasticsearch.standalone-rest-test' apply plugin: 'elasticsearch.test.fixtures' +testFixtures.useFixture() + configurations { dockerPlugins dockerSource diff --git a/plugins/repository-hdfs/build.gradle b/plugins/repository-hdfs/build.gradle index 43b58ea7f39ab..7d849856aa8af 100644 --- a/plugins/repository-hdfs/build.gradle +++ b/plugins/repository-hdfs/build.gradle @@ -37,7 +37,7 @@ versions << [ 'hadoop2': '2.8.1' ] -testFixtures.useFixture ":test:fixtures:krb5kdc-fixture" +testFixtures.useFixture ":test:fixtures:krb5kdc-fixture", "hdfs" configurations { hdfsFixture diff --git a/plugins/repository-s3/build.gradle b/plugins/repository-s3/build.gradle index 99eb86a4e00b9..ab4597cf7f413 100644 --- a/plugins/repository-s3/build.gradle +++ b/plugins/repository-s3/build.gradle @@ -146,6 +146,9 @@ task thirdPartyTest(type: Test) { if (useFixture) { apply plugin: 'elasticsearch.test.fixtures' + + testFixtures.useFixture() + task writeDockerFile { File minioDockerfile = new File("${project.buildDir}/minio-docker/Dockerfile") outputs.file(minioDockerfile) diff --git a/x-pack/qa/kerberos-tests/build.gradle b/x-pack/qa/kerberos-tests/build.gradle index 81e5d746cc767..3b6530a69d8f1 100644 --- a/x-pack/qa/kerberos-tests/build.gradle +++ b/x-pack/qa/kerberos-tests/build.gradle @@ -1,13 +1,12 @@ import java.nio.file.Path import java.nio.file.Paths -import java.nio.file.Files apply plugin: 'elasticsearch.testclusters' apply plugin: 'elasticsearch.standalone-rest-test' apply plugin: 'elasticsearch.rest-test' apply plugin: 'elasticsearch.test.fixtures' -testFixtures.useFixture ":test:fixtures:krb5kdc-fixture" +testFixtures.useFixture ":test:fixtures:krb5kdc-fixture", "peppa" dependencies { testCompile project(':x-pack:plugin:core') diff --git a/x-pack/qa/oidc-op-tests/build.gradle b/x-pack/qa/oidc-op-tests/build.gradle index 9328447597e49..13f2ef4927d1e 100644 --- a/x-pack/qa/oidc-op-tests/build.gradle +++ b/x-pack/qa/oidc-op-tests/build.gradle @@ -10,7 +10,7 @@ dependencies { testCompile project(path: xpackModule('core'), configuration: 'testArtifacts') testCompile project(path: xpackModule('security'), configuration: 'testArtifacts') } -testFixtures.useFixture ":x-pack:test:idp-fixture" +testFixtures.useFixture ":x-pack:test:idp-fixture", "oidc-provider" String ephemeralPort; task setupPorts { diff --git a/x-pack/qa/openldap-tests/build.gradle b/x-pack/qa/openldap-tests/build.gradle index 9fc5a9b3b31a8..805023b54136a 100644 --- a/x-pack/qa/openldap-tests/build.gradle +++ b/x-pack/qa/openldap-tests/build.gradle @@ -7,7 +7,7 @@ dependencies { testCompile project(path: xpackModule('core'), configuration: 'testArtifacts') } -testFixtures.useFixture ":x-pack:test:idp-fixture" +testFixtures.useFixture ":x-pack:test:idp-fixture", "openldap" Project idpFixtureProject = xpackProject("test:idp-fixture") String outputDir = "${project.buildDir}/generated-resources/${project.name}" diff --git a/x-pack/qa/third-party/active-directory/build.gradle b/x-pack/qa/third-party/active-directory/build.gradle index 2d4af2b46bbc0..b76b25b08eae6 100644 --- a/x-pack/qa/third-party/active-directory/build.gradle +++ b/x-pack/qa/third-party/active-directory/build.gradle @@ -15,7 +15,7 @@ processTestResources { compileTestJava.options.compilerArgs << "-Xlint:-rawtypes,-unchecked" -// we have to repeat these patterns because the security test resources are effectively in the src of this project +// we have to repeat these patterns because the security test resources are effectively in the src of this p forbiddenPatterns { exclude '**/*.key' exclude '**/*.p12'