Skip to content
This repository was archived by the owner on Aug 7, 2025. It is now read-only.
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
367 changes: 367 additions & 0 deletions content/en/user-guide/aws/stepfunctions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,373 @@ LocalStack's Step Functions emulation supports the following AWS services:
| | AWS Batch | ✓ | ✓ | | |
| AWS SDK integrations | All LocalStack services | ✓ | | | ✓ |

## Mocked Service Integrations

Mocked service integrations allow you to test AWS Step Functions without calling LocalStack's emulated AWS services.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be helpful to link the AWS documentation from StepFunctions Local here? https://docs.aws.amazon.com/step-functions/latest/dg/sfn-local-test-sm-exec.html
Knowing that we are providing a drop-in replacement seems pretty relevant here, given that it was one of the primary reasons why we built this feature.

(or their announcement blog: https://aws.amazon.com/blogs/compute/mocking-service-integrations-with-aws-step-functions-local/)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely; I added a Compatibility with AWS Step Functions Local paragraph

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done highlighting the strengths of LocalStack beyond what SFN local can provide 👏 🥇

Instead, Task states return predefined outputs from a mock configuration file.
They key components are:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: The


- **Mocked service integrations**: Task states that return predefined responses instead of invoking local AWS services.
- **Mocked responses**: Static payloads associated with mocked Task states.
- **Test cases**: State machine executions using mocked responses.
- **Mock configuration file**: JSON file that defines test cases, mocked states, and their response payloads.

During execution, each Task state defined in the mock file returns its corresponding mocked response.
States not listed continue to invoke their real emulated services, allowing a mix of mocked and live interactions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: great clarification ✨


You can provide one or more mocked payloads per Task state.
Supported patterns include `.sync`, `.sync2`, and `.waitForTaskToken`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The supported ...

Both success and failure scenarios can be simulated.

{{< callout >}}
LocalStack does not validate response formats.
Ensure the payload structure matches what the real service expects.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we clarify?

payload structure in the mocked responses matches

{{< /callout >}}

### Identify a State Machine for Mocked Integrations

Mocked service integrations apply to specific state machine definitions.
The first step is to select the state machine where mocked responses will be used.

In this example, the `LambdaSQSIntegration` state machine will be used with the following definition:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearer: state machine with the name LambdaSQSIntegration


```json
{
"Comment":"This state machine is called: LambdaSQSIntegration",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Would a whitespace between : and " make it slightly more readable (feel free to ignore if this is rendered differently anyways). Just noticed that whitespacing is inconsistent through the JSON samples.

"QueryLanguage":"JSONata",
"StartAt":"LambdaState",
"States":{
"LambdaState":{
"Type":"Task",
"Resource":"arn:aws:states:::lambda:invoke",
"Arguments":{
"FunctionName":"GreetingsFunction",
"Payload":{
"fullname":"{% $states.input.name & ' ' & $states.input.surname %}"
}
},
"Retry":[
{
"ErrorEquals":[ "States.ALL" ],
"IntervalSeconds":2,
"MaxAttempts":4,
"BackoffRate":2
}
],
"Assign":{
"greeting":"{% $states.result.Payload.greeting %}"
},
"Next":"SQSState"
},
"SQSState":{
"Type":"Task",
"Resource":"arn:aws:states:::sqs:sendMessage",
"Arguments":{
"QueueUrl":"http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/localstack-queue",
"MessageBody":"{% $greeting %}"
},
"End":true
}
}
}
```

### Define Mock Integrations in a Configuration File

Mock integrations are defined in a JSON file that follows the `RawMockConfig` schema.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the RawMockConfig?

Can we provide a reference or more self-contained information for a first time reader?

The file contains two top-level sections:

- **StateMachines** – Maps each state machine to its test cases, specifying which states use which mocked responses.
- **MockedResponses** – Defines reusable mock payloads identified by `ResponseID`, which test cases refer to.

#### `StateMachines`

This section specifies the Step Functions state machines to mock and their test cases.
Each test case maps state names to response IDs defined in `MockedResponses`.

```json
"StateMachines": {
"<StateMachineName>": {
"TestCases": {
"<TestCaseName>": {
"<StateName>": "<ResponseID>",
...
}
}
}
}
```

In the example above:

- `StateMachineName`: Must match the exact name used during creation in LocalStack.
- `TestCases`: Named scenarios that define mocked behavior for individual states.

Each test case maps Task states to mock responses that define expected behavior.
At runtime, if a test case is selected, the state uses the mock response if defined; otherwise, it calls the emulated service.

Here is a full example of the `StateMachines` section:

```json
"LambdaSQSIntegration": {
"TestCases": {
"LambdaRetryCase": {
"LambdaState": "MockedLambdaStateRetry",
"SQSState": "MockedSQSStateSuccess"
}
}
}
```

#### `MockedResponses`

This section defines mocked responses for Task states.
Each `ResponseID` contains one or more step keys and either a `Return` or `Throw`.

```json
"MockedResponses": {
"<ResponseID>": {
"<step-key>": { "Return": ... },
"<step-key>": { "Throw": ... }
}
}
```

In the example above:

- `ResponseID`: Unique identifier referenced in test cases.
- `step-key`: Indicates the attempt (e.g., `"0"` for first try, `"1-2"` for a range).
- `Return`: Simulates success with a response payload.
- `Throw`: Simulates failure with `Error` and `Cause`.

{{< callout >}}
Each entry must have **either** `Return` or `Throw`—not both.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: ", but cannot have both" might read a bit more fluid

{{< /callout >}}

Here is a full example of the `MockedResponses` section:

```json
"MockedLambdaStateRetry": {
"0": {
"Throw": {
"Error": "Lambda.ServiceException",
"Cause": "An internal service error occurred."
}
},
"1-2": {
"Throw": {
"Error": "Lambda.TooManyRequestsException",
"Cause": "Invocation rate limit exceeded."
}
},
"3": {
"Return": {
"StatusCode": 200,
"Payload": {
"greeting": "Hello John Smith, you’re now testing mocked integrations with LocalStack!"
}
}
}
}
```

The `MockConfigFile.json` below is used to test the `LambdaSQSIntegration` state machine defined earlier.

```json
{
"StateMachines":{
"LambdaSQSIntegration":{
"TestCases":{
"BaseCase":{
"LambdaState":"MockedLambdaStateSuccess",
"SQSState":"MockedSQSStateSuccess"
},
"LambdaRetryCase":{
"LambdaState":"MockedLambdaStateRetry",
"SQSState":"MockedSQSStateSuccess"
},
"HybridCase":{
"LambdaState":"MockedLambdaSuccess"
}
}
}
},
"MockedResponses":{
"MockedLambdaStateSuccess":{
"0":{
"Return":{
"StatusCode":200,
"Payload":{
"greeting":"Hello John Smith, you’re now testing mocked integrations with LocalStack!"
}
}
}
},
"MockedSQSStateSuccess":{
"0":{
"Return":{
"MD5OfMessageBody":"3661896f-1287-45a3-8f89-53bd7b25a9a6",
"MessageId":"7c9ef661-c455-4779-a9c2-278531e231c2"
}
}
},
"MockedLambdaStateRetry":{
"0":{
"Throw":{
"Error":"Lambda.ServiceException",
"Cause":"An internal service error occurred."
}
},
"1-2":{
"Throw":{
"Error":"Lambda.TooManyRequestsException",
"Cause":"Invocation rate limit exceeded."
}
},
"3":{
"Return":{
"StatusCode":200,
"Payload":{
"greeting":"Hello John Smith, you’re now testing mocked integrations with LocalStack!"
}
}
}
}
}
}
```

### Provide the Mock Configuration to LocalStack

Set the `SFN_MOCK_CONFIG` configuration variable to the path of the mock configuration file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we document SFN_MOCK_CONFIG in the configuration section as well?

When running LocalStack in Docker, mount the file and pass the variable as shown below:

{{< tabpane >}}
{{< tab header="LocalStack CLI" lang="shell" >}}
LOCALSTACK_SFN_MOCK_CONFIG=/tmp/MockConfigFile.json \
localstack start --volume /path/to/MockConfigFile.json:/tmp/MockConfigFile.json
{{< /tab >}}
{{< tab header="Docker Compose" lang="yaml" >}}
services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}"
image: localstack/localstack-pro
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we intentionally using the pro image for showcasing a community feature?
Using the community compose could simplify things a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the pro image as it is used for the LDM, but I agree this is best if presented with the community version

