add Rest tests to index-lifecycle (#30159)

* add QA-style Rest tests to index-lifecycle

This PR introduces a `qa` module within the index-lifecycle project.

the idea is to have both complex policies tested, as well as
policies with isolated/singular actions. So far, only tests with policies
containing one action are implemented.

Following Actions have implemented tests in this commit

- AllocateAction
- DeleteAction
- ForceMergeAction
- ReadOnlyAction
- ReplicasAction

tests to be added later

- RolloverAction
- ShrinkAction

* respond to review and enable integTests

* fix dependsOn fiasco

* fix license

* update to new proj structure

* move to new integTest with x-pack-core as module

* remove unused imports

* update to use module instead of plugin
This commit is contained in:
Tal Levy 2018-05-17 06:17:15 -07:00 committed by GitHub
parent 4e757fff21
commit 2814557679
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 177 additions and 5 deletions

View File

@ -1,6 +1,7 @@
evaluationDependsOn(xpackModule('core'))
apply plugin: 'elasticsearch.esplugin'
esplugin {
name 'x-pack-index-lifecycle'
description 'Elasticsearch Expanded Pack Plugin - Index Lifecycle'
@ -11,16 +12,23 @@ esplugin {
}
archivesBaseName = 'x-pack-index-lifecycle'
// TODO: enable this once we have tests
licenseHeaders.enabled = false
integTest.enabled = false
dependencies {
compileOnly "org.elasticsearch.plugin:x-pack-core:${version}"
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
}
integTestCluster {
numNodes = 2
clusterName = 'index-lifecycle'
setting 'xpack.security.enabled', 'false'
setting 'xpack.watcher.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'
setting 'xpack.ml.enabled', 'false'
setting 'xpack.index_lifecycle.enabled', 'true'
setting 'indices.lifecycle.poll_interval', '500ms'
module project(xpackModule('core'))
}
run {
plugin xpackModule('core')
}

View File

@ -0,0 +1,164 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.indexlifecycle;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.AllocateAction;
import org.elasticsearch.xpack.core.indexlifecycle.DeleteAction;
import org.elasticsearch.xpack.core.indexlifecycle.ForceMergeAction;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.ReadOnlyAction;
import org.elasticsearch.xpack.core.indexlifecycle.ReplicasAction;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep;
import org.elasticsearch.xpack.core.indexlifecycle.TimeseriesLifecycleType;
import org.junit.Before;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
public class TimeSeriesLifecycleActionsIT extends ESRestTestCase {
private String index;
private String policy;
@Before
public void refreshIndex() {
index = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
policy = randomAlphaOfLength(5);
}
public void testAllocate() throws Exception {
createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 2)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0));
String allocateNodeName = "node-" + randomFrom(0, 1);
AllocateAction allocateAction = new AllocateAction(null, null, singletonMap("_name", allocateNodeName));
createNewSingletonPolicy("warm", allocateAction);
updateIndexSettings(index, Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policy));
assertBusy(() -> {
Map<String, Object> settings = getOnlyIndexSettings(index);
assertThat(getStepKey(settings), equalTo(TerminalPolicyStep.KEY));
});
ensureGreen(index);
}
public void testDelete() throws Exception {
createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0));
createNewSingletonPolicy("delete", new DeleteAction());
updateIndexSettings(index, Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policy));
assertBusy(() -> assertFalse(indexExists(index)));
}
public void testReadOnly() throws Exception {
createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0));
createNewSingletonPolicy("warm", new ReadOnlyAction());
updateIndexSettings(index, Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policy));
assertBusy(() -> {
Map<String, Object> settings = getOnlyIndexSettings(index);
assertThat(getStepKey(settings), equalTo(TerminalPolicyStep.KEY));
assertThat(settings.get(IndexMetaData.INDEX_BLOCKS_WRITE_SETTING.getKey()), equalTo("true"));
});
}
@SuppressWarnings("unchecked")
public void testForceMergeAction() throws Exception {
createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0));
for (int i = 0; i < randomIntBetween(2, 10); i++) {
client().performRequest("PUT", index + "/_doc/" + i, singletonMap("refresh", "true"),
new StringEntity("{\"a\": \"test\"}", ContentType.APPLICATION_JSON));
}
Supplier<Integer> numSegments = () -> {
try {
Map<String, Object> segmentResponse = getAsMap(index + "/_segments");
segmentResponse = (Map<String, Object>) segmentResponse.get("indices");
segmentResponse = (Map<String, Object>) segmentResponse.get(index);
segmentResponse = (Map<String, Object>) segmentResponse.get("shards");
List<Map<String, Object>> shards = (List<Map<String, Object>>) segmentResponse.get("0");
return (Integer) shards.get(0).get("num_search_segments");
} catch (Exception e) {
throw new RuntimeException(e);
}
};
assertThat(numSegments.get(), greaterThan(1));
createNewSingletonPolicy("warm", new ForceMergeAction(1, false));
updateIndexSettings(index, Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policy));
assertBusy(() -> {
assertThat(getStepKey(getOnlyIndexSettings(index)), equalTo(TerminalPolicyStep.KEY));
assertThat(numSegments.get(), equalTo(1));
});
}
public void testReplicasAction() throws Exception {
int numShards = randomFrom(1, 5);
int numReplicas = randomFrom(0, 1);
int finalNumReplicas = (numReplicas + 1) % 2;
createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numShards)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numReplicas));
createNewSingletonPolicy("warm", new ReplicasAction(finalNumReplicas));
updateIndexSettings(index, Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policy));
assertBusy(() -> {
Map<String, Object> settings = getOnlyIndexSettings(index);
assertThat(getStepKey(settings), equalTo(TerminalPolicyStep.KEY));
assertThat(settings.get(IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey()), equalTo(String.valueOf(finalNumReplicas)));
});
}
private void createNewSingletonPolicy(String phaseName, LifecycleAction action) throws IOException {
Phase phase = new Phase(phaseName, TimeValue.ZERO, singletonMap(action.getWriteableName(), action));
LifecyclePolicy lifecyclePolicy =
new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, policy, singletonMap(phase.getName(), phase));
XContentBuilder builder = jsonBuilder();
lifecyclePolicy.toXContent(builder, null);
final StringEntity entity = new StringEntity(
"{ \"policy\":" + Strings.toString(builder) + "}", ContentType.APPLICATION_JSON);
client().performRequest("PUT", "_xpack/index_lifecycle/" + policy, Collections.emptyMap(), entity);
}
private void createIndexWithSettings(String index, Settings.Builder settings) throws IOException {
// create the test-index index
createIndex(index, settings.build());
// wait for the shards to initialize
ensureGreen(index);
}
@SuppressWarnings("unchecked")
private Map<String, Object> getOnlyIndexSettings(String index) throws IOException {
return (Map<String, Object>) ((Map<String, Object>) getIndexSettings(index).get(index)).get("settings");
}
private StepKey getStepKey(Map<String, Object> settings) {
String phase = (String) settings.get(LifecycleSettings.LIFECYCLE_PHASE);
String action = (String) settings.get(LifecycleSettings.LIFECYCLE_ACTION);
String step = (String) settings.get(LifecycleSettings.LIFECYCLE_STEP);
return new StepKey(phase, action, step);
}
}