Skip to content

Commit 1ce323e

Browse files
authored
Add option to preserve data in test clusters (#65400)
1 parent e242eb6 commit 1ce323e

File tree

8 files changed

+90
-19
lines changed

8 files changed

+90
-19
lines changed

TESTING.asciidoc

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,13 @@ password: `elastic-password`.
8282

8383
==== Other useful arguments
8484

85-
In order to start a node with a different max heap space add: `-Dtests.heap.size=4G`
86-
In order to disable assertions add: `-Dtests.asserts=false`
87-
In order to use a custom data directory: `--data-dir=/tmp/foo`
88-
In order to remotely attach a debugger to the process: `--debug-jvm`
89-
In order to set a different keystore password: `--keystore-password`
90-
In order to set an Elasticsearch setting, provide a setting with the following prefix: `-Dtests.es.`
85+
- In order to start a node with a different max heap space add: `-Dtests.heap.size=4G`
86+
- In order to disable assertions add: `-Dtests.asserts=false`
87+
- In order to use a custom data directory: `--data-dir=/tmp/foo`
88+
- In order to preserve data in between executions: `--preserve-data`
89+
- In order to remotely attach a debugger to the process: `--debug-jvm`
90+
- In order to set a different keystore password: `--keystore-password`
91+
- In order to set an Elasticsearch setting, provide a setting with the following prefix: `-Dtests.es.`
9192

9293
=== Test case filtering.
9394

@@ -308,15 +309,15 @@ The REST tests are run automatically when executing the "./gradlew check" comman
308309
YAML REST tests use the following command (modules and plugins may also include YAML REST tests):
309310

310311
---------------------------------------------------------------------------
311-
./gradlew :rest-api-spec:yamlRestTest
312+
./gradlew :rest-api-spec:yamlRestTest
312313
---------------------------------------------------------------------------
313314

314315
A specific test case can be run with the following command:
315316

316317
---------------------------------------------------------------------------
317318
./gradlew ':rest-api-spec:yamlRestTest' \
318319
--tests "org.elasticsearch.test.rest.ClientYamlTestSuiteIT" \
319-
-Dtests.method="test {p0=cat.segments/10_basic/Help}"
320+
-Dtests.method="test {p0=cat.segments/10_basic/Help}"
320321
---------------------------------------------------------------------------
321322

322323
The YAML REST tests support all the options provided by the randomized runner, plus the following:
@@ -334,14 +335,14 @@ Java REST tests can be run with the "javaRestTest" task.
334335

335336
For example :
336337
---------------------------------------------------------------------------
337-
./gradlew :modules:mapper-extras:javaRestTest
338+
./gradlew :modules:mapper-extras:javaRestTest
338339
---------------------------------------------------------------------------
339340

340341
A specific test case can be run with the following syntax (fqn.test {params}):
341342

342343
---------------------------------------------------------------------------
343344
./gradlew ':modules:mapper-extras:javaRestTest' \
344-
--tests "org.elasticsearch.index.mapper.TokenCountFieldMapperIntegrationIT.testSearchByTokenCount {storeCountedFields=true loadCountedFields=false}"
345+
--tests "org.elasticsearch.index.mapper.TokenCountFieldMapperIntegrationIT.testSearchByTokenCount {storeCountedFields=true loadCountedFields=false}"
345346
---------------------------------------------------------------------------
346347

347348
yamlRestTest's and javaRestTest's are easy to identify, since they are found in a

buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchCluster.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,16 @@ public void jvmArgs(String... values) {
282282
nodes.all(each -> each.jvmArgs(values));
283283
}
284284

285+
@Internal
286+
public boolean isPreserveDataDir() {
287+
return nodes.stream().anyMatch(node -> node.isPreserveDataDir());
288+
}
289+
290+
@Override
291+
public void setPreserveDataDir(boolean preserveDataDir) {
292+
nodes.all(each -> each.setPreserveDataDir(preserveDataDir));
293+
}
294+
285295
@Override
286296
public void freeze() {
287297
nodes.forEach(ElasticsearchNode::freeze);

buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ public class ElasticsearchNode implements TestClusterConfiguration {
127127
private final FileSystemOperations fileSystemOperations;
128128
private final ArchiveOperations archiveOperations;
129129
private final ExecOperations execOperations;
130-
131130
private final AtomicBoolean configurationFrozen = new AtomicBoolean(false);
132131
private final Path workingDir;
133132

@@ -167,6 +166,7 @@ public class ElasticsearchNode implements TestClusterConfiguration {
167166
private String transportPort = "0";
168167
private Path confPathData;
169168
private String keystorePassword = "";
169+
private boolean preserveDataDir = false;
170170

171171
ElasticsearchNode(
172172
String path,
@@ -421,6 +421,17 @@ public Path getConfigDir() {
421421
return configFile.getParent();
422422
}
423423

424+
@Override
425+
@Input
426+
public boolean isPreserveDataDir() {
427+
return preserveDataDir;
428+
}
429+
430+
@Override
431+
public void setPreserveDataDir(boolean preserveDataDir) {
432+
this.preserveDataDir = preserveDataDir;
433+
}
434+
424435
@Override
425436
public void freeze() {
426437
requireNonNull(testDistribution, "null testDistribution passed when configuring test cluster `" + this + "`");
@@ -453,7 +464,13 @@ public synchronized void start() {
453464
logToProcessStdout("Configuring working directory: " + workingDir);
454465
// make sure we always start fresh
455466
if (Files.exists(workingDir)) {
456-
fileSystemOperations.delete(d -> d.delete(workingDir));
467+
if (preserveDataDir) {
468+
Files.list(workingDir)
469+
.filter(path -> path.equals(confPathData) == false)
470+
.forEach(path -> fileSystemOperations.delete(d -> d.delete(path)));
471+
} else {
472+
fileSystemOperations.delete(d -> d.delete(workingDir));
473+
}
457474
}
458475
isWorkingDirConfigured = true;
459476
}

buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public class RunTask extends DefaultTestClustersTask {
4646

4747
private Boolean debug = false;
4848

49+
private Boolean preserveData = false;
50+
4951
private Path dataDir = null;
5052

5153
private String keystorePassword = "";
@@ -65,6 +67,16 @@ public void setDataDir(String dataDirStr) {
6567
dataDir = Paths.get(dataDirStr).toAbsolutePath();
6668
}
6769

70+
@Input
71+
public Boolean getPreserveData() {
72+
return preserveData;
73+
}
74+
75+
@Option(option = "preserve-data", description = "Preserves data directory contents (path provided to --data-dir is always preserved)")
76+
public void setPreserveData(Boolean preserveData) {
77+
this.preserveData = preserveData;
78+
}
79+
6880
@Option(option = "keystore-password", description = "Set the elasticsearch keystore password")
6981
public void setKeystorePassword(String password) {
7082
keystorePassword = password;
@@ -113,6 +125,7 @@ public void beforeStart() {
113125
httpPort++;
114126
cluster.getFirstNode().setTransportPort(String.valueOf(transportPort));
115127
transportPort++;
128+
cluster.setPreserveDataDir(preserveData);
116129
for (ElasticsearchNode node : cluster.getNodes()) {
117130
additionalSettings.forEach(node::setting);
118131
if (dataDir != null) {

buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/StandaloneRestIntegTestTask.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ public StandaloneRestIntegTestTask() {
6666
.filter(task -> task != this)
6767
.anyMatch(task -> Collections.disjoint(task.getClusters(), getClusters()) == false)
6868
);
69+
70+
this.getOutputs()
71+
.doNotCacheIf(
72+
"Caching disabled for this task since it is configured to preserve data directory",
73+
// Don't cache the output of this task if it's not running from a clean data directory.
74+
t -> getClusters().stream().anyMatch(cluster -> cluster.isPreserveDataDir())
75+
);
6976
}
7077

7178
@Override

buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/TestClusterConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ public interface TestClusterConfiguration {
8787

8888
void jvmArgs(String... values);
8989

90+
boolean isPreserveDataDir();
91+
92+
void setPreserveDataDir(boolean preserveDataDir);
93+
9094
void freeze();
9195

9296
void start();

x-pack/plugin/eql/qa/correctness/README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ the queries and asserts the results that are provided along with the query state
1111
### Running the tests
1212

1313
To be able to run the tests locally, one should set the environmental variable `eql_test_credentials_file` pointing to
14-
a local file holding the service account credentials which allow access to the gcs bucket where the dataset resides.
14+
a local file holding the service account credentials which allow access to the gcs bucket where the dataset resides.
1515
E.g.:
1616
```shell script
1717
export eql_test_credentials_file=/Users/username/credentials.gcs.json
18-
```
18+
```
1919

2020
To run the tests you can issue:
2121
```shell script
@@ -46,7 +46,7 @@ queries executed, e.g.:*
4646

4747
#### Run a specific query
4848

49-
If one wants to run just one query from the set, needs to do it with following command by replacing `<queryNo>` (which
49+
If one wants to run just one query from the set, needs to do it with following command by replacing `<queryNo>` (which
5050
can be found in queries.toml file) with the desired number of the query:
5151

5252
```shell script
@@ -66,7 +66,7 @@ or
6666
./gradlew ':x-pack:plugin:eql:qa:correctness:javaRestTest' --tests "org.elasticsearch.xpack.eql.EsEQLCorrectnessIT.test {<queryNo>}" -Dtests.eql_correctness_debug=true
6767
```
6868

69-
### Run an ES node manually and run the tests against it
69+
### Run an ES node manually and run the tests against it
7070

7171
If one wants to run an ES node manually (most probably to be able to debug the server), needs to run the following:
7272

@@ -76,7 +76,7 @@ If one wants to run an ES node manually (most probably to be able to debug the s
7676

7777
**Set the `eql_test_credentials_file` environmental variable correctly in the shell before running the command above,**
7878

79-
Once the ES node is up and running, the data can be restored from the snapshot by running the `main` of the
79+
Once the ES node is up and running, the data can be restored from the snapshot by running the `main` of the
8080
`EqlDataLoader` class.
8181

8282
Once the data is loaded, a specific query can be run against the running ES node with:
@@ -85,3 +85,10 @@ Once the data is loaded, a specific query can be run against the running ES node
8585
```
8686

8787
**Set the `eql_test_credentials_file` environmental variable correctly in the shell before running the command above,**
88+
89+
#### Preserve data across node restarts
90+
If you'd like to preserve the restored index and avoid the network download and delay of restoring them on every run of the node,
91+
you can set the `eql.test.preserve.data` system property, e.g.:
92+
```shell script
93+
./gradlew :x-pack:plugin:eql:qa:correctness:javaRestTest -Deql.test.preserve.data=true
94+
```

x-pack/plugin/eql/qa/correctness/build.gradle

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,26 @@ dependencies {
2020
javaRestTestImplementation 'io.ous:jtoml:2.0.0'
2121
}
2222

23-
File serviceAccountFile = (System.getenv("eql_test_credentials_file") ?: System.getProperty("eql.test.credentials.file")) as File
23+
File serviceAccountFile = providers.environmentVariable('eql_test_credentials_file')
24+
.forUseAtConfigurationTime()
25+
.orElse(providers.systemProperty('eql.test.credentials.file').forUseAtConfigurationTime())
26+
.map { s -> new File(s)}
27+
.getOrNull()
28+
29+
Boolean preserveData = providers.systemProperty('eql.test.preserve.data')
30+
.forUseAtConfigurationTime()
31+
.map { s -> Boolean.parseBoolean(s) }
32+
.getOrElse(false)
2433

2534
testClusters {
2635
all {
2736
plugin ':plugins:repository-gcs'
2837
if (serviceAccountFile) {
2938
keystore 'gcs.client.eql_test.credentials_file', serviceAccountFile
3039
}
40+
if (preserveData) {
41+
preserveDataDir = true
42+
}
3143
testDistribution = 'DEFAULT'
3244
setting 'xpack.license.self_generated.type', 'basic'
3345
jvmArgs '-Xms4g', '-Xmx4g'
@@ -46,6 +58,6 @@ tasks.named('javaRestTest').configure {
4658
}
4759

4860
tasks.register("runEqlCorrectnessNode", RunTask) {
49-
useCluster testClusters.runTask;
61+
useCluster testClusters.runTask
5062
description = 'Runs elasticsearch in the foreground with gcs plugin and keystore credentials'
5163
}

0 commit comments

Comments
 (0)