Skip to content

Commit

Permalink
Convert Wildfly tests to run in Docker (#53126)
Browse files Browse the repository at this point in the history
Closes #49374.

Convert the Wildfly tests to run using Docker Compose. This drastically simplifies the build setup, and will hopefully make the tests more resilient.
  • Loading branch information
pugnascotia committed Mar 4, 2020
1 parent 883104f commit 38ecfab
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 228 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ subprojects {
':distribution:tools:launchers',
':distribution:tools:plugin-cli',
':qa:os',
':qa:wildfly',
':x-pack:plugin:autoscaling',
':x-pack:plugin:enrich'
]
Expand Down
199 changes: 25 additions & 174 deletions qa/wildfly/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
import org.elasticsearch.gradle.LoggedExec
import org.elasticsearch.gradle.VersionProperties
import org.apache.tools.ant.taskdefs.condition.Os
import org.elasticsearch.gradle.testclusters.DefaultTestClustersTask

import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.util.stream.Stream

/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
Expand All @@ -26,33 +17,14 @@ import java.util.stream.Stream
* under the License.
*/

import org.elasticsearch.gradle.VersionProperties

apply plugin: 'war'
apply plugin: 'elasticsearch.testclusters'
apply plugin: 'elasticsearch.build'
apply plugin: 'elasticsearch.rest-test'
apply plugin: 'elasticsearch.test.fixtures'
apply plugin: 'elasticsearch.distribution-download'

final String wildflyVersion = '11.0.0.Final'
final String wildflyDir = "${buildDir}/wildfly"
final String wildflyInstall = "${buildDir}/wildfly/wildfly-${wildflyVersion}"
int managementPort

repositories {
// the Wildfly distribution is not available via a repository, so we fake an Ivy repository on top of the download site
ivy {
name "wildfly"
url "https://download.jboss.org"
metadataSources {
artifact()
}
patternLayout {
artifact 'wildfly/[revision]/[module]-[revision].[ext]'
}
}
}

configurations {
wildfly
}
testFixtures.useFixture()

dependencies {
providedCompile 'javax.enterprise:cdi-api:1.2'
Expand All @@ -73,162 +45,41 @@ dependencies {
compile "org.apache.logging.log4j:log4j-api:${versions.log4j}"
compile "org.apache.logging.log4j:log4j-core:${versions.log4j}"
compile project(path: ':client:rest-high-level', configuration: 'shadow')
wildfly "org.jboss:wildfly:${wildflyVersion}@zip"
testCompile project(':test:framework')
}

task unzipWildfly(type: Sync) {
into wildflyDir
from { zipTree(configurations.wildfly.singleFile) }
war {
archiveName 'example-app.war'
}

task deploy(type: Copy) {
dependsOn unzipWildfly, war
from war
into "${wildflyInstall}/standalone/deployments"
}

task writeElasticsearchProperties(type: DefaultTestClustersTask) {
onlyIf { !Os.isFamily(Os.FAMILY_WINDOWS) }
useCluster testClusters.integTest
dependsOn deploy
doLast {
final File elasticsearchProperties = file("${wildflyInstall}/standalone/configuration/elasticsearch.properties")
elasticsearchProperties.write(
[
"http.uri=${-> testClusters.integTest.getAllHttpSocketURI().get(0)}"
].join("\n"))
elasticsearch_distributions {
docker {
type = 'docker'
flavor = System.getProperty('tests.distribution', 'default')
version = VersionProperties.getElasticsearch()
failIfUnavailable = false // This ensures we skip this testing if Docker is unavailable
}
}

// the default configuration ships with IPv6 disabled but our cluster could be bound to IPv6 if the host supports it
task enableIPv6 {
dependsOn unzipWildfly
doLast {
final File standaloneConf = file("${wildflyInstall}/bin/standalone.conf")
final List<String> lines =
Files.readAllLines(standaloneConf.toPath())
.collect { line -> line.replace("-Djava.net.preferIPv4Stack=true", "-Djava.net.preferIPv4Stack=false") }
standaloneConf.write(lines.join("\n"))
}
preProcessFixture {
dependsOn war, elasticsearch_distributions.docker
}

task startWildfly {
dependsOn enableIPv6, writeElasticsearchProperties
doLast {
// we skip these tests on Windows so we do no need to worry about compatibility here
final ProcessBuilder wildfly = new ProcessBuilder(
"${wildflyInstall}/bin/standalone.sh",
"-Djboss.http.port=0",
"-Djboss.https.port=0",
"-Djboss.management.http.port=0")
final Process process = wildfly.start()
new BufferedReader(new InputStreamReader(process.getInputStream())).withReader { br ->
String line
int httpPort = 0
while ((line = br.readLine()) != null) {
logger.info(line)
if (line.matches('.*Undertow HTTP listener default listening on .*:\\d+$')) {
assert httpPort == 0
final int index = line.lastIndexOf(":")
assert index >= 0
httpPort = Integer.parseInt(line.substring(index + 1))
// set this system property so the test runner knows the port Wildfly is listening for HTTP requests on
integTestRunner.systemProperty("tests.jboss.root", "http://localhost:$httpPort/wildfly-$version/transport")
} else if (line.matches('.*Http management interface listening on http://.*:\\d+/management$')) {
assert managementPort == 0
final int colonIndex = line.lastIndexOf(":")
assert colonIndex >= 0
final int slashIndex = line.lastIndexOf("/")
assert slashIndex >= 0
managementPort = Integer.parseInt(line.substring(colonIndex + 1, slashIndex))

/*
* As soon as we know the management port, we fork a process that will ensure the Wildfly process is killed if we
* teardown abnormally. We skip these tests on Windows so we do not need to worry about CLI compatibility here.
*/
final File script = new File(project.buildDir, "wildfly/wildfly.killer.sh")
script.setText(
["function shutdown {",
" ${wildflyInstall}/bin/jboss-cli.sh --controller=localhost:${-> managementPort} --connect command=shutdown",
"}",
"trap shutdown EXIT",
// will wait indefinitely for input, but we never pass input, and the pipe is only closed when the build dies
"read line\n"].join('\n'), 'UTF-8')
final ProcessBuilder killer = new ProcessBuilder("bash", script.absolutePath)
killer.start()

} else if (line.matches(".*WildFly Full \\d+\\.\\d+\\.\\d+\\.Final \\(WildFly Core \\d+\\.\\d+\\.\\d+\\.Final\\) started.*")) {
break
}
}

if (httpPort == 0 || managementPort == 0) {
String portType = httpPort == 0 ? "http" : "management"
throw new GradleException("Failed to find ${portType} port in wildfly log")
}
}
dockerCompose {
if ('default'.equalsIgnoreCase(System.getProperty('tests.distribution', 'default'))) {
useComposeFiles = ['docker-compose.yml']
} else {
useComposeFiles = ['docker-compose-oss.yml']
}
}

task configureClient(type: LoggedExec) {
dependsOn startWildfly
// we skip these tests on Windows so we do not need to worry about compatibility here
commandLine "${wildflyInstall}/bin/jboss-cli.sh",
"--controller=localhost:${-> managementPort}",
"--connect",
"--command=/system-property=elasticsearch.properties:add(value=\${jboss.server.config.dir}/elasticsearch.properties)"
}

task stopWildfly(type: LoggedExec) {
// we skip these tests on Windows so we do not need to worry about CLI compatibility here
commandLine "${wildflyInstall}/bin/jboss-cli.sh", "--controller=localhost:${-> managementPort}", "--connect", "command=shutdown"
}

if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
integTestRunner.dependsOn(configureClient)
final TaskExecutionAdapter logDumpListener = new TaskExecutionAdapter() {
@Override
void afterExecute(final Task task, final TaskState state) {
if (task != startWildfly && task != integTestRunner) {
// we might have been called from a parallel, unrelated task
return
}
if (state.failure != null) {
final File logFile = new File(wildflyInstall, "standalone/log/server.log")
println("\nWildfly server log (from ${logFile}):")
println('-----------------------------------------')
final Stream<String> stream = Files.lines(logFile.toPath(), StandardCharsets.UTF_8)
try {
for (String line : stream) {
println(line)
}
} finally {
stream.close()
}
println('=========================================')
}
}
}
startWildfly.doFirst {
project.gradle.addListener(logDumpListener)
}
integTestRunner.doFirst {
project.gradle.addListener(logDumpListener)
}
integTestRunner.doLast {
project.gradle.removeListener(logDumpListener)
}
startWildfly.doLast {
project.gradle.removeListener(logDumpListener)
}
integTestRunner.finalizedBy(stopWildfly)
} else {
integTest.enabled = false
testingConventions.enabled = false
task integTest(type: Test) {
outputs.doNotCacheIf('Build cache is disabled for Docker tests') { true }
maxParallelForks = '1'
include '**/*IT.class'
}

check.dependsOn(integTest)
check.dependsOn integTest

test.enabled = false

Expand Down
35 changes: 35 additions & 0 deletions qa/wildfly/docker-compose-oss.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
version: '3.7'
services:

wildfly:
image: jboss/wildfly:18.0.1.Final
environment:
JAVA_OPTS: -Delasticsearch.uri=elasticsearch:9200 -Djboss.http.port=8080 -Djava.net.preferIPv4Stack=true
volumes:
- ./build/distributions/example-app.war:/opt/jboss/wildfly/standalone/deployments/example-app.war
ports:
- "8080"
healthcheck:
start_period: 5s
test: ["CMD", "grep", "Admin console listening on", "/opt/jboss/wildfly/standalone/log/server.log"]
interval: 2s
timeout: 1s
retries: 5

elasticsearch:
image: elasticsearch-oss:test
environment:
discovery.type: single-node
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
healthcheck:
start_period: 15s
test: ["CMD", "curl", "-f", "-k", "http://localhost:9200"]
interval: 10s
timeout: 2s
retries: 5
35 changes: 35 additions & 0 deletions qa/wildfly/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
version: '3.7'
services:

wildfly:
image: jboss/wildfly:18.0.1.Final
environment:
JAVA_OPTS: -Delasticsearch.uri=elasticsearch:9200 -Djboss.http.port=8080 -Djava.net.preferIPv4Stack=true
volumes:
- ./build/distributions/example-app.war:/opt/jboss/wildfly/standalone/deployments/example-app.war
ports:
- "8080"
healthcheck:
start_period: 5s
test: ["CMD", "grep", "Admin console listening on", "/opt/jboss/wildfly/standalone/log/server.log"]
interval: 2s
timeout: 1s
retries: 5

elasticsearch:
image: elasticsearch:test
environment:
discovery.type: single-node
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
healthcheck:
start_period: 15s
test: ["CMD", "curl", "-f", "-k", "http://localhost:9200"]
interval: 10s
timeout: 2s
retries: 5
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public Response getEmployeeById(final @PathParam("id") Long id) throws IOExcepti
employee.setLastName((String) source.get("last_name"));
employee.setAge((Integer) source.get("age"));
employee.setAbout((String) source.get("about"));
@SuppressWarnings("unchecked") final List<String> interests = (List<String>) source.get("interests");
@SuppressWarnings("unchecked")
final List<String> interests = (List<String>) source.get("interests");
employee.setInterests(interests);
return Response.ok(employee).build();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,14 @@
import org.elasticsearch.common.io.PathUtils;

import javax.enterprise.inject.Produces;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;

@SuppressWarnings("unused")
public final class RestHighLevelClientProducer {

@Produces
public RestHighLevelClient createRestHighLevelClient() throws IOException {
final String elasticsearchProperties = System.getProperty("elasticsearch.properties");
final Properties properties = new Properties();

final String httpUri;
try (InputStream is = Files.newInputStream(getPath(elasticsearchProperties))) {
properties.load(is);
httpUri = properties.getProperty("http.uri");
}
public RestHighLevelClient createRestHighLevelClient() {
String httpUri = System.getProperty("elasticsearch.uri");

return new RestHighLevelClient(RestClient.builder(HttpHost.create(httpUri)));
}
Expand All @@ -53,5 +42,4 @@ public RestHighLevelClient createRestHighLevelClient() throws IOException {
private Path getPath(final String elasticsearchProperties) {
return PathUtils.get(elasticsearchProperties);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@

@Provider
public class RestHighLevelJacksonJsonProvider extends ResteasyJackson2Provider {

}

0 comments on commit 38ecfab

Please sign in to comment.