diff --git a/content/en/references/configuration.md b/content/en/references/configuration.md index c8ee8e1209..a033f74e5b 100644 --- a/content/en/references/configuration.md +++ b/content/en/references/configuration.md @@ -337,6 +337,12 @@ Please consult the [migration guide]({{< ref "user-guide/aws/lambda#migrating-to | `SQS_DISABLE_CLOUDWATCH_METRICS` | `0` (default) | Disables the CloudWatch Metrics for SQS when set to `1` | | `SQS_CLOUDWATCH_METRICS_REPORT_INTERVAL` | `60` (default) | Configures the report interval (in seconds) for `Approximate*` metrics that are sent to CloudWatch periodically. Sending will be disabled if `SQS_DISABLE_CLOUDWATCH_METRICS=1` | +### Step Functions + +| Variable | Example Values | Description | +| - | - | - | +| `SFN_MOCK_CONFIG` | `/tmp/MockConfigFile.json` | Specifies the file path to the mock configuration file that defines mock service integrations for Step Functions. | + ## Security {{< callout "warning" >}} diff --git a/content/en/user-guide/aws/stepfunctions/index.md b/content/en/user-guide/aws/stepfunctions/index.md index a972c55a35..d9efe63536 100644 --- a/content/en/user-guide/aws/stepfunctions/index.md +++ b/content/en/user-guide/aws/stepfunctions/index.md @@ -133,10 +133,392 @@ LocalStack's Step Functions emulation supports the following AWS services: | | AWS Batch | ✓ | ✓ | | | | AWS SDK integrations | All LocalStack services | ✓ | | | ✓ | +## Mocked Service Integrations + +Mocked service integrations let you test AWS Step Functions without invoking LocalStack’s emulated AWS services. +Instead, Task states return predefined outputs from a mock configuration file. + +The key components are: + +- **Mocked service integrations**: Task states that return predefined responses instead of calling local AWS services. +- **Mocked responses**: Static payloads linked to mocked Task states. +- **Test cases**: Executions of your state machine that use mocked responses. +- **Mock configuration file**: A JSON file that defines test cases, mocked states, and their response payloads. + +During execution, each Task state listed in the mock file returns its associated mocked response. States not included in the file continue to invoke the corresponding emulated services, allowing a mix of mocked and real interactions. + +You can define one or more mocked payloads per Task state. + +Supported integration patterns include `.sync`, `.sync2`, and `.waitForTaskToken`. + +Both success and failure scenarios can be simulated. + +### Compatibility with AWS Step Functions Local + +LocalStack can also serve as a drop-in replacement for [AWS Step Functions Local testing with mocked service integrations](https://docs.aws.amazon.com/step-functions/latest/dg/sfn-local-test-sm-exec.html). +It supports test cases with mocked Task states and maintains compatibility with existing Step Functions Local configurations. +This functionality is extended in LocalStack by providing access to the latest Step Functions features such as [JSONata and Variables](https://blog.localstack.cloud/aws-step-functions-made-easy/), as well as the ability to enable both mocked and emulated service interactions emulated by LocalStack. + +{{< callout >}} +LocalStack does not validate response formats. +Ensure the payload structure in the mocked responses matches what the real service expects. +{{< /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 should be applied. + +In this example, we'll use a state machine named `LambdaSQSIntegration`, defined as follows: + +```json +{ + "Comment": "This state machine is called: LambdaSQSIntegration", + "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. + +This 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, each identified by a `ResponseID`, which test cases can reference. + + +#### `StateMachines` + +This section specifies the Step Functions state machines to mock, along with their corresponding test cases. + +Each test case maps state names to `ResponseID`s defined in the `MockedResponses` section. + +```json +"StateMachines": { + "": { + "TestCases": { + "": { + "": "", + ... + } + } + } +} +``` + +In the example above: + +- **`StateMachineName`**: Must exactly match the name used when the state machine was created in LocalStack. +- **`TestCases`**: Named scenarios that define mocked behavior for specific `Task` states. + +Each test case maps `Task` states to mock responses that define their expected behavior. + +At runtime, if a test case is selected, the state uses the mocked response (if defined); otherwise, it falls back to calling the emulated service. + +Below is a complete example of the `StateMachines` section: + +```json +"LambdaSQSIntegration": { + "TestCases": { + "LambdaRetryCase": { + "LambdaState": "MockedLambdaStateRetry", + "SQSState": "MockedSQSStateSuccess" + } + } +} +``` + +#### `MockedResponses` + +This section defines mocked responses for Task states. + +Each `ResponseID` includes one or more step keys and defines either a `Return` value or a `Throw` error. + +```json +"MockedResponses": { + "": { + "": { "Return": ... }, + "": { "Throw": ... } + } +} +``` + +In the example above: + +- `ResponseID`: A unique identifier used in test cases to reference a specific mock response. +- `step-key`: Indicates the attempt number. For example, `"0"` refers to the first try, while `"1-2"` covers a range of attempts. +- `Return`: Simulates a successful response by returning a predefined payload. +- `Throw`: Simulates a failure by returning an `Error` and an optional `Cause`. + +{{< callout >}} +Each entry must have **either** `Return` or `Throw`, but cannot have both. +{{< /callout >}} + +Here is a complete 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` environment variable to the path of your mock configuration file. + +If you're 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 + ports: + - "127.0.0.1:4566:4566" # LocalStack Gateway + - "127.0.0.1:4510-4559:4510-4559" # external services port range + 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 >}} + +### 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 correctly named, you can run test cases defined in the mock configuration file using the [`StartExecution`](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html) API. + +To execute a test case, append the test case name to the state machine ARN using `#`. + +This tells LocalStack to apply the corresponding mocked responses from the configuration file. + +For example, to run the `BaseCase` test case: + + +{{< command >}} +$ awslocal stepfunctions start-execution \ + --state-machine arn:aws:states:us-east-1:000000000000:stateMachine:LambdaSQSIntegration#BaseCase \ + --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:us-east-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:us-east-1:000000000000:execution:LambdaSQSIntegration:MockExecutionBaseCase", + "stateMachineArn": "arn:aws:states:us-east-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:us-east-1:000000000000:execution:LambdaSQSIntegration:MockExecutionBaseCase" +{{< /command >}} + +This will return the full execution history, including entries that indicate how mocked responses were applied to 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. -You can access the Resource Browser by opening the LocalStack Web Application in your browser, navigating to the **Resource Browser** section, and then clicking on **Step Functions** under the **App Integration** section. +The LocalStack Web Application includes a **Resource Browser** for managing Step Functions state machines. + +To access it, open the LocalStack Web UI in your browser, navigate to the **Resource Browser** section, and click **Step Functions** under **App Integration**. Step Functions Resource Browser