Skip to content

Commit 37674f8

Browse files
authored
Refactor GCS test fixture to remove docker dependency (#94755) (#96210)
1 parent 2691e98 commit 37674f8

File tree

22 files changed

+449
-595
lines changed

22 files changed

+449
-595
lines changed

modules/repository-gcs/build.gradle

Lines changed: 26 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
import org.apache.tools.ant.filters.ReplaceTokens
2-
import org.elasticsearch.gradle.internal.info.BuildParams
3-
import org.elasticsearch.gradle.internal.test.RestIntegTestTask
4-
import org.elasticsearch.gradle.internal.test.rest.LegacyYamlRestTestPlugin
5-
import org.elasticsearch.gradle.internal.test.InternalClusterTestPlugin
6-
7-
import java.nio.file.Files
8-
import java.security.KeyPair
9-
import java.security.KeyPairGenerator
10-
11-
import static org.elasticsearch.gradle.PropertyNormalization.IGNORE_VALUE
121
/*
132
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
143
* or more contributor license agreements. Licensed under the Elastic License
154
* 2.0 and the Server Side Public License, v 1; you may not use this file except
165
* in compliance with, at your election, the Elastic License 2.0 or the Server
176
* Side Public License, v 1.
187
*/
19-
apply plugin: 'elasticsearch.legacy-yaml-rest-test'
8+
9+
10+
import org.apache.tools.ant.filters.ReplaceTokens
11+
import org.elasticsearch.gradle.internal.info.BuildParams
12+
import org.elasticsearch.gradle.internal.test.InternalClusterTestPlugin
13+
14+
import java.nio.file.Files
15+
16+
apply plugin: 'elasticsearch.internal-yaml-rest-test'
2017
apply plugin: 'elasticsearch.internal-cluster-test'
2118
apply plugin: 'elasticsearch.internal-test-artifact-base'
2219

@@ -61,6 +58,7 @@ dependencies {
6158
testImplementation "org.apache.httpcomponents:httpcore:${versions.httpcore}"
6259

6360
testImplementation project(':test:fixtures:gcs-fixture')
61+
yamlRestTestImplementation project(':test:fixtures:gcs-fixture')
6462
}
6563

6664
testArtifacts {
@@ -202,60 +200,23 @@ tasks.named("thirdPartyAudit").configure {
202200
}
203201

204202
boolean useFixture = false
205-
206-
def fixtureAddress = { fixture ->
207-
assert useFixture: 'closure should not be used without a fixture'
208-
int ephemeralPort = project(':test:fixtures:gcs-fixture').postProcessFixture.ext."test.fixtures.${fixture}.tcp.80"
209-
assert ephemeralPort > 0
210-
'http://127.0.0.1:' + ephemeralPort
211-
}
212-
213203
String gcsServiceAccount = System.getenv("google_storage_service_account")
214204
String gcsBucket = System.getenv("google_storage_bucket")
215205
String gcsBasePath = System.getenv("google_storage_base_path")
216-
File serviceAccountFile = null
206+
File serviceAccountFile = gcsServiceAccount != null ? new File(gcsServiceAccount) : null
217207

218208
if (!gcsServiceAccount && !gcsBucket && !gcsBasePath) {
219-
serviceAccountFile = new File(project.buildDir, 'generated-resources/service_account_test.json')
220209
gcsBucket = 'bucket'
221210
gcsBasePath = 'integration_test'
222211
useFixture = true
223-
224-
apply plugin: 'elasticsearch.test.fixtures'
225-
testFixtures.useFixture(':test:fixtures:gcs-fixture', 'gcs-fixture')
226-
testFixtures.useFixture(':test:fixtures:gcs-fixture', 'gcs-fixture-third-party')
227-
testFixtures.useFixture(':test:fixtures:gcs-fixture', 'gcs-fixture-with-application-default-credentials')
228-
229212
} else if (!gcsServiceAccount || !gcsBucket || !gcsBasePath) {
230213
throw new IllegalArgumentException("not all options specified to run tests against external GCS service are present")
231-
} else {
232-
serviceAccountFile = new File(gcsServiceAccount)
233214
}
234215

235216
def encodedCredentials = {
236217
Base64.encoder.encodeToString(Files.readAllBytes(serviceAccountFile.toPath()))
237218
}
238219

239-
/** A service account file that points to the Google Cloud Storage service emulated by the fixture **/
240-
tasks.register("createServiceAccountFile") {
241-
doLast {
242-
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA")
243-
keyPairGenerator.initialize(2048)
244-
KeyPair keyPair = keyPairGenerator.generateKeyPair()
245-
String encodedKey = Base64.getEncoder().encodeToString(keyPair.private.getEncoded())
246-
247-
serviceAccountFile.parentFile.mkdirs()
248-
serviceAccountFile.setText("{\n" +
249-
' "type": "service_account",\n' +
250-
' "project_id": "integration_test",\n' +
251-
' "private_key_id": "' + UUID.randomUUID().toString() + '",\n' +
252-
' "private_key": "-----BEGIN PRIVATE KEY-----\\n' + encodedKey + '\\n-----END PRIVATE KEY-----\\n",\n' +
253-
' "client_email": "[email protected]",\n' +
254-
' "client_id": "123456789101112130594"\n' +
255-
'}', 'UTF-8')
256-
}
257-
}
258-
259220
Map<String, Object> expansions = [
260221
'bucket' : gcsBucket,
261222
'base_path': gcsBasePath + "_integration_tests"
@@ -271,86 +232,34 @@ tasks.named("internalClusterTest").configure {
271232
exclude '**/GoogleCloudStorageThirdPartyTests.class'
272233
}
273234

274-
tasks.named("yamlRestTest").configure {
275-
if (useFixture) {
276-
dependsOn "createServiceAccountFile"
235+
tasks.named("yamlRestTest") {
236+
systemProperty 'test.google.fixture', Boolean.toString(useFixture)
237+
if (useFixture == false) {
238+
systemProperty 'test.google.account', serviceAccountFile
239+
// We can't run these test in parallel against a real bucket since the tests will step on each other
240+
maxParallelForks = 1
277241
}
278242
}
279243

280-
/*
281-
* We only use a small amount of data in these tests, which means that the resumable upload path is not tested. We add
282-
* an additional test that forces the large blob threshold to be small to exercise the resumable upload path.
283-
*/
284-
def largeBlobYamlRestTest = tasks.register("largeBlobYamlRestTest", RestIntegTestTask) {
285-
if (useFixture) {
286-
dependsOn "createServiceAccountFile"
287-
}
288-
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
289-
SourceSet yamlRestTestSourceSet = sourceSets.getByName(LegacyYamlRestTestPlugin.SOURCE_SET_NAME)
290-
setTestClassesDirs(yamlRestTestSourceSet.getOutput().getClassesDirs())
291-
setClasspath(yamlRestTestSourceSet.getRuntimeClasspath())
292-
293-
// We have to wait for configure the cluster here as it might not have been created otherwise yet.
294-
testClusters {
295-
largeBlobYamlRestTest {
296-
module tasks.named("explodedBundlePlugin")
297-
298-
// force large blob uploads by setting the threshold small, forcing this code path to be tested
299-
systemProperty 'es.repository_gcs.large_blob_threshold_byte_size', '256'
300-
}
301-
}
302-
}
303-
304-
def gcsThirdPartyTest = tasks.register("gcsThirdPartyTest", Test) {
305-
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
244+
def gcsThirdPartyTest = tasks.register("gcsThirdPartyUnitTest", Test) {
245+
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class)
306246
SourceSet internalTestSourceSet = sourceSets.getByName(InternalClusterTestPlugin.SOURCE_SET_NAME)
307247
setTestClassesDirs(internalTestSourceSet.getOutput().getClassesDirs())
308248
setClasspath(internalTestSourceSet.getRuntimeClasspath())
309249
include '**/GoogleCloudStorageThirdPartyTests.class'
310250
systemProperty 'tests.security.manager', false
311251
systemProperty 'test.google.bucket', gcsBucket
252+
systemProperty 'test.google.fixture', Boolean.toString(useFixture)
312253
nonInputProperties.systemProperty 'test.google.base', gcsBasePath + "_third_party_tests_" + BuildParams.testSeed
313-
nonInputProperties.systemProperty 'test.google.account', "${-> encodedCredentials.call()}"
314-
if (useFixture) {
315-
dependsOn "createServiceAccountFile"
316-
nonInputProperties.systemProperty 'test.google.endpoint', "${-> fixtureAddress('gcs-fixture-third-party')}"
317-
nonInputProperties.systemProperty 'test.google.tokenURI', "${-> fixtureAddress('gcs-fixture-third-party')}/o/oauth2/token"
318-
}
319-
}
320-
321-
testClusters.matching {
322-
it.name == "yamlRestTest" ||
323-
it.name == "largeBlobYamlRestTest" ||
324-
it.name == "gcsThirdPartyTest" }.configureEach {
325-
keystore 'gcs.client.integration_test.credentials_file', serviceAccountFile, IGNORE_VALUE
326-
327-
if (useFixture) {
328-
/* Use a closure on the string to delay evaluation until tests are executed */
329-
setting 'gcs.client.integration_test.endpoint', { "${-> fixtureAddress('gcs-fixture')}" }, IGNORE_VALUE
330-
setting 'gcs.client.integration_test.token_uri', { "${-> fixtureAddress('gcs-fixture')}/o/oauth2/token" }, IGNORE_VALUE
331-
} else {
332-
println "Using an external service to test the repository-gcs plugin"
254+
if (useFixture == false) {
255+
nonInputProperties.systemProperty 'test.google.account', "${-> encodedCredentials.call()}"
333256
}
334257
}
335258

336-
337-
// Application Default Credentials
338-
if (useFixture) {
339-
tasks.register("yamlRestTestApplicationDefaultCredentials", RestIntegTestTask.class) {
340-
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
341-
SourceSet yamlRestTestSourceSet = sourceSets.getByName(LegacyYamlRestTestPlugin.SOURCE_SET_NAME)
342-
setTestClassesDirs(yamlRestTestSourceSet.getOutput().getClassesDirs())
343-
setClasspath(yamlRestTestSourceSet.getRuntimeClasspath())
344-
}
345-
tasks.named("check").configure { dependsOn("yamlRestTestApplicationDefaultCredentials") }
346-
347-
testClusters.matching { it.name == "yamlRestTestApplicationDefaultCredentials" }.configureEach {
348-
setting 'gcs.client.integration_test.endpoint', { "${-> fixtureAddress('gcs-fixture-with-application-default-credentials')}" }, IGNORE_VALUE
349-
module tasks.named("explodedBundlePlugin")
350-
environment 'GCE_METADATA_HOST', { "${-> fixtureAddress('gcs-fixture-with-application-default-credentials')}".replace("http://", "") }, IGNORE_VALUE
351-
}
259+
tasks.register('gcsThirdPartyTest') {
260+
dependsOn 'yamlRestTest', gcsThirdPartyTest
352261
}
353262

354-
tasks.named("check").configure {
355-
dependsOn(largeBlobYamlRestTest, gcsThirdPartyTest)
263+
tasks.named('check') {
264+
dependsOn gcsThirdPartyTest
356265
}

modules/repository-gcs/src/internalClusterTest/java/org/elasticsearch/repositories/gcs/GoogleCloudStorageThirdPartyTests.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88

99
package org.elasticsearch.repositories.gcs;
1010

11+
import fixture.gcs.GoogleCloudStorageHttpFixture;
12+
import fixture.gcs.TestUtils;
13+
1114
import org.elasticsearch.action.support.master.AcknowledgedResponse;
12-
import org.elasticsearch.common.Strings;
1315
import org.elasticsearch.common.settings.MockSecureSettings;
1416
import org.elasticsearch.common.settings.SecureSettings;
1517
import org.elasticsearch.common.settings.Settings;
18+
import org.elasticsearch.core.Booleans;
1619
import org.elasticsearch.plugins.Plugin;
1720
import org.elasticsearch.repositories.AbstractThirdPartyRepositoryTestCase;
21+
import org.junit.ClassRule;
1822

1923
import java.util.Base64;
2024
import java.util.Collection;
@@ -24,6 +28,10 @@
2428
import static org.hamcrest.Matchers.not;
2529

2630
public class GoogleCloudStorageThirdPartyTests extends AbstractThirdPartyRepositoryTestCase {
31+
private static final boolean USE_FIXTURE = Booleans.parseBoolean(System.getProperty("test.google.fixture", "true"));
32+
33+
@ClassRule
34+
public static GoogleCloudStorageHttpFixture fixture = new GoogleCloudStorageHttpFixture(USE_FIXTURE, "bucket", "o/oauth2/token");
2735

2836
@Override
2937
protected Collection<Class<? extends Plugin>> getPlugins() {
@@ -34,27 +42,30 @@ protected Collection<Class<? extends Plugin>> getPlugins() {
3442
protected Settings nodeSettings() {
3543
Settings.Builder builder = Settings.builder().put(super.nodeSettings());
3644

37-
if (Strings.isNullOrEmpty(System.getProperty("test.google.endpoint")) == false) {
38-
builder.put("gcs.client.default.endpoint", System.getProperty("test.google.endpoint"));
39-
}
40-
41-
if (Strings.isNullOrEmpty(System.getProperty("test.google.tokenURI")) == false) {
42-
builder.put("gcs.client.default.token_uri", System.getProperty("test.google.tokenURI"));
45+
if (USE_FIXTURE) {
46+
builder.put("gcs.client.default.endpoint", fixture.getAddress());
47+
builder.put("gcs.client.default.token_uri", fixture.getAddress() + "/o/oauth2/token");
4348
}
4449

4550
return builder.build();
4651
}
4752

4853
@Override
4954
protected SecureSettings credentials() {
50-
assertThat(System.getProperty("test.google.account"), not(blankOrNullString()));
55+
if (USE_FIXTURE == false) {
56+
assertThat(System.getProperty("test.google.account"), not(blankOrNullString()));
57+
}
5158
assertThat(System.getProperty("test.google.bucket"), not(blankOrNullString()));
5259

5360
MockSecureSettings secureSettings = new MockSecureSettings();
54-
secureSettings.setFile(
55-
"gcs.client.default.credentials_file",
56-
Base64.getDecoder().decode(System.getProperty("test.google.account"))
57-
);
61+
if (USE_FIXTURE) {
62+
secureSettings.setFile("gcs.client.default.credentials_file", TestUtils.createServiceAccount(random()));
63+
} else {
64+
secureSettings.setFile(
65+
"gcs.client.default.credentials_file",
66+
Base64.getDecoder().decode(System.getProperty("test.google.account"))
67+
);
68+
}
5869
return secureSettings;
5970
}
6071

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.repositories.gcs;
10+
11+
import fixture.gcs.GoogleCloudStorageHttpFixture;
12+
13+
import com.carrotsearch.randomizedtesting.annotations.Name;
14+
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
15+
16+
import org.elasticsearch.core.Booleans;
17+
import org.elasticsearch.test.cluster.ElasticsearchCluster;
18+
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
19+
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
20+
import org.junit.BeforeClass;
21+
import org.junit.ClassRule;
22+
import org.junit.rules.RuleChain;
23+
import org.junit.rules.TestRule;
24+
25+
public class DefaultCredentialsRepositoryGcsClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
26+
private static final boolean USE_FIXTURE = Booleans.parseBoolean(System.getProperty("test.google.fixture", "true"));
27+
28+
private static GoogleCloudStorageHttpFixture fixture = new GoogleCloudStorageHttpFixture(
29+
true,
30+
"bucket",
31+
"computeMetadata/v1/instance/service-accounts/default/token"
32+
);
33+
34+
private static ElasticsearchCluster cluster = ElasticsearchCluster.local()
35+
.module("repository-gcs")
36+
.setting("gcs.client.integration_test.endpoint", () -> fixture.getAddress())
37+
.environment("GCE_METADATA_HOST", () -> fixture.getAddress().replace("http://", ""))
38+
.build();
39+
40+
@ClassRule
41+
public static TestRule ruleChain = RuleChain.outerRule(fixture).around(cluster);
42+
43+
public DefaultCredentialsRepositoryGcsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
44+
super(testCandidate);
45+
}
46+
47+
@BeforeClass
48+
public static void checkFixtureEnabled() {
49+
assumeTrue("Only run against test fixture", USE_FIXTURE);
50+
}
51+
52+
@Override
53+
protected String getTestRestCluster() {
54+
return cluster.getHttpAddresses();
55+
}
56+
57+
@ParametersFactory
58+
public static Iterable<Object[]> parameters() throws Exception {
59+
return createParameters();
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.repositories.gcs;
10+
11+
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
12+
13+
public class LargeBlobRepositoryGcsClientYamlTestSuiteIT extends RepositoryGcsClientYamlTestSuiteIT {
14+
15+
static {
16+
clusterConfig = c -> c.systemProperty("es.repository_gcs.large_blob_threshold_byte_size", "256");
17+
}
18+
19+
public LargeBlobRepositoryGcsClientYamlTestSuiteIT(ClientYamlTestCandidate testCandidate) {
20+
super(testCandidate);
21+
}
22+
}

0 commit comments

Comments
 (0)