Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
51 changes: 51 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Run on LocalStack

on:
push:
paths-ignore:
- 'README.md'
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:

jobs:
chaos:
name: Run the chaos demo
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'

- name: Install lstk
run: |
npm install -g @localstack/lstk
lstk setup aws --force --non-interactive

- name: Build the demo
run: dotnet build ChaosEngDemo

- name: Start LocalStack
env:
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
run: lstk start

- name: Run tests
run: make test

- name: Show LocalStack logs
if: failure()
run: lstk logs | tail -200
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ logs: ## Save the logs in a separate file
@lstk logs > logs.txt

run: ## Run the chaos demo
dotnet run
dotnet run --project ChaosEngDemo

.PHONY: usage install start stop logs run
test: ## Run the demo with and without a DynamoDB fault injected
./test.sh

.PHONY: usage install start stop logs run test
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ make start
* Retrieve the item and print its attributes to the console.
* Handle any exceptions that may occur during these operations.

3. **Test the error handling:** `make test` runs the demo twice. The first run has a fault injected on DynamoDB `PutItem` through the [LocalStack Chaos API](https://docs.localstack.cloud/aws/capabilities/chaos-engineering/chaos-api/), so the program reports the `AccessDeniedException`. The second run has no fault and reads the item back.

## Key Concepts

* **LocalStack:** Provides a local AWS cloud stack for development and testing. This allows you to run the demo without needing a real AWS account.
Expand Down
52 changes: 52 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash
# Run the demo twice:
# 1. with a fault injected on DynamoDB PutItem through the LocalStack Chaos API,
# and check the program reports the AWS SDK exception
# 2. without the fault, and check the item is stored and read back
set -euo pipefail

ENDPOINT=${ENDPOINT:-http://localhost:4566}
RUN_DEMO=${RUN_DEMO:-dotnet run --project ChaosEngDemo}
# A non-retryable error, so the SDK fails fast instead of backing off
FAULT='[{"service": "dynamodb", "region": "us-east-1", "operation": "PutItem", "probability": 1.0,
"error": {"statusCode": 400, "code": "AccessDeniedException"}}]'

remove_fault() {
curl -s -X DELETE "$ENDPOINT/_localstack/chaos/faults" -H 'Content-Type: application/json' -d "$FAULT" > /dev/null
}
trap remove_fault EXIT

echo "Injecting a fault on DynamoDB PutItem"
curl -s --fail-with-body -X POST "$ENDPOINT/_localstack/chaos/faults" \
-H 'Content-Type: application/json' -d "$FAULT" > /dev/null

output=$($RUN_DEMO 2>&1)
echo "$output"
if [[ "$output" != *"AWS SDK Exception caught!"* || "$output" != *"Error Code: AccessDeniedException"* ]]; then
echo "Test failed: the demo did not report the injected fault"
exit 1
fi
if [[ "$output" == *"Item inserted."* ]]; then
echo "Test failed: the item was inserted despite the fault"
exit 1
fi
echo "PASS: the demo caught the injected AccessDeniedException"

remove_fault
echo "Fault removed, running the demo again"

output=$($RUN_DEMO 2>&1)
echo "$output"
if [[ "$output" != *"Item retrieved:"* || "$output" != *"Name: Chaos Widget"* ]]; then
echo "Test failed: the demo did not read the item back"
exit 1
fi
name=$(lstk aws dynamodb get-item --table-name Products --key '{"Id": {"S": "123"}}' \
--query Item.Name.S --output text)
if [ "$name" != "Chaos Widget" ]; then
echo "Test failed: item 123 in the Products table has name '$name'"
exit 1
fi
echo "PASS: the item was stored in DynamoDB and read back"

echo "Test passed: the demo handles DynamoDB faults and recovers once they are gone"
Loading