/*
* Copyright 2011-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazonaws.services.stepfunctions.builder;
import static com.amazonaws.services.stepfunctions.builder.StatesAsserts.assertStateMachineMatches;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.and;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.branch;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.catcher;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.choice;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.choiceState;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.end;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.eq;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.failState;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.gt;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.gte;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.lt;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.lte;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.next;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.not;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.or;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.parallelState;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.passState;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.retrier;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.seconds;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.secondsPath;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.stateMachine;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.succeedState;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.taskState;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.timestamp;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.timestampPath;
import static com.amazonaws.services.stepfunctions.builder.StepFunctionBuilder.waitState;
import java.util.Date;
import org.joda.time.DateTime;
import org.junit.Test;
public class StepFunctionBuilderTest {
@Test
public void singleSucceedState() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.timeoutSeconds(30)
.comment("My Simple State Machine")
.state("InitialState", succeedState()
.comment("Initial State")
.inputPath("$.input")
.outputPath("$.output"))
.build();
assertStateMachineMatches("SingleSucceedState.json", stateMachine);
}
@Test
public void singleTaskState() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", taskState()
.comment("Initial State")
.timeoutSeconds(10)
.heartbeatSeconds(1)
.transition(next("NextState"))
.resource("resource-arn")
.inputPath("$.input")
.resultPath("$.result")
.outputPath("$.output"))
.state("NextState", succeedState())
.build();
assertStateMachineMatches("SimpleTaskState.json", stateMachine);
}
@Test
public void taskStateWithEnd() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", taskState()
.resource("resource-arn")
.transition(end()))
.build();
assertStateMachineMatches("TaskStateWithEnd.json", stateMachine);
}
@Test
public void singleTaskStateWithRetries() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", taskState()
.transition(next("NextState"))
.resource("resource-arn")
.retriers(retrier()
.errorEquals("Foo", "Bar")
.intervalSeconds(20)
.maxAttempts(3)
.backoffRate(2.0),
retrier()
.retryOnAllErrors()
.intervalSeconds(30)
.maxAttempts(10)
.backoffRate(2.0)))
.state("NextState", succeedState())
.build();
assertStateMachineMatches("SimpleTaskStateWithRetries.json", stateMachine);
}
@Test
public void singleTaskStateWithCatchers() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", taskState()
.transition(next("NextState"))
.resource("resource-arn")
.catchers(catcher()
.errorEquals("Foo", "Bar")
.transition(next("RecoveryState"))
.resultPath("$.result-path"),
catcher()
.catchAll()
.transition(next("OtherRecoveryState"))))
.state("NextState", succeedState())
.state("RecoveryState", succeedState())
.state("OtherRecoveryState", succeedState())
.build();
assertStateMachineMatches("SimpleTaskStateWithCatchers.json", stateMachine);
}
@Test
public void singlePassStateWithJsonResult() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", passState()
.comment("Pass through state")
.inputPath("$.input")
.outputPath("$.output")
.resultPath("$.result")
.transition(next("NextState"))
.result("{\"Foo\": \"Bar\"}"))
.state("NextState", succeedState())
.build();
assertStateMachineMatches("SinglePassStateWithJsonResult.json", stateMachine);
}
@Test
public void singlePassStateWithObjectResult() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", passState()
.transition(end())
.result(new SimplePojo("value")))
.build();
assertStateMachineMatches("SinglePassStateWithObjectResult.json", stateMachine);
}
@Test
public void singleWaitState_WaitForSeconds() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", waitState()
.comment("My wait state")
.inputPath("$.input")
.outputPath("$.output")
.waitFor(seconds(10))
.transition(next("NextState")))
.state("NextState", succeedState())
.build();
assertStateMachineMatches("SingleWaitStateWithSeconds.json", stateMachine);
}
@Test
public void singleWaitState_WaitUntilSecondsPath() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", waitState()
.waitFor(secondsPath("$.seconds"))
.transition(end()))
.build();
assertStateMachineMatches("SingleWaitStateWithSecondsPath.json", stateMachine);
}
@Test
public void singleWaitState_WaitUntilTimestamp() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", waitState()
.waitFor(timestamp(DateTime.parse("2016-03-14T01:59:00Z").toDate()))
.transition(end()))
.build();
assertStateMachineMatches("SingleWaitStateWithTimestamp.json", stateMachine);
}
@Test
public void singleWaitState_WaitUntilTimestampWithMillisecond() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", waitState()
.waitFor(timestamp(DateTime.parse("2016-03-14T01:59:00.123Z").toDate()))
.transition(end()))
.build();
assertStateMachineMatches("SingleWaitStateWithTimestampWithMilliseconds.json", stateMachine);
}
@Test
public void singleWaitState_WaitUntilTimestampWithTimezone() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", waitState()
.waitFor(timestamp(DateTime.parse("2016-03-14T01:59:00.123-08:00").toDate()))
.transition(end()))
.build();
assertStateMachineMatches("SingleWaitStateWithTimestampWithTimezone.json", stateMachine);
}
@Test
public void singleWaitState_WaitUntilTimestampWithPath() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", waitState()
.waitFor(timestampPath("$.timestamp"))
.transition(end()))
.build();
assertStateMachineMatches("SingleWaitStateWithTimestampWithPath.json", stateMachine);
}
@Test
public void singleFailState() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", failState()
.comment("My fail state")
.cause("InternalError")
.error("java.lang.Exception"))
.build();
assertStateMachineMatches("SingleFailState.json", stateMachine);
}
@Test
public void simpleChoiceState() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.comment("My choice state")
.defaultStateName("DefaultState")
.inputPath("$.input")
.outputPath("$.output")
.choice(choice().transition(next("NextState"))
.condition(eq("$.var", "value"))))
.state("NextState", succeedState())
.state("DefaultState", succeedState())
.build();
assertStateMachineMatches("SimpleChoiceState.json", stateMachine);
}
@Test
public void choiceStateWithMultipleChoices() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.defaultStateName("DefaultState")
.choices(
choice().transition(next("NextState"))
.condition(eq("$.var", "value")),
choice().transition(next("OtherNextState"))
.condition(gt("$.number", 10))))
.state("NextState", succeedState())
.state("OtherNextState", succeedState())
.state("DefaultState", succeedState())
.build();
assertStateMachineMatches("ChoiceStateWithMultipleChoices.json", stateMachine);
}
@Test
public void choiceStateWithAndCondition() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.defaultStateName("DefaultState")
.choice(choice().transition(next("NextState"))
.condition(
and(eq("$.var", "value"),
eq("$.other-var", 10)
))))
.state("NextState", succeedState())
.state("DefaultState", succeedState())
.build();
assertStateMachineMatches("ChoiceStateWithAndCondition.json", stateMachine);
}
@Test
public void choiceStateWithOrCondition() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.defaultStateName("DefaultState")
.choice(choice().transition(next("NextState"))
.condition(
or(gt("$.var", "value"),
lte("$.other-var", 10)
))))
.state("NextState", succeedState())
.state("DefaultState", succeedState())
.build();
assertStateMachineMatches("ChoiceStateWithOrCondition.json", stateMachine);
}
@Test
public void choiceStateWithNotCondition() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.defaultStateName("DefaultState")
.choice(choice().transition(next("NextState"))
.condition(not(gte("$.var", "value")))))
.state("NextState", succeedState())
.state("DefaultState", succeedState())
.build();
assertStateMachineMatches("ChoiceStateWithNotCondition.json", stateMachine);
}
@Test
public void choiceStateWithComplexCondition() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.defaultStateName("DefaultState")
.choice(choice().transition(next("NextState"))
.condition(and(
gte("$.var", "value"),
lte("$.other-var", "foo"),
or(
lt("$.numeric", 9000.1),
not(gte("$.numeric", 42))
)
))))
.state("NextState", succeedState())
.state("DefaultState", succeedState())
.build();
assertStateMachineMatches("ChoiceStateWithComplexCondition.json", stateMachine);
}
@Test
public void choiceStateWithAllPrimitiveConditions() {
final Date date = DateTime.parse("2016-03-14T01:59:00.000Z").toDate();
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.defaultStateName("DefaultState")
.choice(choice().transition(next("NextState"))
.condition(and(
eq("$.string", "value"),
gt("$.string", "value"),
gte("$.string", "value"),
lt("$.string", "value"),
lte("$.string", "value"),
eq("$.integral", 42),
gt("$.integral", 42),
gte("$.integral", 42),
lt("$.integral", 42),
lte("$.integral", 42),
eq("$.double", 9000.1),
gt("$.double", 9000.1),
gte("$.double", 9000.1),
lt("$.double", 9000.1),
lte("$.double", 9000.1),
eq("$.timestamp", date),
gt("$.timestamp", date),
gte("$.timestamp", date),
lt("$.timestamp", date),
lte("$.timestamp", date),
eq("$.boolean", true),
eq("$.boolean", false)
))))
.state("NextState", succeedState())
.state("DefaultState", succeedState())
.build();
assertStateMachineMatches("ChoiceStateWithAllPrimitiveCondition.json", stateMachine);
}
@Test
public void simpleParallelState() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", parallelState()
.comment("My parallel state")
.inputPath("$.input")
.outputPath("$.output")
.resultPath("$.result")
.transition(next("NextState"))
.branches(
branch()
.comment("Branch one")
.startAt("BranchOneInitial")
.state("BranchOneInitial", succeedState()),
branch()
.comment("Branch two")
.startAt("BranchTwoInitial")
.state("BranchTwoInitial", succeedState())
))
.state("NextState", succeedState())
.build();
assertStateMachineMatches("SimpleParallelState.json", stateMachine);
}
@Test
public void parallelStateWithRetriers() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", parallelState()
.transition(end())
.branches(
branch()
.comment("Branch one")
.startAt("BranchOneInitial")
.state("BranchOneInitial", succeedState()),
branch()
.comment("Branch two")
.startAt("BranchTwoInitial")
.state("BranchTwoInitial", succeedState())
)
.retriers(retrier()
.errorEquals("Foo", "Bar")
.intervalSeconds(10)
.backoffRate(1.0)
.maxAttempts(3),
retrier()
.retryOnAllErrors()
.intervalSeconds(10)
.backoffRate(1.0)
.maxAttempts(3)
))
.build();
assertStateMachineMatches("ParallelStateWithRetriers.json", stateMachine);
}
@Test
public void parallelStateWithCatchers() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", parallelState()
.transition(end())
.branches(
branch()
.comment("Branch one")
.startAt("BranchOneInitial")
.state("BranchOneInitial", succeedState()),
branch()
.comment("Branch two")
.startAt("BranchTwoInitial")
.state("BranchTwoInitial", succeedState())
)
.catchers(catcher()
.errorEquals("Foo", "Bar")
.transition(next("RecoveryState"))
.resultPath("$.result"),
catcher()
.catchAll()
.transition(next("OtherRecoveryState"))
.resultPath("$.result")
))
.state("RecoveryState", succeedState())
.state("OtherRecoveryState", succeedState())
.build();
assertStateMachineMatches("ParallelStateWithCatchers.json", stateMachine);
}
@Test
public void choiceStateWithEmptyStringInExpectedValue_DoesNotExcludeExpectedValueFromJson() {
final StateMachine stateMachine = stateMachine()
.startAt("InitialState")
.state("InitialState", choiceState()
.comment("My choice state")
.choice(choice().transition(next("FinalState"))
.condition(eq("$.var", ""))))
.state("FinalState", succeedState())
.build();
assertStateMachineMatches("ChoiceStateWithEmptyStringInExpectedValue.json", stateMachine);
}
@Test(expected = Exception.class)
public void stateMachineFromJson_MalformedJson_ThrowsException() {
StateMachine.fromJson("{");
}
}