add tests for ExecuteStepsUpdateTask

This commit is contained in:
Tal Levy 2018-04-04 15:32:36 -07:00
parent a8dc8a7c98
commit 55d2a62fec
9 changed files with 229 additions and 96 deletions

View File

@ -143,7 +143,11 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
List<Step> steps = new ArrayList<>();
List<Phase> orderedPhases = type.getOrderedPhases(phases);
ListIterator<Phase> phaseIterator = orderedPhases.listIterator(orderedPhases.size());
Step.StepKey lastStepKey = null;
// final step so that policy can properly update cluster-state with last action completed
steps.add(TerminalPolicyStep.INSTANCE);
Step.StepKey lastStepKey = TerminalPolicyStep.KEY;
// add steps for each phase, in reverse
while (phaseIterator.hasPrevious()) {
Phase phase = phaseIterator.previous();
@ -162,14 +166,15 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
}
// add `after` step for phase
Step.StepKey afterStepKey = new Step.StepKey(phase.getName(), null, "after");
Step.StepKey afterStepKey = new Step.StepKey(phase.getName(), "pre-action", "after");
Step phaseAfterStep = new PhaseAfterStep(nowSupplier, phase.getAfter(), afterStepKey, lastStepKey);
steps.add(phaseAfterStep);
lastStepKey = phaseAfterStep.getKey();
}
// init step so that policy is guaranteed to have
steps.add(new InitializePolicyContextStep(new Step.StepKey("", "", ""), lastStepKey));
steps.add(new InitializePolicyContextStep(
new Step.StepKey("pre-phase", "pre-action", "init"), lastStepKey));
Collections.reverse(steps);
logger.error("STEP COUNT: " + steps.size());

View File