ports:
- "127.0.0.1:4566:4566" # LocalStack Gateway
- "127.0.0.1:4510-4559:4510-4559" # external services port range
- "127.0.0.1:443:443" # LocalStack HTTPS Gateway (Pro)
environment:
# LocalStack configuration: https://docs.localstack.cloud/references/configuration/
- DEBUG=${DEBUG:-0}
- SFN_MOCK_CONFIG=/tmp/MockConfigFile.json
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
- "./MockConfigFile.json:/tmp/MockConfigFile.json"
{{< /tab >}}
{{< /tabpane >}}

This tells LocalStack to use the specified file for mocked service integrations during Step Functions execution.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this sentence after the code pane add extra value?
suggestion: better specify any preview (what it does) and required information before the code section.


### Run Test Cases with Mocked Integrations

Create the state machine to match the name defined in the mock configuration file.
In this example, create the `LambdaSQSIntegration` state machine using:

{{< command >}}
$ awslocal stepfunctions create-state-machine \
--definition file://LambdaSQSIntegration.json \
--name "LambdaSQSIntegration" \
--role-arn "arn:aws:iam::000000000000:role/service-role/testrole"
{{< /command >}}

After the state machine is created and named correctly, test cases from the mock configuration file can be run using the [`StartExecution`](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html) or [StartSyncExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartSyncExecution.html) APIs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: intentional ` and non-` ?


