Skip to content

Commit

Permalink
Merge branch 'main' into patch-11
Browse files Browse the repository at this point in the history
  • Loading branch information
dancfox authored Feb 27, 2024
2 parents 0d9ad92 + 510d865 commit dc45611
Show file tree
Hide file tree
Showing 260 changed files with 11,865 additions and 159 deletions.
6 changes: 3 additions & 3 deletions .github/METADATA/metadata_json_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"type": "string",
"title": "Repository Programming Language",
"examples": [".NET","Python"],
"pattern": ".NET|Java|Python|Typescript|GO|Rust",
"pattern": ".NET|Java|Python|Typescript|GO|Rust|Custom|Node.js|PHP",
"maxLength": 60,
"minLength": 3
},
Expand Down Expand Up @@ -66,15 +66,15 @@
"type": "string",
"title": "Deployment Framework for the pattern",
"examples": ["SAM"],
"pattern": "SAM|Cloudformation|CDK",
"pattern": "CDK|SAM|Amplify|CloudFormation|Serverless Framework",
"maxLength": 60,
"minLength": 3
},
"services": {
"$id": "#/properties/services",
"type": "array",
"title": "AWS Services used in the pattern",
"examples": [["apigw","lambda","dynamodb"]],
"examples": [["AWS Lambda","Amazon API Gateway","Amazon DynamoDB"]],
"minItems": 1,
"uniqueItems": True,
"items": {
Expand Down
55 changes: 37 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,58 @@ The repository is divided into several language directories. If you would like t
This repository contains sample code for testing a variety of different types of workloads, including API's, Event-Driven Architectures, Service Orchestration, Data Processing, and AWS Partner Patterns.

## API's
|System Under Test|Language|
---|---
|[API Gateway with Lambda and DynamoDB](./python-test-samples/apigw-lambda-dynamodb)|Python|API Gateway, AWS Lambda and Amazon DynamoDB|
|[API Gateway HTTP with CDK](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/python-http-cdk) [External] | Python |
|[API Gateway HTTP with SAM](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/python-http-sam) [External] | Python |
|[API Gateway REST with SAM](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/python-rest-sam) [External] | Python |
|[Api Gateway, Lambda, DynamoDB](./typescript-test-samples/apigw-lambda-dynamodb)|TypeScript|
|[API Gateway, Lambda Authorizer, Lambda, DynamoDB](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/javascript-http-sam) [External] | Node.js |
|[API Gateway, Lambda, DynamoDB](./java-test-samples/apigw-lambda-ddb)|Java|
|[API Gateway, Lambda, DynamoDB](./dotnet-test-samples/apigw-lambda-ddb)|.NET|
|[AppSync, DynamoDB](./java-test-samples/java-appsync-sam)|Java|
| System Under Test|Language|
|---|---|
| [API Gateway with Lambda and DynamoDB](./python-test-samples/apigw-lambda-dynamodb)|Python|API Gateway, AWS Lambda and Amazon DynamoDB|
| [API Gateway HTTP with CDK](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/python-http-cdk) [External]| Python |
| [API Gateway HTTP with SAM](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/python-http-sam) [External]| Python |
| [API Gateway REST with SAM](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/python-rest-sam) [External]| Python |
| [Api Gateway, Lambda, DynamoDB](./typescript-test-samples/apigw-lambda-dynamodb)|TypeScript|
| [API Gateway, Lambda Authorizer, Lambda, DynamoDB](https://github.com/aws-samples/serverless-samples/tree/main/serverless-rest-api/javascript-http-sam) [External] | Node.js |
| [API Gateway, Lambda, S3](./dotnet-test-samples/apigw-lambda-list-s3-buckets)|.NET|
| [API Gateway, Lambda, DynamoDB](./dotnet-test-samples/apigw-lambda-ddb)|.NET|
| [SQS, Lambda, DynamoDB](./dotnet-test-samples/sqs-lambda)|.NET|
| [API Gateway, Lambda, DynamoDB](./java-test-samples/apigw-lambda-ddb)|Java|
| [AppSync, DynamoDB](./java-test-samples/java-appsync-sam)|Java|

## Event-Driven Architectures
Event-driven architectures (EDA) are an architecture style that uses events and asynchronous communication to loosely couple an application’s components. To learn more about several strategies for testing EDA's visit [this guide at Serverlessland.com](https://serverlessland.com/event-driven-architecture/testing-introduction).
|System Under Test|Language|Description|
---|---|---
|[S3, Lambda](./python-test-samples/async-lambda-dynamodb)|Python|This is a great starter project for learning how to test async EDA.|
|[Schemas and Contracts](./typescript-test-samples/schema-and-contract-testing)|TypeScript|Event driven architectures decouple producers and consumers at the infrastructure layer, but these resources may still be coupled at the application layer by the event contract. Learn how to test for breaking changes in the contract.|
|[S3, Lambda, DynamoDB](./dotnet-test-samples/async-architectures/async-lambda-dynamodb)|.NET|This example shows how to test async system by using DynamoDB during to store incoming asynchronous events during testing|
|[S3, Lambda, SQS](./dotnet-test-samples/async-architectures/async-lambda-sqs)|.NET|An example to how to test asynchronous workflow by long polling the queue that resulting messages are sent to.|

## Architectural patterns
|Pattern|Services used|Language|Description|
|---|---|---|---|
| [Hexagonal architecture](./dotnet-test-samples/hexagonal-architecture/) |API Gateway, Lambda, DynamoDB|.NET|Hexagonal architecture is an architectural pattern used for encapsulating domain logic and decoupling it from other implementation details, such as infrastructure or client requests.|

## Service Orchestration
|System Under Test|Language|Description|
---|---|---
|[Step Functions](./java-test-samples/step-functions-local) [External]|Java|This project shows a technique for testing an AWS Step Functions workflow in a local desktop environment.
|---|---|---|
| [Step Functions](./java-test-samples/step-functions-local) [External] |Java|This project shows a technique for testing an AWS Step Functions workflow in a local desktop environment.|

## Data Processing
|System Under Test|Language|Description|
---|---|---
| System Under Test|Language|Description|
|---|---|---|
|[Kinesis Data Stream, Lambda](./typescript-test-samples/kinesis-lambda-dynamodb)|TypeScript|This project shows a technique for testing a streaming data processing system.|
|[Kinesis Data Stream, Lambda, DynamoDB](./dotnet-test-samples/kinesis-lambda-dynamodb)|.NET|This pattern creates an AWS Lambda function that consumes messages from an Amazon Kinesis Data Streams and dumps them to Amazon DynamoDB using SAM and .NET 6.|

## AWS Partner Patterns
|Partner|System Under Test|Language|Description|
---|---|---|---
|Datadog|[API Gateway, Lambda, SQS, SNS](./typescript-test-samples/apigw-lambda-sqs-sns-datadog)|TypeScript|This example is about creating Synthetic Tests and Monitors with Datadog.|
| Partner |System Under Test|Language|Description|
|---|---|---|---|
| Datadog |[API Gateway, Lambda, SQS, SNS](./typescript-test-samples/apigw-lambda-sqs-sns-datadog)|TypeScript|This example is about creating Synthetic Tests and Monitors with Datadog.|

## Test Containers
[Testcontainers](https://testcontainers.com/) is an open source framework for providing throwaway, lightweight instances of databases, message brokers, web browsers, or just about anything that can run in a Docker container. These tests demonstrate how you can utilize this as part of your testing frameworks to startup, initialize and tear down emulated resources.

Emulation is not a replacement for testing against actual cloud resources, and integration tests will always run against deployed versions of your applications. However, the emulation of certain services like DynamoDB can provide fast feedback loops on your local machine.

|System Under Test|Language|Description|
|---|---|---|
|[API Gateway, Lambda, DynamoDB](./dotnet-test-samples/test-containers)|.NET|This example demonstrates how you can simplify local testing and emulation using the TestContainers project.|

# How do I contribute?

Expand Down
8 changes: 5 additions & 3 deletions dotnet-test-samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ This portion of the repository contains code samples for testing serverless appl

## Test Basic Patterns
|Project|Description|
---|---
|---|---|
|[.NET Starter Project](./apigw-lambda-list-s3-buckets)|This project contains introductory examples of .NET tests written for AWS Lambda. This is the best place to start!|
|[API Gateway with Lambda and DynamoDB](./apigw-lambda-ddb)|This project contains unit and integration tests for a pattern using API Gateway, AWS Lambda and Amazon DynamoDB.|
|[API Gateway with AWS Lambda and DynamoDB](./apigw-lambda-ddb)|This project contains unit and integration tests for a pattern using API Gateway, AWS Lambda and Amazon DynamoDB.|
|[Hexagonal Architecture](./hexagonal-architecture)|An example of hexagonal architecture implemented using AWS Lambda with tests.|
|[Kinesis Data Streams](./kinesis-lambda-dynamodb/)|This project contains unit and integration tests for a pattern using Kinesis Data Streams, AWS Lambda and Amazon DynamoDB.|
|[SQS with AWS Lambda and DynamoDb](./sqs-lambda)|This project contains unit and integration tests for AWS Lambda that is invoked by Amazon Simple Queue Service (SQS)|


## Test Asynchronous Architectures
* In a synchronous system, a calling service makes a request to a receiving service and then blocks, waiting for the receiver to complete the operation and return a result. In contrast, in an **asynchronous system**, a caller makes a request to a receiving system, which typically returns an immediate acknowledgement but then performs the requested operation at a later time. Asynchronous systems are frequently designed using event-driven architectures. These types of systems have several advantages including increased reliability, greater control over load processing, and improved scalability. However, testing these systems can present unique challenges.

|Project|Description|
---|---
|---|---|
|[Schema & Contract Testing](./schema-and-contract-testing)|This project contains examples on how to do schema and contract testing for your event driven applications.|
|[Async Testing Introduction](./apigw-lambda-ddb)|This project contains an introduction to asynchronous testing using Lambda, S3 & DynamoDB.|

6 changes: 5 additions & 1 deletion dotnet-test-samples/apigw-lambda-ddb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,8 @@ sam delete
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed
* [.NET 6](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) installed
* [.NET 6](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) installed

## Video Walkthroughs

[Unit testing AWS Lambda with .NET 6](https://www.youtube.com/watch?v=481ylgKPnNg&pp=ygUTLk5FVCBsYW1iZGEgdGVzdGluZw%3D%3D)
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@
},
{
"title": "Integration Test",
"filepath": "/tests/AsyncTesting.IntegrationTest/AsyncTests.cs"
"filepath": "/tests/AsyncTesting.IntegrationTest/TextTransformerE2ETest.cs"
}
],
"authors": [
{
"name": "James Eastham",
"image": "https://media.licdn.com/dms/image/C4D03AQHDx6vm65vyeA/profile-displayphoto-shrink_800_800/0/1637340702988?e=1684972800&v=beta&t=ohSQHb3h2VmM4iq8EWlLVi1wfrR7AUgke8wfSqP8RPI",
"image": "/assets/images/resources/contributors/ext-james-eastham.jpg",
"bio": "Senior Cloud Architect at AWS",
"linkedin": "https://www.linkedin.com/in/james-eastham/",
"twitter": "https://twitter.com/plantpowerjames"
}
]
}
}
2 changes: 1 addition & 1 deletion dotnet-test-samples/hexagonal-architecture/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"authors": [
{
"name": "Dror Helper",
"image": "https://media.licdn.com/dms/image/C4D03AQGbBwfXtx0Zmg/profile-displayphoto-shrink_200_200/0/1638988504464?e=1686182400&v=beta&t=5G7912InrYUbzHXPah-84eIDnh1j1UYQKIRFEENKmBs",
"image": "https://media.licdn.com/dms/image/C4D03AQGbBwfXtx0Zmg/profile-displayphoto-shrink_800_800/0/1638988505074?e=1712188800&v=beta&t=gzxBAr2Q9PGgXvI9t9TQzIdi_apxEq3VEvO12ClTMy8",
"bio": "Senior Microsoft Specialist Solution Architect at AWS",
"linkedin": "https://www.linkedin.com/in/drorhelper/",
"twitter": "https://twitter.com/dhelper"
Expand Down
133 changes: 133 additions & 0 deletions dotnet-test-samples/schema-and-contract-testing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# .NET: Schema and Contract testing for Event-Driven Architectures

---

## Contents

- [Introduction](#introduction)
- [Schema testing](#schema-testing-schema-difference)
- [Goal](#goal)
- [Description](#description)
- [System under test](#system-under-test-sut)
- [Limitations](#limitations)
- [Contract testing](#contract-testing)

- [Goal](#goal-1)
- [Description](#description-1)
- [System under test](#system-under-test-sut-1)
- [Limitations](#limitations-1)

- [Key Files in the Project](#key-files-in-this-project)
- [Run the tests](#run-the-tests)

---

## Introduction

Event driven architectures decouple producers and consumers at the infrastructure layer, but these resources may still be coupled at the application layer by the event contract. Consumers may write business logic that expects events to conform to specific schemas. If schemas change over time the consumer code may fail. Creating automated tests that validate event schemas can help increase the quality of your systems and prevent breaking changes.

## Schema Testing

### Goal

To prevent event schema changes from breaking consumer applications.

### Description

Schema tests are designed to check for changes that are not backward-compatible, such as removing elements, changing a field type or adding new mandatory elements. Adding optional elements is considered backward-compatible. If a new schema version is backward-compatible, the schema tests will pass and the consumer application business logic should not fail.

### System Under Test (SUT)

This test is integration service agnostic, as it runs against the schema published to a schema registry. Amazon EventBridge Schema Registry is one example of such a registry. It provides schemas for all events that are generated by AWS services. When you turn on schema discovery it will automatically detect and provide schemas for your custom events (OpenAPI and JSON Schemas). You can also use your own Git repository as a registry for storing schemas. In our test we will use a local “schemas” folder as a registry for simplicity.

The diagram below shows an example of how schema tests may run as part of a producer’s CI/CD pipeline. You can [view a sample schema test](tests/schema-testing.test.ts) that could be run during the "Build" step of the process.

![System Under Test (SUT)](img/schema_testing.png)

### Schema Test Limitations

Schema tests have two limitations worth mentioning.

First, schemas are inherently ambiguous as they do not capture business requirements. They may not express that a particular combination of fields is invalid, or they may not explicitly state the dependencies between fields. For example, when you create an AWS Lambda function, the `runtime` property is mandatory for zip packaging formats, but this field is not required for container image packaging formats. The schema for the Lambda `create-function` API payload will not convey this requirement. If an event consumer makes invalid assumptions about a new version of the payload, its business logic may fail even if there are technically no breaking schema changes.

Second, unless an event consumer uses SDK/code bindings generated specifically for the version of schema in use, the code and the schema may drift apart over time and the consumer business logic may eventually fail. In these cases, the schema validation test results create a false sense of security.

Both of these limitations can be addressed with [contract testing](#contract-testing).

## Contract Testing

### System Under Test (SUT)

This test is integration service agnostic as it uses sample events generated from a schema published to a schema registry. The diagram below shows one way of implementing contract testing as part of producer’s CI/CD pipeline.

The diagram below shows an example of how contract testing can be used as part of a producer’s CI/CD pipeline. You can [view a sample contract test](tests/SchemaTesting.UnitTest.ContractTests.cs) that could be run during the "Build" step of the process.

In this example, the sample schema is [loaded from disk.](tests/SchemaTesting.UnitTest/LocalDiskSchemaReader.cs) This could be replaced to retrieve schemas from EventBridge Schema Registry using the EventBridge SDK. An example of this can be found in the [EventBridgeSchemaRegistryReader class](tests/SchemaTesting.UnitTest/EventBridgeSchemaRegistryReader.cs).

![System Under Test (SUT)](img/contract_testing.png)

### Goal

To identify the side effects of non-breaking schema changes on consumer applications.

### Description

Contract testing uses sample events provided by producers to validate consumer side business logic and to provide a stronger guarantee of preventing breaking changes. Contract tests are owned by consumers.

Consider the following example. In a schema test, changing the format of an `address` field from a full address to a street address only and then adding new event fields like `country`, `city`, `state` and `postcode` would not produce a failure. These schema changes would be considered to be backward compatible, since the changes only add new elements. In contrast, a consumer test expecting a full address in the `address` field would fail and notify us that this change is actually not backward compatible.

There are other common strategies for implementing contract testing. One strategy is to establish test doubles. Test doubles are resources that replace production objects for testing purposes. The contract tests with test doubles run on the consumer side and expect that calls to the doubles return the same results as calls to the production application. Review the [Pact.io documentation](https://docs.pact.io/) for examples of this approach.

### Limitations

Writing tests and performing on-going maintenance requires a degree of additional effort. However once written, schema changes can be done more efficiently and with less effort to prevent and resolve breaking changes.

You may choose to be selective in deciding where to implement contract testing. Start by identifying critical applications where the cost of breaking changes is highest. Applications with greater tolerances for failure may choose to rely on schema testing only.

---

### Key Files in this Project

- [SchemaTesting.cs](tests/SchemaTesting.UnitTest/SchemaTests.cs) - unit test for schema testing
- [ContractTesting.cs](tests/SchemaTesting.UnitTest/ContractTests.cs) - unit test for contract testing
- [schemas](schemas) - versioned schemas used for schema testing
- [events](events) - sample events used for contract testing

## Deploy the sample application

This example includes both local tests and tests that can execute against the Amazon Event Bridge Schema Registry. To use schema registry for testing, you first need to deploy the sample application and then run some load through the system.

```bash
sam build
sam deploy --guided
```

You can make a POST request to the generated API endpoint on the `/customer` route, using the below request body.

```json
{
"firstName": "James",
"lastName": "Eastham",
"address": "Holborn Viaduct, London, Greater London, England, The World"
}
```

Check your Amazon Event Bridge Schema Registry. You will see events under the `com.dev.customer@CustomerCreatedEventV1` heading. It can take a few minutes for new schemas to be registered.

## Run the Tests

### Bash
```
cd ./tests/SchemaTesting.UnitTests
dotnet test
```

### Windows
```
cd .\tests\SchemaTesting.UnitTests
dotnet test
```

[Top](#contents)

---
Loading

0 comments on commit dc45611

Please sign in to comment.