Skip to content

Cloud Runner

The Durable Execution SDK Test Cloud Runner invokes a deployed Lambda function and polls for completion. Use it to validate IAM permissions, real service integrations, and deployment correctness. The same test assertions you write for local testing work with the cloud runner.

Set up the cloud runner

Create a CloudDurableTestRunner with the qualified function name and region. The runner invokes the function, extracts the execution ARN from the response, and polls until the execution completes.

import { CloudDurableTestRunner } from "@aws/durable-execution-sdk-js-testing";
import { LambdaClient } from "@aws-sdk/client-lambda";
import { ExecutionStatus } from "@aws-sdk/client-lambda";

const runner = new CloudDurableTestRunner({
  functionName: "MyFunction:$LATEST",
  client: new LambdaClient({ region: "us-east-1" }),
});

it("runs against a deployed function", async () => {
  const result = await runner.run({ payload: { name: "world" } });

  expect(result.getStatus()).toBe(ExecutionStatus.SUCCEEDED);
  expect(result.getResult()).toBe("hello world");
});
from aws_durable_execution_sdk_python.execution import InvocationStatus
from aws_durable_execution_sdk_python_testing.runner import DurableFunctionCloudTestRunner


def test_runs_against_deployed_function():
    runner = DurableFunctionCloudTestRunner(
        function_name="MyFunction:$LATEST",
        region="us-east-1",
    )
    result = runner.run(input='{"name": "world"}', timeout=60)

    assert result.status is InvocationStatus.SUCCEEDED
    assert result.result is not None
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import software.amazon.lambda.durable.model.ExecutionStatus;
import software.amazon.lambda.durable.testing.CloudDurableTestRunner;

class CloudRunnerTest {

    @Test
    void runsAgainstDeployedFunction() {
        var runner = CloudDurableTestRunner.create(
            "arn:aws:lambda:us-east-1:123456789012:function:MyFunction:$LATEST",
            String.class,
            String.class
        );

        var result = runner.runUntilComplete("{\"name\": \"world\"}");

        assertEquals(ExecutionStatus.SUCCEEDED, result.getStatus());
        assertNotNull(result.getResult(String.class));
    }
}

Deploy before running

Cloud mode requires a deployed function. Deploy with your preferred tool before running cloud tests:

sam build
sam deploy --stack-name my-durable-function

After deployment, get the qualified function name or ARN:

aws lambda get-function --function-name MyFunction \
  --query 'Configuration.FunctionArn' --output text

Configure polling

The runner polls for completion, then retrieves the full operation history for assertions. Configure the poll interval to control how frequently the runner checks for completion.

Pass config: { pollInterval } (in milliseconds) to the constructor:

import { CloudDurableTestRunner } from "@aws/durable-execution-sdk-js-testing";
import { LambdaClient } from "@aws-sdk/client-lambda";
import { ExecutionStatus } from "@aws-sdk/client-lambda";

const runner = new CloudDurableTestRunner({
  functionName: "MyFunction:$LATEST",
  client: new LambdaClient({ region: "us-east-1" }),
  config: { pollInterval: 2000 },
});

it("runs against a deployed function", async () => {
  const result = await runner.run({ payload: { name: "world" } });

  expect(result.getStatus()).toBe(ExecutionStatus.SUCCEEDED);
});

Pass timeout in seconds to run():

from aws_durable_execution_sdk_python.execution import InvocationStatus
from aws_durable_execution_sdk_python_testing.runner import DurableFunctionCloudTestRunner


def test_runs_with_custom_timeout():
    runner = DurableFunctionCloudTestRunner(
        function_name="MyFunction:$LATEST",
        region="us-east-1",
    )
    result = runner.run(input='{"name": "world"}', timeout=60)

    assert result.status is InvocationStatus.SUCCEEDED

Use withTimeout(Duration) to set the maximum wait time:

import static org.junit.jupiter.api.Assertions.*;

import java.time.Duration;
import org.junit.jupiter.api.Test;
import software.amazon.lambda.durable.model.ExecutionStatus;
import software.amazon.lambda.durable.testing.CloudDurableTestRunner;

class CloudRunnerTimeoutTest {

    @Test
    void runsWithCustomTimeout() {
        var runner = CloudDurableTestRunner
            .create(
                "arn:aws:lambda:us-east-1:123456789012:function:MyFunction:$LATEST",
                String.class,
                String.class
            )
            .withTimeout(Duration.ofSeconds(60));

        var result = runner.runUntilComplete("{\"name\": \"world\"}");

        assertEquals(ExecutionStatus.SUCCEEDED, result.getStatus());
    }
}

Required IAM permissions

Cloud mode requires AWS credentials in the environment. The runner uses the default credential chain, so any standard AWS credential configuration works.

The IAM principal running the tests needs these permissions on the target function:

{
  "Effect": "Allow",
  "Action": [
    "lambda:InvokeFunction",
    "lambda:GetDurableExecution",
    "lambda:GetDurableExecutionHistory"
  ],
  "Resource": "arn:aws:lambda:region:account-id:function:function-name"
}

Troubleshooting

Credentials not configured

The runner throws when it cannot find AWS credentials. Run aws sts get-caller-identity to verify your credentials are configured.

Function not found

Verify the function name or ARN is correct and the function exists in the target region: aws lambda get-function --function-name MyFunction.

Execution timeout

The function took longer than the configured timeout. Increase the timeout or check the function logs: aws logs tail /aws/lambda/MyFunction --follow.

Note

SAM CLI also supports invoking deployed functions with sam remote invoke and resolving callbacks with sam remote callback succeed. See SAM CLI.

See also

  • Authoring Set up the local test runner.
  • Assertions Inspect operation history after a test run.