@ -0,0 +1,23 @@
/*
* 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.core.indexlifecycle;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.index.Index;
public class TerminalPolicyStep extends ClusterStateActionStep {
public static final StepKey KEY = new StepKey("completed", "completed", "completed");
public static final TerminalPolicyStep INSTANCE = new TerminalPolicyStep(KEY, null);
private TerminalPolicyStep(StepKey key, StepKey nextStepKey) {
super(key, nextStepKey);
}
@Override
public ClusterState performAction(Index index, ClusterState clusterState) {
return clusterState;
}
}

View File

@ -17,25 +17,26 @@ import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class MockAction implements LifecycleAction {
public static final String NAME = "TEST_ACTION";
private final List<MockStep> steps;
private List<Step> steps;
private static final ConstructingObjectParser<MockAction, Void> PARSER = new ConstructingObjectParser<>(NAME,
a -> new MockAction((List<MockStep>) a[0]));
static {
PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), MockStep.PARSER, new ParseField("steps"));
}
private static final ObjectParser<MockAction, Void> PARSER = new ObjectParser<>(NAME, MockAction::new);
public static MockAction parse(XContentParser parser) {
return PARSER.apply(parser, null);
}
public MockAction(List<MockStep> steps) {
public MockAction() {
this.steps = Collections.emptyList();
}
public MockAction(List<Step> steps) {
this.steps = steps;
}
@ -46,11 +47,6 @@ public class MockAction implements LifecycleAction {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.startArray("steps");
for (MockStep step : steps) {
step.toXContent(builder, params);
}
builder.endArray();
builder.endObject();
return builder;
}
@ -60,7 +56,7 @@ public class MockAction implements LifecycleAction {
return NAME;
}
public List<MockStep> getSteps() {
public List<Step> getSteps() {
return steps;
}
@ -71,7 +67,7 @@ public class MockAction implements LifecycleAction {
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeList(steps);
out.writeList(steps.stream().map(MockStep::new).collect(Collectors.toList()));
}
@Override
@ -90,9 +86,4 @@ public class MockAction implements LifecycleAction {
MockAction other = (MockAction) obj;
return Objects.equals(steps, other.steps);
}
@Override
public String toString() {
return Strings.toString(this, true, true);
}
}

View File

@ -33,8 +33,8 @@ public class MockActionTests extends AbstractSerializingTestCase<MockAction> {
@Override
protected MockAction mutateInstance(MockAction instance) throws IOException {
List<MockStep> steps = new ArrayList<>(instance.getSteps());
MockStep lastStep = steps.remove(steps.size() - 1);
List<Step> steps = new ArrayList<>(instance.getSteps());
Step lastStep = steps.remove(steps.size() - 1);
if (randomBoolean()) {
Step.StepKey additionalStepKey = randomStepKey();
steps.add(new MockStep(lastStep.getKey(), additionalStepKey));
@ -45,7 +45,7 @@ public class MockActionTests extends AbstractSerializingTestCase<MockAction> {
// TODO(talevy): design this in a way that we can build up a proper LifecyclePolicy where the steps connect
public static MockAction randomMockAction(@Nullable Step.StepKey nextExternalStepKey) {
List<MockStep> steps = new ArrayList<>();
List<Step> steps = new ArrayList<>();
int stepCount = randomIntBetween(2, 10);
Step.StepKey currentStepKey = randomStepKey();
Step.StepKey nextStepKey;

View File

@ -5,38 +5,23 @@
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
public class MockStep extends Step implements ToXContent, Writeable {
public class MockStep extends Step implements Writeable {
public static final String NAME = "TEST_STEP";
static final ConstructingObjectParser<MockStep, Void> PARSER = new ConstructingObjectParser<>(NAME,
a -> new MockStep((StepKey) a[0], (StepKey) a[1]));
private static final ConstructingObjectParser<StepKey, Void> KEY_PARSER = new ConstructingObjectParser<>("TEST_KEY",
a -> new StepKey((String) a[0], (String) a[1], (String) a[2]));
static {
KEY_PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("phase"));
KEY_PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("action"));
KEY_PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("name"));
PARSER.declareObject(ConstructingObjectParser.constructorArg(), KEY_PARSER::apply,
new ParseField("step_key"));
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), KEY_PARSER::apply,
new ParseField("next_step_key"));
}
public MockStep(StepKey stepKey, Step.StepKey nextStepKey) {
super(stepKey, nextStepKey);
}
public MockStep(Step other) {
super(other.getKey(), other.getNextStepKey());
}
public MockStep(StreamInput in) throws IOException {
super(new StepKey(in.readString(), in.readString(), in.readString()), readOptionalNextStepKey(in));
}
@ -61,35 +46,4 @@ public class MockStep extends Step implements ToXContent, Writeable {
out.writeString(getNextStepKey().getName());
}
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
{
builder.startObject("step_key");
{
builder.field("phase", getKey().getPhase());
builder.field("action", getKey().getAction());
builder.field("name", getKey().getName());
}
builder.endObject();
if (getNextStepKey() != null) {
builder.startObject("next_step_key");
{
builder.field("phase", getNextStepKey().getPhase());
builder.field("action", getNextStepKey().getAction());
builder.field("name", getNextStepKey().getName());
}
builder.endObject();
}
}
builder.endObject();
return builder;
}
@Override
public String toString() {
return Strings.toString(this, true, true);
}
}

View File

@ -56,6 +56,9 @@ public class ExecuteStepsUpdateTask extends ClusterStateUpdateTask {
// move
// the cluster state to the next step
currentState = ((ClusterStateActionStep) currentStep).performAction(index, currentState);
if (currentStep.getNextStepKey() == null) {
return currentState;
}
currentState = IndexLifecycleRunner.moveClusterStateToNextStep(index, currentState, currentStep.getNextStepKey());
} else {
// cluster state wait step so evaluate the
@ -66,6 +69,9 @@ public class ExecuteStepsUpdateTask extends ClusterStateUpdateTask {
// condition again
boolean complete = ((ClusterStateWaitStep) currentStep).isConditionMet(index, currentState);
if (complete) {
if (currentStep.getNextStepKey() == null) {
return currentState;
}
currentState = IndexLifecycleRunner.moveClusterStateToNextStep(index, currentState, currentStep.getNextStepKey());
} else {
logger.warn("condition not met, returning existing state");

View File

@ -5,16 +5,159 @@
*/
package org.elasticsearch.xpack.indexlifecycle;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.Index;
import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.MockAction;
import org.elasticsearch.xpack.core.indexlifecycle.MockStep;
import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.Step;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep;
import org.elasticsearch.xpack.core.indexlifecycle.TestLifecycleType;
import static org.elasticsearch.xpack.indexlifecycle.IndexLifecycleRunnerTests.MockClusterStateActionStep;
import static org.elasticsearch.xpack.indexlifecycle.IndexLifecycleRunnerTests.MockClusterStateWaitStep;
import static org.hamcrest.Matchers.equalTo;
import org.junit.Before;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ExecuteStepsUpdateTaskTests extends ESTestCase {
private static final StepKey firstStepKey = new StepKey("phase_1", "action_1", "step_1");
private static final StepKey secondStepKey = new StepKey("phase_1", "action_1", "step_2");
private static final StepKey thirdStepKey = new StepKey("phase_1", "action_1", "step_3");
private ClusterState clusterState;
private PolicyStepsRegistry policyStepsRegistry;
private String mixedPolicyName;
private String allClusterPolicyName;
private Index index;
private MockClusterStateActionStep firstStep;
private MockClusterStateWaitStep secondStep;
private MockClusterStateWaitStep allClusterSecondStep;
private MockStep thirdStep;
@Before
public void prepareServices() {
public void prepareState() {
firstStep = new MockClusterStateActionStep(firstStepKey, secondStepKey);
secondStep = new MockClusterStateWaitStep(secondStepKey, thirdStepKey);
secondStep.setWillComplete(true);
allClusterSecondStep = new MockClusterStateWaitStep(secondStepKey, TerminalPolicyStep.KEY);
allClusterSecondStep.setWillComplete(true);
thirdStep = new MockStep(thirdStepKey, null);
mixedPolicyName = randomAlphaOfLengthBetween(5, 10);
allClusterPolicyName = randomAlphaOfLengthBetween(1, 4);
Phase mixedPhase = new Phase("first_phase", TimeValue.ZERO, Collections.singletonMap(MockAction.NAME,
new MockAction(Arrays.asList(firstStep, secondStep, thirdStep))));
Phase allClusterPhase = new Phase("first_phase", TimeValue.ZERO, Collections.singletonMap(MockAction.NAME,
new MockAction(Arrays.asList(firstStep, allClusterSecondStep))));
LifecyclePolicy mixedPolicy = new LifecyclePolicy(TestLifecycleType.INSTANCE, mixedPolicyName,
Collections.singletonMap(mixedPhase.getName(), mixedPhase));
LifecyclePolicy allClusterPolicy = new LifecyclePolicy(TestLifecycleType.INSTANCE, allClusterPolicyName,
Collections.singletonMap(allClusterPhase.getName(), allClusterPhase));
Map<String, LifecyclePolicy> policyMap = new HashMap<>();
policyMap.put(mixedPolicyName, mixedPolicy);
policyMap.put(allClusterPolicyName, allClusterPolicy);
policyStepsRegistry = new PolicyStepsRegistry();
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT)
.put(LifecycleSettings.LIFECYCLE_NAME, mixedPolicyName)
.put(LifecycleSettings.LIFECYCLE_PHASE, "pre-phase")
.put(LifecycleSettings.LIFECYCLE_ACTION, "pre-action")
.put(LifecycleSettings.LIFECYCLE_STEP, "init"))
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
index = indexMetadata.getIndex();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap))
.put(IndexMetaData.builder(indexMetadata))
.build();
String nodeId = randomAlphaOfLength(10);
DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT)
.put(Node.NODE_MASTER_SETTING.getKey(), true).build(),
new TransportAddress(TransportAddress.META_ADDRESS, 9300), nodeId);
clusterState = ClusterState.builder(ClusterName.DEFAULT)
.metaData(metaData)
.nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build())
.build();
policyStepsRegistry.update(clusterState, null, () -> 0L);
}
public void test() {
// TODO: stub
public void testExecuteAllUntilEndOfPolicy() {
Step startStep = policyStepsRegistry.getFirstStep(allClusterPolicyName);
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(allClusterPolicyName, index, startStep, policyStepsRegistry);
ClusterState newState = task.execute(clusterState);
assertThat(firstStep.getExecuteCount(), equalTo(1L));
assertThat(allClusterSecondStep.getExecuteCount(), equalTo(1L));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(newState.metaData().index(index).getSettings());
assertThat(currentStepKey, equalTo(TerminalPolicyStep.KEY));
}
public void testExecuteMoveToNextActionStep() {
secondStep.setWillComplete(false);
Step startStep = policyStepsRegistry.getFirstStep(mixedPolicyName);
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry);
ClusterState newState = task.execute(clusterState);
assertThat(firstStep.getExecuteCount(), equalTo(1L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(newState.metaData().index(index).getSettings());
assertThat(currentStepKey, equalTo(secondStepKey));
}
public void testNeverExecuteNonClusterStateStep() {
setStateToKey(thirdStepKey);
Step startStep = policyStepsRegistry.getStep(mixedPolicyName, thirdStepKey);
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry);
assertThat(task.execute(clusterState), equalTo(clusterState));
}
public void testExecuteUntilFirstNonClusterStateStep() {
setStateToKey(secondStepKey);
Step startStep = policyStepsRegistry.getStep(mixedPolicyName, secondStepKey);
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry);
ClusterState newState = task.execute(clusterState);
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(newState.metaData().index(index).getSettings());
assertThat(currentStepKey, equalTo(thirdStepKey));
assertThat(firstStep.getExecuteCount(), equalTo(0L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));
}
public void testExecuteIncompleteWaitStep() {
secondStep.setWillComplete(false);
setStateToKey(secondStepKey);
Step startStep = policyStepsRegistry.getStep(mixedPolicyName, secondStepKey);
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry);
ClusterState newState = task.execute(clusterState);
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(newState.metaData().index(index).getSettings());
assertThat(currentStepKey, equalTo(secondStepKey));
assertThat(firstStep.getExecuteCount(), equalTo(0L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));
}
private void setStateToKey(StepKey stepKey) {
clusterState = ClusterState.builder(clusterState)
.metaData(MetaData.builder(clusterState.metaData())
.updateSettings(Settings.builder()
.put(LifecycleSettings.LIFECYCLE_PHASE, stepKey.getPhase())
.put(LifecycleSettings.LIFECYCLE_ACTION, stepKey.getAction())
.put(LifecycleSettings.LIFECYCLE_STEP, stepKey.getName()).build(), index.getName())).build();
}
}

