Skip to content

Commit e9ff708

Browse files
committed
Refactor GCS test fixture to remove docker dependency (elastic#94755)
1 parent 6661c94 commit e9ff708

File tree

22 files changed

+449
-596
lines changed

22 files changed

+449
-596
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

2219
esplugin {
@@ -60,6 +57,7 @@ dependencies {
6057
testImplementation "org.apache.httpcomponents:httpcore:${versions.httpcore}"
6158

6259
testImplementation project(':test:fixtures:gcs-fixture')
60+
yamlRestTestImplementation project(':test:fixtures:gcs-fixture')
6361
}
6462

6563
restResources {
@@ -192,60 +190,23 @@ tasks.named("thirdPartyAudit").configure {
192190
}
193191

194192
boolean useFixture = false
195-
196-
def fixtureAddress = { fixture ->
197-
assert useFixture: 'closure should not be used without a fixture'
198-
int ephemeralPort = project(':test:fixtures:gcs-fixture').postProcessFixture.ext."test.fixtures.${fixture}.tcp.80"
199-
assert ephemeralPort > 0
200-
'http://127.0.0.1:' + ephemeralPort
201-
}
202-
203193
String gcsServiceAccount = System.getenv("google_storage_service_account")
204194
String gcsBucket = System.getenv("google_storage_bucket")
205195
String gcsBasePath = System.getenv("google_storage_base_path")
206-
File serviceAccountFile = null
196+
File serviceAccountFile = gcsServiceAccount != null ? new File(gcsServiceAccount) : null
207197

208198
if (!gcsServiceAccount && !gcsBucket && !gcsBasePath) {
209-
serviceAccountFile = new File(project.buildDir, 'generated-resources/service_account_test.json')
210199
gcsBucket = 'bucket'
211200
gcsBasePath = 'integration_test'
212201
useFixture = true
213-
214-
apply plugin: 'elasticsearch.test.fixtures'
215-
testFixtures.useFixture(':test:fixtures:gcs-fixture', 'gcs-fixture')
216-
testFixtures.useFixture(':test:fixtures:gcs-fixture', 'gcs-fixture-third-party')
217-
testFixtures.useFixture(':test:fixtures:gcs-fixture', 'gcs-fixture-with-application-default-credentials')
218-
219202
} else if (!gcsServiceAccount || !gcsBucket || !gcsBasePath) {
220203
throw new IllegalArgumentException("not all options specified to run tests against external GCS service are present")
221-
} else {
222-
serviceAccountFile = new File(gcsServiceAccount)
223204
}
224205

225206
def encodedCredentials = {
226207
Base64.encoder.encodeToString(Files.readAllBytes(serviceAccountFile.toPath()))
227208
}
228209

229-
/** A service account file that points to the Google Cloud Storage service emulated by the fixture **/
230-
tasks.register("createServiceAccountFile") {
231-
doLast {
232-
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA")
233-
keyPairGenerator.initialize(2048)
234-
KeyPair keyPair = keyPairGenerator.generateKeyPair()
235-
String encodedKey = Base64.getEncoder().encodeToString(keyPair.private.getEncoded())
236-
237-
serviceAccountFile.parentFile.mkdirs()
238-
serviceAccountFile.setText("{\n" +
239-
' "type": "service_account",\n' +
240-
' "project_id": "integration_test",\n' +
241-
' "private_key_id": "' + UUID.randomUUID().toString() + '",\n' +
242-
' "private_key": "-----BEGIN PRIVATE KEY-----\\n' + encodedKey + '\\n-----END PRIVATE KEY-----\\n",\n' +
243-
' "client_email": "[email protected]",\n' +
244-
' "client_id": "123456789101112130594"\n' +
245-
'}', 'UTF-8')
246-
}
247-
}
248-
249210
Map<String, Object> expansions = [
250211
'bucket' : gcsBucket,
251212
'base_path': gcsBasePath + "_integration_tests"
@@ -261,86 +222,34 @@ tasks.named("internalClusterTest").configure {
261222
exclude '**/GoogleCloudStorageThirdPartyTests.class'
262223
}
263224

264-
tasks.named("yamlRestTest").configure {
265-
if (useFixture) {
266-
dependsOn "createServiceAccountFile"
225+
tasks.named("yamlRestTest") {
226+
systemProperty 'test.google.fixture', Boolean.toString(useFixture)
227+
if (useFixture == false) {
228+
systemProperty 'test.google.account', serviceAccountFile
229+
// We can't run these test in parallel against a real bucket since the tests will step on each other
230+
maxParallelForks = 1
267231
}
268232
}
269233

270-
/*
271-
* We only use a small amount of data in these tests, which means that the resumable upload path is not tested. We add
272-
* an additional test that forces the large blob threshold to be small to exercise the resumable upload path.
273-
*/
274-
def largeBlobYamlRestTest = tasks.register("largeBlobYamlRestTest", RestIntegTestTask) {
275-
if (useFixture) {
276-
dependsOn "createServiceAccountFile"
277-
}
278-
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
279-
SourceSet yamlRestTestSourceSet = sourceSets.getByName(LegacyYamlRestTestPlugin.SOURCE_SET_NAME)
280-
setTestClassesDirs(yamlRestTestSourceSet.getOutput().getClassesDirs())
281-
setClasspath(yamlRestTestSourceSet.getRuntimeClasspath())
282-
283-
// We have to wait for configure the cluster here as it might not have been created otherwise yet.
284-
testClusters {
285-
largeBlobYamlRestTest {
286-
module tasks.named("explodedBundlePlugin")
287-
288-
// force large blob uploads by setting the threshold small, forcing this code path to be tested
289-
systemProperty 'es.repository_gcs.large_blob_threshold_byte_size', '256'
290-
}
291-
}
292-
}
293-
294-
def gcsThirdPartyTest = tasks.register("gcsThirdPartyTest", Test) {
295-
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
234+
def gcsThirdPartyTest = tasks.register("gcsThirdPartyUnitTest", Test) {
235+
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class)
296236
SourceSet internalTestSourceSet = sourceSets.getByName(InternalClusterTestPlugin.SOURCE_SET_NAME)
297237
setTestClassesDirs(internalTestSourceSet.getOutput().getClassesDirs())
298238
setClasspath(internalTestSourceSet.getRuntimeClasspath())
299239
include '**/GoogleCloudStorageThirdPartyTests.class'
300240
systemProperty 'tests.security.manager', false
301241
systemProperty 'test.google.bucket', gcsBucket
242+
systemProperty 'test.google.fixture', Boolean.toString(useFixture)
302243
nonInputProperties.systemProperty 'test.google.base', gcsBasePath + "_third_party_tests_" + BuildParams.testSeed
303-
nonInputProperties.systemProperty 'test.google.account', "${-> encodedCredentials.call()}"
304-
if (useFixture) {
305-
dependsOn "createServiceAccountFile"
306-
nonInputProperties.systemProperty 'test.google.endpoint', "${-> fixtureAddress('gcs-fixture-third-party')}"
307-
nonInputProperties.systemProperty 'test.google.tokenURI', "${-> fixtureAddress('gcs-fixture-third-party')}/o/oauth2/token"
308-
}
309-
}
310-
311-
testClusters.matching {
312-
it.name == "yamlRestTest" ||
313-
it.name == "largeBlobYamlRestTest" ||
314-
it.name == "gcsThirdPartyTest" }.configureEach {
315-
keystore 'gcs.client.integration_test.credentials_file', serviceAccountFile, IGNORE_VALUE
316-
317-
if (useFixture) {
318-
/* Use a closure on the string to delay evaluation until tests are executed */
319-
setting 'gcs.client.integration_test.endpoint', { "${-> fixtureAddress('gcs-fixture')}" }, IGNORE_VALUE
320-
setting 'gcs.client.integration_test.token_uri', { "${-> fixtureAddress('gcs-fixture')}/o/oauth2/token" }, IGNORE_VALUE
321-
} else {
322-
println "Using an external service to test the repository-gcs plugin"
244+
if (useFixture == false) {
245+
nonInputProperties.systemProperty 'test.google.account', "${-> encodedCredentials.call()}"
323246
}
324247
}
325248

326-
327-
// Application Default Credentials
328-
if (useFixture) {
329-
tasks.register("yamlRestTestApplicationDefaultCredentials", RestIntegTestTask.class) {
330-
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
331-
SourceSet yamlRestTestSourceSet = sourceSets.getByName(LegacyYamlRestTestPlugin.SOURCE_SET_NAME)
332-
setTestClassesDirs(yamlRestTestSourceSet.getOutput().getClassesDirs())
333-
setClasspath(yamlRestTestSourceSet.getRuntimeClasspath())
334-
}
335-
tasks.named("check").configure { dependsOn("yamlRestTestApplicationDefaultCredentials") }
336-
337-
testClusters.matching { it.name == "yamlRestTestApplicationDefaultCredentials" }.configureEach {
338-
setting 'gcs.client.integration_test.endpoint', { "${-> fixtureAddress('gcs-fixture-with-application-default-credentials')}" }, IGNORE_VALUE
339-
module tasks.named("explodedBundlePlugin")
340-
environment 'GCE_METADATA_HOST', { "${-> fixtureAddress('gcs-fixture-with-application-default-credentials')}".replace("http://", "") }, IGNORE_VALUE
341-
}
249+
tasks.register('gcsThirdPartyTest') {
250+
dependsOn 'yamlRestTest', gcsThirdPartyTest
342251
}
343252

344-
tasks.named("check").configure {
345-
dependsOn(largeBlobYamlRestTest, gcsThirdPartyTest)
253+
tasks.named('check') {
254+
dependsOn gcsThirdPartyTest
346255
}

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)