To execute a test case, append the test case name to the state machine ARN using `#`.
This tells LocalStack to apply the mocked responses from the configuration file.
For example, run the `BaseCase` test case:

{{< command >}}
$ awslocal stepfunctions start-execution \
--state-machine arn:aws:states:ca-central-1:000000000000:stateMachine:LambdaSQSIntegration#BaseCase \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to adopt the default LocalStack region us-east-1 everywhere?

--input '{"name": "John", "surname": "smith"}' \
--name "MockExecutionBaseCase"
{{< /command >}}

During execution, any state mapped in the mock config will use the predefined response.
States without mock entries invoke the actual emulated service as usual.

You can inspect the execution using the [`DescribeExecution`](https://docs.aws.amazon.com/step-functions/latest/apireference/API_DescribeExecution.html) API:

{{< command >}}
$ awslocal stepfunctions describe-execution \
--execution-arn "arn:aws:states:ca-central-1:000000000000:execution:LambdaSQSIntegration:MockExecutionBaseCase"
{{< /command >}}

The sample output shows the execution details, including the state machine ARN, execution ARN, status, start and stop dates, input, and output:

```json
{
"executionArn": "arn:aws:states:ca-central-1:000000000000:execution:LambdaSQSIntegration:MockExecutionBaseCase",
"stateMachineArn": "arn:aws:states:ca-central-1:000000000000:stateMachine:LambdaSQSIntegration",
"name": "MockExecutionBaseCase",
"status": "SUCCEEDED",
"startDate": "...",
"stopDate": "...",
"input": "{\"name\":\"John\",\"surname\":\"smith\"}",
"inputDetails": {
"included": true
},
"output": "{\"MessageId\":\"7c9ef661-c455-4779-a9c2-278531e231c2\",\"MD5OfMessageBody\":\"3661896f-1287-45a3-8f89-53bd7b25a9a6\"}",
"outputDetails": {
"included": true
}
}
```

You can also use the [`GetExecutionHistory`](https://docs.aws.amazon.com/step-functions/latest/apireference/API_GetExecutionHistory.html) API to retrieve the execution history, including the events and their details.

{{< command >}}
$ awslocal stepfunctions get-execution-history \
--execution-arn "arn:aws:states:ca-central-1:000000000000:execution:LambdaSQSIntegration:MockExecutionBaseCase"
{{< /command >}}

This will return the full execution history, including entries that indicate how the mocked responses were applied to the Lambda and SQS states.

```json
...
{
"timestamp": "...",
"type": "TaskSucceeded",
"id": 5,
"previousEventId": 4,
"taskSucceededEventDetails": {
"resourceType": "lambda",
"resource": "invoke",
"output": "{\"StatusCode\": 200, \"Payload\": {\"greeting\": \"Hello John Smith, you\\u2019re now testing mocked integrations with LocalStack!\"}}",
"outputDetails": {
"truncated": false
}
}
}
...
{
"timestamp": "...",
"type": "TaskSucceeded",
"id": 10,
"previousEventId": 9,
"taskSucceededEventDetails": {
"resourceType": "sqs",
"resource": "sendMessage",
"output": "{\"MessageId\": \"7c9ef661-c455-4779-a9c2-278531e231c2\", \"MD5OfMessageBody\": \"3661896f-1287-45a3-8f89-53bd7b25a9a6\"}",
"outputDetails": {
"truncated": false
}
}
}
...
```

## Resource Browser

The LocalStack Web Application provides a Resource Browser for managing Step Functions state machines.
Expand Down