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: 44 additions & 7 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ jobs:
strategy:
matrix:
include:
- { python-version: '3.12', region: us-west-1, access-key-id: '000000000001'}
- { python-version: '3.13', awscli-version: "1.41.0", region: us-west-1, access-key-id: '000000000001'}
- { python-version: '3.13', region: us-west-1, access-key-id: 'test'}
- { python-version: '3.12', region: us-east-1, access-key-id: 'test'}
- { python-version: '3.11', region: us-east-1, access-key-id: 'test'}
- { python-version: '3.10', region: us-east-1, access-key-id: 'test'}
- { python-version: '3.9', region: us-east-1, access-key-id: 'test'}
- { python-version: '3.8', region: us-east-1, access-key-id: 'test'}

env:
AWS_ACCESS_KEY_ID: ${{ matrix.access-key-id }}
Expand All @@ -44,22 +44,59 @@ jobs:
- name: Install deps
run: pip install '.[ver1]'

- name: Install specific version of awscli
if: ${{ matrix.awscli-version }}
run: pip install "awscli==${{ matrix.awscli-version }}"

- name: Check aws-cli version
run: |
aws --version
awslocal --version
which aws
which awslocal

- name: Start and wait for localstack (Community)
- name: Setup BATS
run: |
git clone https://github.com/bats-core/bats-core.git "$HOME"/bats-core
cd "$HOME"/bats-core
sudo ./install.sh /usr/local

- name: Start and wait for LocalStack (Community)
timeout-minutes: 10
run: |
docker pull localstack/localstack:latest
localstack start -d
localstack wait -t 30

- name: Test usage of awslocal
- name: Run bats tests
run: |
awslocal lambda list-functions
awslocal s3api list-buckets
awslocal s3 ls
bats --report-formatter junit -r tests/bin/ --output .
mv report.xml tests-junit-bin-${{ matrix.python-version }}-${{ matrix.awscli-version }}-${{ matrix.region }}-${{ matrix.access-key-id }}.xml

- name: Archive Test Results
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: test-results-tests-bin-${{ matrix.python-version }}-${{ matrix.awscli-version }}-${{ matrix.region }}-${{ matrix.access-key-id }}
path: tests-junit-*.xml
retention-days: 30

report:
runs-on: ubuntu-latest
needs: test
if: success() || failure()
steps:
- name: Download Test Results
uses: actions/download-artifact@v4
with:
pattern: test-results-tests-*
merge-multiple: true

- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
if: success() || failure()
with:
files: tests-junit-*.xml
check_name: "Smoke Tests"
action_fail_on_inconclusive: true

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
*.egg-info/
*.pyc
__pycache__/
/.idea/
/output/*
!/output/.gitkeep
16 changes: 7 additions & 9 deletions bin/awslocal
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ import os
import sys
import subprocess
import re
from threading import Thread

from boto3.session import Session

PARENT_FOLDER = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
S3_VIRTUAL_ENDPOINT_HOSTNAME = 's3.localhost.localstack.cloud'
Expand Down Expand Up @@ -100,6 +97,7 @@ def prepare_environment():

env_dict.pop('AWS_DATA_PATH', None)

from boto3.session import Session
session = Session()
credentials = session.get_credentials()

Expand Down Expand Up @@ -236,14 +234,14 @@ def patch_awscli_libs():
# get stack frame of caller
curframe = inspect.currentframe()
calframe = inspect.getouterframes(curframe, 2)
fname = calframe[1].filename

# check if we are executing within the target method
is_target = (os.path.join('cloudformation', 'deploy.py') in fname
or os.path.join('cloudformation', 'package.py') in fname)
if is_target:
# try to find the Cfn deploy or package frame
cfn_frame = next(filter(lambda frame: os.path.join('cloudformation', 'deploy.py') in frame.filename
or os.path.join('cloudformation', 'package.py') in frame.filename, calframe), None)

if cfn_frame:
if 'endpoint_url' not in kwargs:
args_passed = inspect.getargvalues(calframe[1].frame).locals
args_passed = inspect.getargvalues(cfn_frame.frame).locals
kwargs['endpoint_url'] = args_passed['parsed_args'].s3_endpoint_url
return create_client_orig(*args, **kwargs)

Expand Down
Empty file added output/.gitkeep
Empty file.
57 changes: 57 additions & 0 deletions tests/bin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# BATS tests

The tests in this folder are not regular Pytest tests.
They are implemented with [BATS](https://github.com/bats-core/bats-core) to test `awslocal` from `bash`.

## Prerequisites

**Install BATS**: If you don't have BATS installed, you need to install it first. On a Unix-like system, you can usually install it using a package manager.

For any system with `npm`:
```bash
npm install -g bats
```

For macOS using Homebrew:
```bash
brew install bats-core
```

Alternatively, you can install BATS manually by cloning the repository and adding the `bin` folder to your `PATH` environment variable.
```bash
git clone https://github.com/bats-core/bats-core.git
cd bats-core
sudo ./install.sh /usr/local
```

## Writing tests

Create a file with a `.bats` extension, for example, `test_example.bats`. Here’s a simple test file:

```bash
#!/usr/bin/env bats
@test "test description" {
run echo "hello"
[ "$status" -eq 0 ]
[ "$output" = "hello" ]
}
```

## Running Tests
To run the tests, execute the bats command followed by the test file or directory containing test files:

```bash
bats test_example.bats
```

You can also run all `.bats` files in a directory:

```bash
bats tests/bin
```

To run with some debug information, you can use this:

```bash
bats --trace --verbose-run --print-output-on-failure -r tests/bin/
```
4 changes: 4 additions & 0 deletions tests/bin/cfn_templates/lamba/TestLambda/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "test-lambda",
"version": "0.0.1"
}
1 change: 1 addition & 0 deletions tests/bin/cfn_templates/lamba/TestLambda/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.handler = async (event, context) => { return "Pong!" };
19 changes: 19 additions & 0 deletions tests/bin/cfn_templates/lamba/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
TestLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: TestLambda
CodeUri: TestLambda
Handler: src/app.handler
Runtime: nodejs22.x
TestLambdaUrl:
Type: AWS::Lambda::Url
Properties:
TargetFunctionArn: !GetAtt TestLambda.Arn
AuthType: NONE
Outputs:
LambdaURL:
Description: URL for the Lambda
Value: !GetAtt TestLambdaUrl.FunctionUrl
27 changes: 27 additions & 0 deletions tests/bin/test.cloudformation.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bats

setup_file() {
# Ensure the AWS CLI is configured to use LocalStack
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1

# Create a bucket for the test
awslocal s3 mb s3://cfn-package-lambdas
}

@test "cloudformation package, deploy, execute" {
# Package the template
run awslocal cloudformation package --template $BATS_TEST_DIRNAME/cfn_templates/lamba/template.yaml --output-template output/packaged_template.yaml --s3-bucket cfn-package-lambdas
[ "$status" -eq 0 ]
run awslocal cloudformation deploy --template-file output/packaged_template.yaml --stack-name test-stack
[ "$status" -eq 0 ]
URL=`awslocal cloudformation describe-stacks --stack-name test-stack --query "Stacks[0].Outputs[?OutputKey=='LambdaURL'].OutputValue" --output text`
curl -s $URL | grep "Pong!"
[ "$status" -eq 0 ]
}

teardown_file() {
awslocal cloudformation delete-stack --stack-name test-stack
awslocal s3 rb s3://cfn-package-lambdas --force
}
23 changes: 23 additions & 0 deletions tests/bin/test.smoke.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bats

setup_file() {
# Ensure the AWS CLI is configured to use LocalStack
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
}

@test "lambda list-functions" {
run awslocal lambda list-functions
[ "$status" -eq 0 ]
}

@test "s3api list-buckets" {
run awslocal s3api list-buckets
[ "$status" -eq 0 ]
}

@test "s3 ls" {
run awslocal s3api list-buckets
[ "$status" -eq 0 ]
}