This project contains automated test code samples for serverless applications. The project uses the AWS Serverless Application Model (SAM) CLI for configuration, testing and deployment.
- Project contents
- Prerequisites
- Build and deploy with the SAM CLI
- Working with events
- Working with local emulators
- Run a unit test using a mock framework
- Run an integration test against cloud resources
- Testing with the Spock testing framework
- Invoke a Lambda function in the cloud
- Fetch, tail, and filter Lambda function logs locally
- Use SAM Accelerate to speed up feedback cycles
- Perform a load test
- Implement application tracing
- Cleanup
- Additional resources
This application creates several AWS resources, including a Lambda function and an API Gateway. These resources are defined in the template.yaml
file in this project. This project includes the following files and folders:
- src - Code for the application's Lambda function.
- events - synthetic events that you can use to invoke the function.
- tests - Unit and integration tests for the application code.
- template.yaml - A template that defines the application's AWS resources.
The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API.
To use the SAM CLI, you need the following tools.
- SAM CLI - Install the SAM CLI
- Java11 - Install the Java 11
- Maven - Install Maven
- Docker - Install Docker community edition
Use the following command to build your application locally:
# build your application locally using a sam
apigw-lambda-list-s3-buckets$ sam build
The SAM CLI installs dependencies defined in apigw-lambda-list-s3-buckets/pom.xml
, creates a deployment package, and saves it in the .aws-sam/build
folder. Read the documentation.
Note: If you witness error
Could not find public.ecr.aws/sam/build-java11:latest-x86_64 image locally and failed to pull it from docker
then rundocker logout public.ecr.aws
and rerunsam build
Use the following commend to deploy your application package to AWS:
# deploy your application to the AWS cloud
apigw-lambda-list-s3-buckets$ sam deploy --guided
After running this command you will receive a series of prompts:
- Stack Name: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name.
- AWS Region: The AWS region you want to deploy your app to.
- Confirm changes before deploy: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes.
- Allow SAM CLI IAM role creation: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the
CAPABILITY_IAM
value forcapabilities
must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass--capabilities CAPABILITY_IAM
to thesam deploy
command. - Save arguments to samconfig.toml: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run
sam deploy
without parameters to deploy changes to your application.
You can find your API Gateway Endpoint URL in the output values displayed after deployment.
Take note of this URL for use in the logging section below. On subsequent deploys you can run sam deploy
without the --guided
flag. Read the documentation.
Testing event driven architectures often requires working with synthetic events. Events are frequently defined as JSON documents. Synthetic events are test data that represent AWS events such as a requests from API Gateway or a messages from SQS.
AWS Lambda always requires an event during invocation. A sample test event is included in the events
folder in this project. SAM provides the capability of generating additional synthetic events for a variety of AWS services. Read the documentation.
Use the following command to learn more about generating synthetic events:
# generate a synthetic event
apigw-lambda-list-s3-buckets$ sam local generate-event
The SAM CLI can emulate a Lambda function inside a Docker container deployed to your local desktop. To use this feature, invoke the function with the sam local invoke
command passing a synthetic event. Print statements log to standard out. Read the documentation.
# invoke a Lambda function locally
apigw-lambda-list-s3-buckets$ sam local invoke ListBucketsFunction --event events/event.json
The sam local start-lambda
command starts a local endpoint that emulates the AWS Lambda invoke endpoint. You can invoke it from your automated tests. Because this endpoint emulates the AWS Lambda invoke endpoint, you can write tests and then run them against the local Lambda emulator. You can also run the same tests against a deployed AWS SAM stack in your CI/CD pipeline. Read the documentation.
# start a local emulator for a Lambda function endpoint
apigw-lambda-list-s3-buckets$ sam local start-lambda --region us-east-1
# run a unit test in a separate terminal
apigw-lambda-list-s3-buckets$ aws lambda invoke --function-name "ListBucketsFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt
The SAM CLI can also emulate your application's API. Use the sam local start-api
to run the API locally on port 3000.
# start a local emulator for an API Gateway endpoint
apigw-lambda-list-s3-buckets$ sam local start-api
# make a request to the endpoint in a separate terminal
apigw-lambda-list-s3-buckets$ curl http://localhost:3000/listBuckets
The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The Events
property on each function's definition includes the route and method for each path.
Events:
HelloWorld:
Type: Api
Properties:
Path: /listBuckets
Method: get
Tests are defined in the apigw-lambda-list-s3-buckets/src/test
folder in this project.
apigw-lambda-list-s3-buckets$ mvn test
You can use mocking frameworks like Mockito to mock the service calls that are being done in the Lambda function.
AppWithMockTest.java
covers this example:
@ExtendWith(MockitoExtension.class)
public class AppWithMockTest {
private static S3Client s3Client;
@BeforeEach
public void setup() {
s3Client = mock(S3Client.class);
Bucket bucket = mock(Bucket.class);
when(bucket.name()).thenReturn("foo");
lenient().when(s3Client.listBuckets())
.thenReturn(ListBucketsResponse.builder().buckets(bucket).build());
}
@Test
public void successfulResponse() {
App app = new App(s3Client);
APIGatewayProxyResponseEvent result = app.handleRequest(null, null);
assertEquals(200, result.getStatusCode().intValue());
assertEquals("text/plain", result.getHeaders().get("Content-Type"));
String content = result.getBody();
assertNotNull(content);
assertTrue(content.length() > 0);
assertEquals("foo", content);
}
}
Spock is a Groovy-based testing framework that uses a narrative style with blocks like "when", "then", and "expect" for writing clear and readable tests. It provides mocking, stubbing, and spying to isolate code under test. With its expressive Groovy syntax and declarative style Spock reduces boilerplate code and aims to simplify testing.
You can use Spock to mock the service calls that are being done in the Lambda function.
AppWithMockSpec.groovy
covers this example:
class AppWithMockSpec extends Specification {
def mockS3Client = Mock(S3Client)
def app = new App(mockS3Client)
def "returns a list of buckets"() {
given: "a bucket exists"
1 * mockS3Client.listBuckets() >> listWithBucket()
when: "a request is received"
def request = getRequestFromFile()
def responseEvent = app.handleRequest(request, null)
then: "a list of buckets is returned"
def responseBody = new JsonSlurper().parseText(responseEvent.getBody()) as List
responseBody.size() >= 1
and: "the first item is the example bucket"
responseBody.first() == TEST_BUCKET_NAME
}
}
The AWS CLI
enables you to invoke a Lambda function in the cloud.
# invoke a Lambda function in the cloud using the AWS CLI
aws lambda invoke --function-name <function-name> outfile.txt
To simplify troubleshooting, SAM CLI has a command called sam logs
. The sam logs
command lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several features to help you quickly find your bug.
NOTE
: This command works for all AWS Lambda functions; not just the ones you deploy using SAM.
apigw-lambda-list-s3-buckets$ sam logs -n ListBucketsFunction --stack-name <stack-name> --tail
In a new terminal, curl the API Gateway and watch the log output.
apigw-lambda-list-s3-buckets$ curl <API Gateway url>
You can find more information and examples about filtering Lambda function logs in the SAM CLI Documentation.
AWS SAM Accelerate is a set of features that reduces deployment latency and enable developers to test their code quickly against production AWS services in the cloud. Read the blog post
# synchronize local code with the cloud
apigw-lambda-list-s3-buckets$ sam sync --watch --stack-name <stack-name>
You can use AWS X-Ray to track user requests as they travel through your entire application. With X-Ray, you can understand how your application and its underlying services are performing to identify and troubleshoot the root cause of performance issues and errors. This Lambda function handler has been instrumented using AWS X-Ray. Find your Lambda function in the console. Then navigate to Monitor -> Traces and you should see a graph of your X-Ray trace.
You may also navigate to the X-Ray service in the console to examine your traces in greater detail. In the console you should be able to find a service map that looks similar to the one below.
To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following:
apigw-lambda-list-s3-buckets$ sam delete
See the AWS SAM developer guide for an introduction to SAM specification, the SAM CLI, and serverless application concepts.
Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: AWS Serverless Application Repository main page
Local emulation of AWS services offers a simple way to build and test cloud native applications using local resources. Local emulation can speed up the build and deploy cycle creating faster feedback loops for application developers.
Local emulation has several limitations. Cloud services evolve rapidly, so local emulators are unlikely to have feature parity with their counterpart services in the cloud. Local emulators may not be able to provide an accurate representation of IAM permissions or service quotas. Local emulators do not exist for every AWS service.
SAM provides local emulation features for AWS Lambda and Amazon API Gateway. AWS provides Amazon DynamoDB Local as well as AWS Step Functions Local.
This project demonstrates local emulation of Lambda and API Gateway with SAM.