Use TestFixturesPlugin to Run Minio in Tests (#37852)

* Use TestFixturesPlugin to Run Minio in Tests

* Closes #37680
* Closes #37783
This commit is contained in:
Armin Braun 2019-01-25 12:56:40 +01:00 committed by GitHub
parent a3baa8f5ef
commit be6bdab346
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 182 deletions

View File

@ -1,13 +1,10 @@
import org.apache.tools.ant.taskdefs.condition.Os import org.elasticsearch.gradle.BuildPlugin
import org.elasticsearch.gradle.LoggedExec
import org.elasticsearch.gradle.MavenFilteringHack import org.elasticsearch.gradle.MavenFilteringHack
import org.elasticsearch.gradle.test.AntFixture import org.elasticsearch.gradle.test.AntFixture
import org.elasticsearch.gradle.test.ClusterConfiguration import org.elasticsearch.gradle.test.ClusterConfiguration
import org.elasticsearch.gradle.test.RestIntegTestTask import org.elasticsearch.gradle.test.RestIntegTestTask
import com.carrotsearch.gradle.junit4.RandomizedTestingTask import com.carrotsearch.gradle.junit4.RandomizedTestingTask
import java.lang.reflect.Field
/* /*
* Licensed to Elasticsearch under one or more contributor * Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with * license agreements. See the NOTICE file distributed with
@ -139,25 +136,6 @@ if (!s3EC2Bucket && !s3EC2BasePath && !s3ECSBucket && !s3ECSBasePath) {
throw new IllegalArgumentException("not all options specified to run EC2/ECS tests are present") throw new IllegalArgumentException("not all options specified to run EC2/ECS tests are present")
} }
final String minioVersion = 'RELEASE.2018-06-22T23-48-46Z'
final String minioBinDir = "${buildDir}/minio/bin"
final String minioDataDir = "${buildDir}/minio/data"
final String minioAddress = "127.0.0.1"
String minioDistribution
String minioCheckSum
if (Os.isFamily(Os.FAMILY_MAC)) {
minioDistribution = 'darwin-amd64'
minioCheckSum = '96b0bcb2f590e8e65fb83d5c3e221f9bd1106b49fa6f22c6b726b80b845d7c60'
} else if (Os.isFamily(Os.FAMILY_UNIX)) {
minioDistribution = 'linux-amd64'
minioCheckSum = '713dac7c105285eab3b92649be92b5e793b29d3525c7929fa7aaed99374fad99'
} else {
minioDistribution = null
minioCheckSum = null
}
buildscript { buildscript {
repositories { repositories {
maven { maven {
@ -169,177 +147,39 @@ buildscript {
} }
} }
private static int freePort(String minioAddress) { if (useFixture) {
int minioPort
ServerSocket serverSocket = new ServerSocket(0, 1, InetAddress.getByName(minioAddress))
try {
minioPort = serverSocket.localPort
} finally {
serverSocket.close()
}
if (minioPort == 0) {
throw new GradleException("Could not find a free port for Minio")
}
return minioPort
}
private int getMinioPid(Process minioProcess) { apply plugin: 'elasticsearch.test.fixtures'
int minioPid
if (JavaVersion.current() <= JavaVersion.VERSION_1_8) {
try {
Class<?> cProcessImpl = minioProcess.getClass()
Field fPid = cProcessImpl.getDeclaredField("pid")
if (!fPid.isAccessible()) {
fPid.setAccessible(true)
}
minioPid = fPid.getInt(minioProcess)
} catch (Exception e) {
logger.error("failed to read pid from minio process", e)
minioProcess.destroyForcibly()
throw e
}
} else {
minioPid = minioProcess.pid()
}
return minioPid
}
private static Process setupMinio(String minioAddress, int minioPort, String minioDataDir, String accessKey, String secretKey,
String minioBinDir, String minioFileName) {
// we skip these tests on Windows so we do no need to worry about compatibility here
final ProcessBuilder minio = new ProcessBuilder(
"${minioBinDir}/${minioFileName}",
"server",
"--address",
minioAddress + ":" + minioPort,
minioDataDir)
minio.environment().put('MINIO_ACCESS_KEY', accessKey)
minio.environment().put('MINIO_SECRET_KEY', secretKey)
return minio.start()
}
private void addShutdownHook(Process minioProcess, int minioPort, int minioPid) {
new BufferedReader(new InputStreamReader(minioProcess.inputStream)).withReader { br ->
String line
int httpPort = 0
while ((line = br.readLine()) != null) {
logger.info(line)
if (line.matches('.*Endpoint.*:\\d+$')) {
assert httpPort == 0
final int index = line.lastIndexOf(":")
assert index >= 0
httpPort = Integer.parseInt(line.substring(index + 1))
if (httpPort != minioPort) {
throw new IllegalStateException("Port mismatch, expected ${minioPort} but was ${httpPort}")
}
final File script = new File(project.buildDir, "minio/minio.killer.sh")
script.setText(
["function shutdown {",
" kill ${minioPid}",
"}",
"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()
break
}
}
if (httpPort <= 0) {
throw new IllegalStateException("httpPort must be > 0")
}
}
}
if (useFixture && minioDistribution) {
apply plugin: 'de.undercouch.download'
final String minioFileName = "minio.${minioVersion}"
final String minioDownloadURL = "https://dl.minio.io/server/minio/release/${minioDistribution}/archive/${minioFileName}"
final String minioFilePath = "${gradle.gradleUserHomeDir}/downloads/minio/${minioDistribution}/${minioFileName}"
task downloadMinio(type: Download) {
src minioDownloadURL
dest minioFilePath
onlyIfModified true
}
task verifyMinioChecksum(type: Verify, dependsOn: downloadMinio) {
src minioFilePath
algorithm 'SHA-256'
checksum minioCheckSum
}
task installMinio(type: Sync, dependsOn: verifyMinioChecksum) {
from minioFilePath
into minioBinDir
fileMode 0755
}
task startMinio {
dependsOn installMinio
ext.minioPid = 0L
ext.minioPort = 0
doLast {
new File("${minioDataDir}/${s3PermanentBucket}").mkdirs()
Exception accumulatedException = null
for (int i = 0; i < 5; ++i) {
try {
minioPort = freePort(minioAddress)
final Process process =
setupMinio(minioAddress, minioPort, minioDataDir, s3PermanentAccessKey, s3PermanentSecretKey, minioBinDir, minioFileName)
minioPid = getMinioPid(process)
addShutdownHook(process, minioPort, minioPid)
break
} catch (Exception e) {
logger.error("Exception while trying to start Minio {}", e)
if (accumulatedException == null) {
accumulated = e
} else {
accumulatedException.addSuppressed(e)
}
}
}
if (accumulatedException != null) {
throw new GradleException("Failed to start Minio", accumulatedException)
}
}
}
task stopMinio(type: LoggedExec) {
onlyIf { startMinio.minioPid > 0 }
doFirst {
logger.info("Shutting down minio with pid ${startMinio.minioPid}")
}
final Object pid = "${ -> startMinio.minioPid }"
// we skip these tests on Windows so we do no need to worry about compatibility here
executable = 'kill'
args('-9', pid)
}
RestIntegTestTask integTestMinio = project.tasks.create('integTestMinio', RestIntegTestTask.class) { RestIntegTestTask integTestMinio = project.tasks.create('integTestMinio', RestIntegTestTask.class) {
description = "Runs REST tests using the Minio repository." description = "Runs REST tests using the Minio repository."
} }
Task writeDockerFile = project.tasks.create('writeDockerFile') {
File minioDockerfile = new File("${project.buildDir}/minio-docker/Dockerfile")
outputs.file(minioDockerfile)
doLast {
minioDockerfile.parentFile.mkdirs()
minioDockerfile.text = "FROM minio/minio:RELEASE.2019-01-23T23-18-58Z\n" +
"RUN mkdir -p /minio/data/${s3PermanentBucket}\n" +
"ENV MINIO_ACCESS_KEY ${s3PermanentAccessKey}\n" +
"ENV MINIO_SECRET_KEY ${s3PermanentSecretKey}"
}
}
preProcessFixture.dependsOn(writeDockerFile)
// The following closure must execute before the afterEvaluate block in the constructor of the following integrationTest tasks: // The following closure must execute before the afterEvaluate block in the constructor of the following integrationTest tasks:
project.afterEvaluate { project.afterEvaluate {
ClusterConfiguration cluster = project.extensions.getByName('integTestMinioCluster') as ClusterConfiguration ClusterConfiguration cluster = project.extensions.getByName('integTestMinioCluster') as ClusterConfiguration
cluster.dependsOn(project.bundlePlugin) cluster.dependsOn(project.bundlePlugin)
cluster.dependsOn(startMinio) // otherwise we don't know the Minio port cluster.dependsOn(postProcessFixture)
cluster.keystoreSetting 's3.client.integration_test_permanent.access_key', s3PermanentAccessKey cluster.keystoreSetting 's3.client.integration_test_permanent.access_key', s3PermanentAccessKey
cluster.keystoreSetting 's3.client.integration_test_permanent.secret_key', s3PermanentSecretKey cluster.keystoreSetting 's3.client.integration_test_permanent.secret_key', s3PermanentSecretKey
Closure<String> minioAddressAndPort = { Closure<String> minioAddressAndPort = {
assert startMinio.minioPort > 0 int minioPort = postProcessFixture.ext."test.fixtures.minio-fixture.tcp.9000"
return 'http://' + minioAddress + ':' + startMinio.minioPort assert minioPort > 0
return 'http://127.0.0.1:' + minioPort
} }
cluster.setting 's3.client.integration_test_permanent.endpoint', "${ -> minioAddressAndPort.call()}" cluster.setting 's3.client.integration_test_permanent.endpoint', "${ -> minioAddressAndPort.call()}"
@ -354,8 +194,7 @@ if (useFixture && minioDistribution) {
restIntegTestTask.clusterConfig.jvmArgs = jvmArgs restIntegTestTask.clusterConfig.jvmArgs = jvmArgs
} }
integTestMinioRunner.dependsOn(startMinio) integTestMinioRunner.dependsOn(postProcessFixture)
integTestMinioRunner.finalizedBy(stopMinio)
// Minio only supports a single access key, see https://github.com/minio/minio/pull/5968 // Minio only supports a single access key, see https://github.com/minio/minio/pull/5968
integTestMinioRunner.systemProperty 'tests.rest.blacklist', [ integTestMinioRunner.systemProperty 'tests.rest.blacklist', [
'repository_s3/30_repository_temporary_credentials/*', 'repository_s3/30_repository_temporary_credentials/*',
@ -364,6 +203,7 @@ if (useFixture && minioDistribution) {
].join(",") ].join(",")
project.check.dependsOn(integTestMinio) project.check.dependsOn(integTestMinio)
BuildPlugin.requireDocker(integTestMinio)
} }
File parentFixtures = new File(project.buildDir, "fixtures") File parentFixtures = new File(project.buildDir, "fixtures")

View File

@ -0,0 +1,9 @@
version: '3'
services:
minio-fixture:
build:
context: ./build/minio-docker
dockerfile: Dockerfile
ports:
- "9000"
command: ["server", "/minio/data"]