|
| 1 | +import org.apache.tools.ant.taskdefs.condition.Os |
| 2 | +import org.elasticsearch.gradle.LoggedExec |
| 3 | +import org.elasticsearch.gradle.MavenFilteringHack |
| 4 | +import org.elasticsearch.gradle.test.AntFixture |
| 5 | +import org.elasticsearch.gradle.test.ClusterConfiguration |
| 6 | +import org.elasticsearch.gradle.test.RestIntegTestTask |
| 7 | + |
| 8 | +import java.lang.reflect.Field |
| 9 | + |
1 | 10 | /*
|
2 | 11 | * Licensed to Elasticsearch under one or more contributor
|
3 | 12 | * license agreements. See the NOTICE file distributed with
|
@@ -64,14 +73,245 @@ test {
|
64 | 73 | exclude '**/*CredentialsTests.class'
|
65 | 74 | }
|
66 | 75 |
|
67 |
| -check { |
68 |
| - // also execute the QA tests when testing the plugin |
69 |
| - dependsOn 'qa:amazon-s3:check' |
| 76 | +boolean useFixture = false |
| 77 | + |
| 78 | +// We test against two repositories, one which uses the usual two-part "permanent" credentials and |
| 79 | +// the other which uses three-part "temporary" or "session" credentials. |
| 80 | + |
| 81 | +String s3PermanentAccessKey = System.getenv("amazon_s3_access_key") |
| 82 | +String s3PermanentSecretKey = System.getenv("amazon_s3_secret_key") |
| 83 | +String s3PermanentBucket = System.getenv("amazon_s3_bucket") |
| 84 | +String s3PermanentBasePath = System.getenv("amazon_s3_base_path") |
| 85 | + |
| 86 | +String s3TemporaryAccessKey = System.getenv("amazon_s3_access_key_temporary") |
| 87 | +String s3TemporarySecretKey = System.getenv("amazon_s3_secret_key_temporary") |
| 88 | +String s3TemporarySessionToken = System.getenv("amazon_s3_session_token_temporary") |
| 89 | +String s3TemporaryBucket = System.getenv("amazon_s3_bucket_temporary") |
| 90 | +String s3TemporaryBasePath = System.getenv("amazon_s3_base_path_temporary") |
| 91 | + |
| 92 | +// If all these variables are missing then we are testing against the internal fixture instead, which has the following |
| 93 | +// credentials hard-coded in. |
| 94 | + |
| 95 | +if (!s3PermanentAccessKey && !s3PermanentSecretKey && !s3PermanentBucket && !s3PermanentBasePath |
| 96 | + && !s3TemporaryAccessKey && !s3TemporarySecretKey && !s3TemporaryBucket && !s3TemporaryBasePath && !s3TemporarySessionToken) { |
| 97 | + |
| 98 | + s3PermanentAccessKey = 's3_integration_test_permanent_access_key' |
| 99 | + s3PermanentSecretKey = 's3_integration_test_permanent_secret_key' |
| 100 | + s3PermanentBucket = 'permanent-bucket-test' |
| 101 | + s3PermanentBasePath = 'integration_test' |
| 102 | + |
| 103 | + s3TemporaryAccessKey = 's3_integration_test_temporary_access_key' |
| 104 | + s3TemporarySecretKey = 's3_integration_test_temporary_secret_key' |
| 105 | + s3TemporaryBucket = 'temporary-bucket-test' |
| 106 | + s3TemporaryBasePath = 'integration_test' |
| 107 | + s3TemporarySessionToken = 's3_integration_test_temporary_session_token' |
| 108 | + |
| 109 | + useFixture = true |
| 110 | +} else if (!s3PermanentAccessKey || !s3PermanentSecretKey || !s3PermanentBucket || !s3PermanentBasePath |
| 111 | + || !s3TemporaryAccessKey || !s3TemporarySecretKey || !s3TemporaryBucket || !s3TemporaryBasePath || !s3TemporarySessionToken) { |
| 112 | + throw new IllegalArgumentException("not all options specified to run against external S3 service") |
| 113 | +} |
| 114 | + |
| 115 | +final String minioVersion = 'RELEASE.2018-06-22T23-48-46Z' |
| 116 | +final String minioBinDir = "${buildDir}/minio/bin" |
| 117 | +final String minioDataDir = "${buildDir}/minio/data" |
| 118 | +final String minioAddress = "127.0.0.1:60920" |
| 119 | + |
| 120 | +final String minioDistribution |
| 121 | +final String minioCheckSum |
| 122 | +if (Os.isFamily(Os.FAMILY_MAC)) { |
| 123 | + minioDistribution = 'darwin-amd64' |
| 124 | + minioCheckSum = '96b0bcb2f590e8e65fb83d5c3e221f9bd1106b49fa6f22c6b726b80b845d7c60' |
| 125 | +} else if (Os.isFamily(Os.FAMILY_UNIX)) { |
| 126 | + minioDistribution = 'linux-amd64' |
| 127 | + minioCheckSum = '713dac7c105285eab3b92649be92b5e793b29d3525c7929fa7aaed99374fad99' |
| 128 | +} else { |
| 129 | + minioDistribution = null |
| 130 | + minioCheckSum = null |
| 131 | +} |
| 132 | + |
| 133 | +buildscript { |
| 134 | + repositories { |
| 135 | + maven { |
| 136 | + url 'https://plugins.gradle.org/m2/' |
| 137 | + } |
| 138 | + } |
| 139 | + dependencies { |
| 140 | + classpath 'de.undercouch:gradle-download-task:3.4.3' |
| 141 | + } |
| 142 | +} |
| 143 | + |
| 144 | +if (useFixture && minioDistribution) { |
| 145 | + apply plugin: 'de.undercouch.download' |
| 146 | + |
| 147 | + final String minioFileName = "minio.${minioVersion}" |
| 148 | + final String minioDownloadURL = "https://dl.minio.io/server/minio/release/${minioDistribution}/archive/${minioFileName}" |
| 149 | + final String minioFilePath = "${gradle.gradleUserHomeDir}/downloads/minio/${minioDistribution}/${minioFileName}" |
| 150 | + |
| 151 | + task downloadMinio(type: Download) { |
| 152 | + src minioDownloadURL |
| 153 | + dest minioFilePath |
| 154 | + onlyIfModified true |
| 155 | + } |
| 156 | + |
| 157 | + task verifyMinioChecksum(type: Verify, dependsOn: downloadMinio) { |
| 158 | + src minioFilePath |
| 159 | + algorithm 'SHA-256' |
| 160 | + checksum minioCheckSum |
| 161 | + } |
| 162 | + |
| 163 | + task installMinio(type: Sync, dependsOn: verifyMinioChecksum) { |
| 164 | + from minioFilePath |
| 165 | + into minioBinDir |
| 166 | + fileMode 0755 |
| 167 | + } |
| 168 | + |
| 169 | + task startMinio { |
| 170 | + dependsOn installMinio |
| 171 | + |
| 172 | + ext.minioPid = 0L |
| 173 | + |
| 174 | + doLast { |
| 175 | + new File("${minioDataDir}/${s3PermanentBucket}").mkdirs() |
| 176 | + // we skip these tests on Windows so we do no need to worry about compatibility here |
| 177 | + final ProcessBuilder minio = new ProcessBuilder( |
| 178 | + "${minioBinDir}/${minioFileName}", |
| 179 | + "server", |
| 180 | + "--address", |
| 181 | + minioAddress, |
| 182 | + minioDataDir) |
| 183 | + minio.environment().put('MINIO_ACCESS_KEY', s3PermanentAccessKey) |
| 184 | + minio.environment().put('MINIO_SECRET_KEY', s3PermanentSecretKey) |
| 185 | + final Process process = minio.start() |
| 186 | + if (JavaVersion.current() <= JavaVersion.VERSION_1_8) { |
| 187 | + try { |
| 188 | + Class<?> cProcessImpl = process.getClass() |
| 189 | + Field fPid = cProcessImpl.getDeclaredField("pid") |
| 190 | + if (!fPid.isAccessible()) { |
| 191 | + fPid.setAccessible(true) |
| 192 | + } |
| 193 | + minioPid = fPid.getInt(process) |
| 194 | + } catch (Exception e) { |
| 195 | + logger.error("failed to read pid from minio process", e) |
| 196 | + process.destroyForcibly() |
| 197 | + throw e |
| 198 | + } |
| 199 | + } else { |
| 200 | + minioPid = process.pid() |
| 201 | + } |
| 202 | + |
| 203 | + new BufferedReader(new InputStreamReader(process.getInputStream())).withReader { br -> |
| 204 | + String line |
| 205 | + int httpPort = 0 |
| 206 | + while ((line = br.readLine()) != null) { |
| 207 | + logger.info(line) |
| 208 | + if (line.matches('.*Endpoint.*:\\d+$')) { |
| 209 | + assert httpPort == 0 |
| 210 | + final int index = line.lastIndexOf(":") |
| 211 | + assert index >= 0 |
| 212 | + httpPort = Integer.parseInt(line.substring(index + 1)) |
| 213 | + |
| 214 | + final File script = new File(project.buildDir, "minio/minio.killer.sh") |
| 215 | + script.setText( |
| 216 | + ["function shutdown {", |
| 217 | + " kill ${minioPid}", |
| 218 | + "}", |
| 219 | + "trap shutdown EXIT", |
| 220 | + // will wait indefinitely for input, but we never pass input, and the pipe is only closed when the build dies |
| 221 | + "read line\n"].join('\n'), 'UTF-8') |
| 222 | + final ProcessBuilder killer = new ProcessBuilder("bash", script.absolutePath) |
| 223 | + killer.start() |
| 224 | + break |
| 225 | + } |
| 226 | + } |
| 227 | + |
| 228 | + assert httpPort > 0 |
| 229 | + } |
| 230 | + } |
| 231 | + } |
| 232 | + |
| 233 | + task stopMinio(type: LoggedExec) { |
| 234 | + onlyIf { startMinio.minioPid > 0 } |
| 235 | + |
| 236 | + doFirst { |
| 237 | + logger.info("Shutting down minio with pid ${startMinio.minioPid}") |
| 238 | + } |
| 239 | + |
| 240 | + final Object pid = "${ -> startMinio.minioPid }" |
| 241 | + |
| 242 | + // we skip these tests on Windows so we do no need to worry about compatibility here |
| 243 | + executable = 'kill' |
| 244 | + args('-9', pid) |
| 245 | + } |
| 246 | + |
| 247 | + RestIntegTestTask integTestMinio = project.tasks.create('integTestMinio', RestIntegTestTask.class) { |
| 248 | + description = "Runs REST tests using the Minio repository." |
| 249 | + } |
| 250 | + |
| 251 | + // The following closure must execute before the afterEvaluate block in the constructor of the following integrationTest tasks: |
| 252 | + project.afterEvaluate { |
| 253 | + ClusterConfiguration cluster = project.extensions.getByName('integTestMinioCluster') as ClusterConfiguration |
| 254 | + cluster.dependsOn(project.bundlePlugin) |
| 255 | + cluster.keystoreSetting 's3.client.integration_test_permanent.access_key', s3PermanentAccessKey |
| 256 | + cluster.keystoreSetting 's3.client.integration_test_permanent.secret_key', s3PermanentSecretKey |
| 257 | + |
| 258 | + cluster.setting 's3.client.integration_test_permanent.endpoint', "http://${minioAddress}" |
| 259 | + |
| 260 | + Task restIntegTestTask = project.tasks.getByName('integTestMinio') |
| 261 | + restIntegTestTask.clusterConfig.plugin(project.path) |
| 262 | + |
| 263 | + // Default jvm arguments for all test clusters |
| 264 | + String jvmArgs = "-Xms" + System.getProperty('tests.heap.size', '512m') + |
| 265 | + " " + "-Xmx" + System.getProperty('tests.heap.size', '512m') + |
| 266 | + " " + System.getProperty('tests.jvm.argline', '') |
| 267 | + |
| 268 | + restIntegTestTask.clusterConfig.jvmArgs = jvmArgs |
| 269 | + } |
| 270 | + |
| 271 | + integTestMinioRunner.dependsOn(startMinio) |
| 272 | + integTestMinioRunner.finalizedBy(stopMinio) |
| 273 | + // Minio only supports a single access key, see https://github.com/minio/minio/pull/5968 |
| 274 | + integTestMinioRunner.systemProperty 'tests.rest.blacklist', 'repository_s3/30_repository_temporary_credentials/*' |
| 275 | + |
| 276 | + project.check.dependsOn(integTestMinio) |
| 277 | +} |
| 278 | + |
| 279 | +/** A task to start the AmazonS3Fixture which emulates an S3 service **/ |
| 280 | +task s3Fixture(type: AntFixture) { |
| 281 | + dependsOn testClasses |
| 282 | + env 'CLASSPATH', "${ -> project.sourceSets.test.runtimeClasspath.asPath }" |
| 283 | + executable = new File(project.runtimeJavaHome, 'bin/java') |
| 284 | + args 'org.elasticsearch.repositories.s3.AmazonS3Fixture', baseDir, s3PermanentBucket, s3TemporaryBucket |
| 285 | +} |
| 286 | + |
| 287 | +Map<String, Object> expansions = [ |
| 288 | + 'permanent_bucket': s3PermanentBucket, |
| 289 | + 'permanent_base_path': s3PermanentBasePath, |
| 290 | + 'temporary_bucket': s3TemporaryBucket, |
| 291 | + 'temporary_base_path': s3TemporaryBasePath |
| 292 | +] |
| 293 | + |
| 294 | +processTestResources { |
| 295 | + inputs.properties(expansions) |
| 296 | + MavenFilteringHack.filter(it, expansions) |
70 | 297 | }
|
71 | 298 |
|
72 | 299 | integTestCluster {
|
73 |
| - keystoreSetting 's3.client.integration_test.access_key', "s3_integration_test_access_key" |
74 |
| - keystoreSetting 's3.client.integration_test.secret_key', "s3_integration_test_secret_key" |
| 300 | + keystoreSetting 's3.client.integration_test_permanent.access_key', s3PermanentAccessKey |
| 301 | + keystoreSetting 's3.client.integration_test_permanent.secret_key', s3PermanentSecretKey |
| 302 | + |
| 303 | + keystoreSetting 's3.client.integration_test_temporary.access_key', s3TemporaryAccessKey |
| 304 | + keystoreSetting 's3.client.integration_test_temporary.secret_key', s3TemporarySecretKey |
| 305 | + keystoreSetting 's3.client.integration_test_temporary.session_token', s3TemporarySessionToken |
| 306 | + |
| 307 | + if (useFixture) { |
| 308 | + dependsOn s3Fixture |
| 309 | + /* Use a closure on the string to delay evaluation until tests are executed */ |
| 310 | + setting 's3.client.integration_test_permanent.endpoint', "http://${-> s3Fixture.addressAndPort}" |
| 311 | + setting 's3.client.integration_test_temporary.endpoint', "http://${-> s3Fixture.addressAndPort}" |
| 312 | + } else { |
| 313 | + println "Using an external service to test the repository-s3 plugin" |
| 314 | + } |
75 | 315 | }
|
76 | 316 |
|
77 | 317 | thirdPartyAudit.excludes = [
|
|
0 commit comments