View File

@ -31,6 +31,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.function.Supplier;
public class IndexLifecycleRunnerTests extends ESTestCase {
@ -582,9 +583,9 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
}
private static class MockClusterStateActionStep extends ClusterStateActionStep {
static class MockClusterStateActionStep extends ClusterStateActionStep {
private Exception exception;
private RuntimeException exception;
private boolean willComplete;
private long executeCount = 0;
@ -592,7 +593,7 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
super(key, nextStepKey);
}
public void setException(Exception exception) {
public void setException(RuntimeException exception) {
this.exception = exception;
}
@ -606,14 +607,18 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
@Override
public ClusterState performAction(Index index, ClusterState clusterState) {
return null;
executeCount++;
if (exception != null) {
throw exception;
}
return clusterState;
}
}
private static class MockClusterStateWaitStep extends ClusterStateWaitStep {
static class MockClusterStateWaitStep extends ClusterStateWaitStep {
private Exception exception;
private RuntimeException exception;
private boolean willComplete;
private long executeCount = 0;
@ -621,7 +626,7 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
super(key, nextStepKey);
}
public void setException(Exception exception) {
public void setException(RuntimeException exception) {
this.exception = exception;
}
@ -635,7 +640,11 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
@Override
public boolean isConditionMet(Index index, ClusterState clusterState) {
return false;
executeCount++;
if (exception != null) {
throw exception;
}
return willComplete;
}
}

View File

@ -25,6 +25,7 @@ import org.elasticsearch.xpack.core.indexlifecycle.MockStep;
import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseAfterStep;
import org.elasticsearch.xpack.core.indexlifecycle.Step;
import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep;
import org.elasticsearch.xpack.core.indexlifecycle.TestLifecycleType;
import org.elasticsearch.xpack.core.indexlifecycle.TimeseriesLifecycleType;
@ -133,10 +134,10 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
List<Step> steps = policy.toSteps(client, nowSupplier);
assertThat(steps.size(), equalTo(3));
assertThat(steps.get(0).getKey(), equalTo(new Step.StepKey("", "", "")));
assertThat(steps.get(0).getNextStepKey(), equalTo(new Step.StepKey("test", null, "after")));
assertThat(steps.get(1).getKey(), equalTo(new Step.StepKey("test", null, "after")));
assertThat(steps.size(), equalTo(4));
assertThat(steps.get(0).getKey(), equalTo(new Step.StepKey("pre-phase", "pre-action", "init")));
assertThat(steps.get(0).getNextStepKey(), equalTo(new Step.StepKey("test", "pre-action", "after")));
assertThat(steps.get(1).getKey(), equalTo(new Step.StepKey("test", "pre-action", "after")));
assertThat(steps.get(1).getNextStepKey(), equalTo(firstStep.getKey()));
assertThat(steps.get(2), equalTo(firstStep));
assertNull(steps.get(2).getNextStepKey());
@ -146,11 +147,11 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
Client client = mock(Client.class);
LongSupplier nowSupplier = () -> 0L;
MockStep secondActionStep = new MockStep(new Step.StepKey("second_phase", "test", "test"), null);
MockStep secondAfter = new MockStep(new Step.StepKey("second_phase", null, "after"), secondActionStep.getKey());
MockStep secondAfter = new MockStep(new Step.StepKey("second_phase", "pre-action", "after"), secondActionStep.getKey());
MockStep firstActionAnotherStep = new MockStep(new Step.StepKey("first_phase", "test", "test"), secondAfter.getKey());
MockStep firstActionStep = new MockStep(new Step.StepKey("first_phase", "test", "test"), firstActionAnotherStep.getKey());
MockStep firstAfter = new MockStep(new Step.StepKey("first_phase", null, "after"), firstActionStep.getKey());
MockStep init = new MockStep(new Step.StepKey("", "", ""), firstAfter.getKey());
MockStep firstAfter = new MockStep(new Step.StepKey("first_phase", "pre-action", "after"), firstActionStep.getKey());
MockStep init = new MockStep(new Step.StepKey("pre-phase", "pre-action", "init"), firstAfter.getKey());
lifecycleName = randomAlphaOfLengthBetween(1, 20);
Map<String, Phase> phases = new LinkedHashMap<>();
@ -165,7 +166,7 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
List<Step> steps = policy.toSteps(client, nowSupplier);
assertThat(steps.size(), equalTo(6));
assertThat(steps.size(), equalTo(7));
assertThat(steps.get(0).getClass(), equalTo(InitializePolicyContextStep.class));
assertThat(steps.get(0).getKey(), equalTo(init.getKey()));
assertThat(steps.get(0).getNextStepKey(), equalTo(init.getNextStepKey()));
@ -178,5 +179,6 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
assertThat(steps.get(4).getKey(), equalTo(secondAfter.getKey()));
assertThat(steps.get(4).getNextStepKey(), equalTo(secondAfter.getNextStepKey()));
assertThat(steps.get(5), equalTo(secondActionStep));
assertThat(steps.get(6).getClass(), equalTo(TerminalPolicyStep.class));
}
}