-
Notifications
You must be signed in to change notification settings - Fork 25.1k
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
RFC: Proposal to replace fixtures with docker-compose #35651
Changes from all commits
bbc57cc
268665a
4416463
0623db7
a232329
b8db838
1c009ca
7f52fe3
9bd8e55
df045ef
d18603d
1306d8f
4bc31ba
06f606b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* 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.testfixtures; | ||
|
||
import org.gradle.api.NamedDomainObjectContainer; | ||
import org.gradle.api.Project; | ||
|
||
public class TestFixtureExtension { | ||
|
||
private final Project project; | ||
final NamedDomainObjectContainer<Project> fixtures; | ||
|
||
public TestFixtureExtension(Project project) { | ||
this.project = project; | ||
this.fixtures = project.container(Project.class); | ||
} | ||
|
||
public void useFixture(String path) { | ||
Project fixtureProject = this.project.findProject(path); | ||
if (fixtureProject == null) { | ||
throw new IllegalArgumentException("Could not find test fixture " + fixtureProject); | ||
} | ||
if (fixtureProject.file(TestFixturesPlugin.DOCKER_COMPOSE_YML).exists() == false) { | ||
throw new IllegalArgumentException( | ||
"Project " + path + " is not a valid test fixture: missing " + TestFixturesPlugin.DOCKER_COMPOSE_YML | ||
); | ||
} | ||
fixtures.add(fixtureProject); | ||
} | ||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/* | ||
* 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.testfixtures; | ||
|
||
import com.avast.gradle.dockercompose.ComposeExtension; | ||
import com.avast.gradle.dockercompose.DockerComposePlugin; | ||
import org.elasticsearch.gradle.precommit.JarHellTask; | ||
import org.elasticsearch.gradle.precommit.ThirdPartyAuditTask; | ||
import org.gradle.api.DefaultTask; | ||
import org.gradle.api.Plugin; | ||
import org.gradle.api.Project; | ||
import org.gradle.api.Task; | ||
import org.gradle.api.plugins.BasePlugin; | ||
import org.gradle.api.tasks.TaskContainer; | ||
|
||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.util.Collections; | ||
|
||
public class TestFixturesPlugin implements Plugin<Project> { | ||
|
||
static final String DOCKER_COMPOSE_YML = "docker-compose.yml"; | ||
|
||
@Override | ||
public void apply(Project project) { | ||
TaskContainer tasks = project.getTasks(); | ||
|
||
TestFixtureExtension extension = project.getExtensions().create( | ||
"testFixtures", TestFixtureExtension.class, project | ||
); | ||
|
||
// Don't look for docker-compose on the PATH yet that would pick up on Windows as well | ||
if (project.file("/usr/local/bin/docker-compose").exists() == false && | ||
project.file("/usr/bin/docker-compose").exists() == false | ||
) { | ||
project.getLogger().warn( | ||
"Tests require docker-compose at /usr/local/bin/docker-compose or /usr/bin/docker-compose " + | ||
"but none could not be found so these will be skipped" | ||
); | ||
tasks.withType(getTaskClass("com.carrotsearch.gradle.junit4.RandomizedTestingTask"), task -> | ||
task.setEnabled(false) | ||
); | ||
return; | ||
} | ||
|
||
if (project.file(DOCKER_COMPOSE_YML).exists()) { | ||
project.apply(spec -> spec.plugin(BasePlugin.class)); | ||
project.apply(spec -> spec.plugin(DockerComposePlugin.class)); | ||
ComposeExtension composeExtension = project.getExtensions().getByType(ComposeExtension.class); | ||
composeExtension.setUseComposeFiles(Collections.singletonList(DOCKER_COMPOSE_YML)); | ||
composeExtension.setRemoveContainers(true); | ||
composeExtension.setExecutable( | ||
project.file("/usr/local/bin/docker-compose").exists() ? | ||
"/usr/local/bin/docker-compose" : "/usr/bin/docker-compose" | ||
); | ||
|
||
project.getTasks().getByName("clean").dependsOn("composeDown"); | ||
|
||
// convenience boilerplate with build plugin | ||
project.getPluginManager().withPlugin("elasticsearch.build", (appliedPlugin) -> { | ||
// Can't reference tasks that are implemented in Groovy, use reflection instead | ||
disableTaskByType(tasks, getTaskClass("org.elasticsearch.gradle.precommit.LicenseHeadersTask")); | ||
disableTaskByType(tasks, getTaskClass("com.carrotsearch.gradle.junit4.RandomizedTestingTask")); | ||
disableTaskByType(tasks, ThirdPartyAuditTask.class); | ||
disableTaskByType(tasks, JarHellTask.class); | ||
}); | ||
} else { | ||
tasks.withType(getTaskClass("com.carrotsearch.gradle.junit4.RandomizedTestingTask"), task -> | ||
extension.fixtures.all(fixtureProject -> { | ||
task.dependsOn(fixtureProject.getTasks().getByName("composeUp")); | ||
task.finalizedBy(fixtureProject.getTasks().getByName("composeDown")); | ||
// Configure ports for the tests as system properties. | ||
// We only know these at execution time so we need to do it in doFirst | ||
task.doFirst(it -> | ||
fixtureProject.getExtensions().getByType(ComposeExtension.class).getServicesInfos() | ||
.forEach((service, infos) -> | ||
infos.getPorts() | ||
.forEach((container, host) -> setSystemProperty( | ||
it, | ||
"test.fixtures." + fixtureProject.getName() + "." + service + "." + container, | ||
host | ||
)) | ||
)); | ||
})); | ||
} | ||
} | ||
|
||
private void setSystemProperty(Task task, String name, Object value) { | ||
try { | ||
Method systemProperty = task.getClass().getMethod("systemProperty", String.class, Object.class); | ||
systemProperty.invoke(task, name, value); | ||
} catch (NoSuchMethodException e) { | ||
throw new IllegalArgumentException("Could not find systemProperty method on RandomizedTestingTask", e); | ||
} catch (IllegalAccessException | InvocationTargetException e) { | ||
throw new IllegalArgumentException("Could not call systemProperty method on RandomizedTestingTask", e); | ||
} | ||
} | ||
|
||
private void disableTaskByType(TaskContainer tasks, Class<? extends Task> type) { | ||
tasks.withType(type, task -> task.setEnabled(false)); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private Class<? extends DefaultTask> getTaskClass(String type) { | ||
Class<?> aClass; | ||
try { | ||
aClass = Class.forName(type); | ||
if (DefaultTask.class.isAssignableFrom(aClass) == false) { | ||
throw new IllegalArgumentException("Not a task type: " + type); | ||
} | ||
} catch (ClassNotFoundException e) { | ||
throw new IllegalArgumentException("No such task: " + type); | ||
} | ||
return (Class<? extends DefaultTask>) aClass; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
implementation-class=org.elasticsearch.gradle.testfixtures.TestFixturesPlugin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
FROM ubuntu:16.04 | ||
RUN apt-get update -qqy && apt-get install -qqy samba ldap-utils | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have a strong opinion on that, and don't mind doing it in a follow up. |
||
ADD . /fixture | ||
RUN chmod +x /fixture/src/main/resources/provision/installsmb.sh | ||
RUN /fixture/src/main/resources/provision/installsmb.sh | ||
|
||
EXPOSE 389 | ||
EXPOSE 636 | ||
EXPOSE 3268 | ||
EXPOSE 3269 | ||
|
||
CMD service samba-ad-dc restart && sleep infinity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe name them rather than use the original port number? As much as I love port numbers I think it'd be nicer to call them
LDAP
andLDAP_GC
or something.