|
Size: 3896
Comment:
|
← Revision 23 as of 2026-08-22 18:57:31 ⇥
Size: 7951
Comment:
|
| Deletions are marked like this. | Additions are marked like this. |
| Line 1: | Line 1: |
| <<TableOfContents(2)>> | |
| Line 63: | Line 64: |
| === start-moto.sh === {{{#!highlight sh #!/bin/sh docker compose up }}} === build.sh === {{{#!highlight sh #!/bin/bash # sudo apt install python3-pip PACKAGE_NAME="py-my-function.zip" BUILD_DIR="dist" HANDLER_FILE="lambda_function.py" TEST_FILE="test_lambda.py" echo "Cleaning up old builds" rm -rf $BUILD_DIR rm -f $PACKAGE_NAME mkdir $BUILD_DIR echo "Installing dependencies in $BUILD_DIR ..." pip3 install -r requirements.txt -t $BUILD_DIR/ echo "Running tests..." export PYTHONPATH=$PYTHONPATH:$(pwd)/$BUILD_DIR python3 -m unittest $TEST_FILE if [ $? -eq 0 ]; then echo "Tests passed! Proceeding to build..." else echo "Tests failed. Build aborted." exit 1 fi echo "Clean up pycache" find $BUILD_DIR -type d -name "__pycache__" -exec rm -rf {} + echo "Copy source code" cp $HANDLER_FILE $BUILD_DIR/ echo "Creating the ZIP $PACKAGE_NAME" cd $BUILD_DIR zip -r ../$PACKAGE_NAME . cd .. echo "Deployment package ready: $PACKAGE_NAME" }}} === test.sh === {{{#!highlight sh #!/bin/bash # sudo apt install python3-pip PACKAGE_NAME="py-my-function.zip" BUILD_DIR="dist" HANDLER_FILE="lambda_function.py" TEST_FILE="test_lambda.py" echo "Cleaning up old builds" rm -rf $BUILD_DIR rm -f $PACKAGE_NAME mkdir $BUILD_DIR echo "Installing dependencies in $BUILD_DIR ..." pip3 install -r requirements.txt -t $BUILD_DIR/ echo "Running tests..." export PYTHONPATH=$PYTHONPATH:$(pwd)/$BUILD_DIR python3 -m unittest $TEST_FILE if [ $? -eq 0 ]; then echo "Tests passed! Proceeding to build..." else echo "Tests failed. Build aborted." exit 1 fi }}} === compose.yaml === {{{#!highlight yaml services: motoserver: image: motoserver/moto:latest ports: - "4000:4000" environment: - MOTO_PORT=4000 # set moto listener port with env var - MOTO_DOCKER_NETWORK_NAME=motoserver_default # docker network ls volumes: - "/var/run/docker.sock:/var/run/docker.sock" }}} === test_lambda.py === {{{#!highlight python import os import unittest from unittest.mock import patch, MagicMock from lambda_function import lambda_handler class TestLambda(unittest.TestCase): @patch.dict(os.environ, {'AWS_ACCESS_KEY_ID':'xxx1'}) @patch.dict(os.environ, {'AWS_SECRET_ACCESS_KEY':'xxx2'}) @patch.dict(os.environ, {'AWS_DEFAULT_REGION':'xxx3'}) @patch.dict(os.environ, {'AWS_ENDPOINT_URL':'xxx4'}) @patch('lambda_function.get_s3_client') @patch('lambda_function.get_buckets') def test_handler_success(self, mock_get_buckets, mock_get_s3client): # mock function get_buckets return value mock_get_buckets.return_value=['aaaa','bbb'] # the return value for get_s3_client is a MagicMock mock_get_s3client.return_value=MagicMock() # when s3_client.create_bucket is called it returns dictionary cow chicken mock_get_s3client.return_value.create_bucket.return_value = {'cow':'chicken'} # Execute lambda handler event = {'first_name':'aaa','last_name':'bbb'} context = None response = lambda_handler(event, context) self.assertEqual(response['message'],"Hello aaa bbb! <class 'dict'> {\"cow\": \"chicken\"}") if __name__ == '__main__': unittest.main() }}} === requirements.txt === {{{ boto3 moto }}} |
|
| Line 67: | Line 192: |
| import json import datetime def get_s3_client(): session = boto3.session.Session() s3_client = session.client( service_name='s3', endpoint_url='http://motoserver:4000' ) return s3_client def get_buckets(s3_client): buckets=[] for bucket in s3_client.list_buckets()['Buckets']: buckets.append(bucket['Name']) return buckets |
|
| Line 70: | Line 208: |
| session = boto3.session.Session() s3 = session.client( service_name='s3', endpoint_url='http://motoserver:4000' ) buckets=[] for bucket in s3.list_buckets()['Buckets']: buckets.append(bucket['Name']) response = s3.create_bucket(Bucket='examplebucket') |
s3_client = get_s3_client() buckets=get_buckets(s3_client) response = s3_client.create_bucket(Bucket='examplebucket') assert isinstance(response,dict) |
| Line 80: | Line 216: |
| 'message' : message, | 'message' : "%s %s %s"%(message , str(type(response)) , json.dumps(response) ), |
| Line 82: | Line 218: |
| 'currdatetime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), | |
| Line 88: | Line 225: |
| s3.put_object(Body=str(body), Bucket='examplebucket', Key='examplebucket/response.txt') | s3_client.put_object(Body=str(body), Bucket='examplebucket', Key='examplebucket/response.txt') |
| Line 91: | Line 228: |
| """ deploy.sh aws s3 ls aws s3api get-object --bucket examplebucket --key examplebucket/response.txt r1.txt cat r1.txt """ |
|
| Line 94: | Line 237: |
| {{{#!highlight shell | {{{#!highlight sh |
| Line 102: | Line 245: |
zip py-my-function.zip lambda_function.py aws lambda delete-function --function-name py-my-function aws iam delete-role --role-name lambda-ex aws iam create-role --role-name lambda-ex --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}' |
# export DOCKER_HOST=unix:///var/run/docker.sock ROLE_NAME=lambda-ex LAMBDA_FUNCTION_NAME=py-my-function ZIP_NAME=py-my-function.zip MODULE_NAME=lambda_function zip $ZIP_NAME $MODULE_NAME.py aws lambda delete-function --function-name $LAMBDA_FUNCTION_NAME aws iam delete-role --role-name $ROLE_NAME aws iam create-role --role-name $ROLE_NAME --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}' |
| Line 112: | Line 261: |
aws lambda create-function --function-name py-my-function \ --zip-file fileb://py-my-function.zip \ --handler lambda_function.lambda_handler --runtime python3.14 \ --role $ROLE_ARN --timeout 30 |
aws lambda create-function --function-name $LAMBDA_FUNCTION_NAME --zip-file fileb://$ZIP_NAME --handler $MODULE_NAME.lambda_handler --runtime python3.14 --role $ROLE_ARN --timeout 120 |
| Line 119: | Line 263: |
| Line 120: | Line 265: |
| aws lambda invoke --function-name py-my-function --payload $PAYLOAD response.json | aws lambda invoke --function-name $LAMBDA_FUNCTION_NAME --payload $PAYLOAD response.json |
| Line 122: | Line 268: |
| cat response.json aws s3 ls aws lambda list-functions }}} |
cat response.json | jq . }}} |
moto
A python library that allows you to easily mock out tests based on AWS infrastructure.
Install AWS CLI
Create S3 bucket
1 export AWS_ACCESS_KEY_ID='testing'
2 export AWS_SECRET_ACCESS_KEY='testing'
3 export AWS_SECURITY_TOKEN='testing'
4 export AWS_SESSION_TOKEN='testing'
5 export AWS_DEFAULT_REGION='us-east-1'
6 export AWS_ENDPOINT_URL="http://localhost:4000"
7
8 docker run --rm -p 4000:4000 --name moto motoserver/moto:latest
compose.yaml
1 docker compose up
2 docker compose exec motoserver sh
3 # in the container
4 cat /etc/os-release
5 # NAME="Alpine Linux"
6 exit
7
8 aws s3 ls
9 aws s3api create-bucket --bucket my-bucket
10 # https://docs.aws.amazon.com/cli/latest/reference/s3api/
11 echo "test" > test.txt
12 aws s3api put-object --bucket my-bucket --key dir-1/test.txt --body test.txt
13 aws s3api get-object --bucket my-bucket --key dir-1/test.txt test2.txt
14 cat test2.txt
15 aws s3 ls
Create lambda function
start-moto.sh
build.sh
1 #!/bin/bash
2 # sudo apt install python3-pip
3 PACKAGE_NAME="py-my-function.zip"
4 BUILD_DIR="dist"
5 HANDLER_FILE="lambda_function.py"
6 TEST_FILE="test_lambda.py"
7
8 echo "Cleaning up old builds"
9 rm -rf $BUILD_DIR
10 rm -f $PACKAGE_NAME
11 mkdir $BUILD_DIR
12 echo "Installing dependencies in $BUILD_DIR ..."
13 pip3 install -r requirements.txt -t $BUILD_DIR/
14 echo "Running tests..."
15 export PYTHONPATH=$PYTHONPATH:$(pwd)/$BUILD_DIR
16 python3 -m unittest $TEST_FILE
17
18 if [ $? -eq 0 ]; then
19 echo "Tests passed! Proceeding to build..."
20 else
21 echo "Tests failed. Build aborted."
22 exit 1
23 fi
24
25 echo "Clean up pycache"
26 find $BUILD_DIR -type d -name "__pycache__" -exec rm -rf {} +
27 echo "Copy source code"
28 cp $HANDLER_FILE $BUILD_DIR/
29 echo "Creating the ZIP $PACKAGE_NAME"
30 cd $BUILD_DIR
31 zip -r ../$PACKAGE_NAME .
32 cd ..
33 echo "Deployment package ready: $PACKAGE_NAME"
test.sh
1 #!/bin/bash
2 # sudo apt install python3-pip
3 PACKAGE_NAME="py-my-function.zip"
4 BUILD_DIR="dist"
5 HANDLER_FILE="lambda_function.py"
6 TEST_FILE="test_lambda.py"
7
8 echo "Cleaning up old builds"
9 rm -rf $BUILD_DIR
10 rm -f $PACKAGE_NAME
11 mkdir $BUILD_DIR
12 echo "Installing dependencies in $BUILD_DIR ..."
13 pip3 install -r requirements.txt -t $BUILD_DIR/
14 echo "Running tests..."
15 export PYTHONPATH=$PYTHONPATH:$(pwd)/$BUILD_DIR
16 python3 -m unittest $TEST_FILE
17
18 if [ $? -eq 0 ]; then
19 echo "Tests passed! Proceeding to build..."
20 else
21 echo "Tests failed. Build aborted."
22 exit 1
23 fi
compose.yaml
test_lambda.py
1 import os
2 import unittest
3 from unittest.mock import patch, MagicMock
4 from lambda_function import lambda_handler
5
6 class TestLambda(unittest.TestCase):
7 @patch.dict(os.environ, {'AWS_ACCESS_KEY_ID':'xxx1'})
8 @patch.dict(os.environ, {'AWS_SECRET_ACCESS_KEY':'xxx2'})
9 @patch.dict(os.environ, {'AWS_DEFAULT_REGION':'xxx3'})
10 @patch.dict(os.environ, {'AWS_ENDPOINT_URL':'xxx4'})
11 @patch('lambda_function.get_s3_client')
12 @patch('lambda_function.get_buckets')
13 def test_handler_success(self, mock_get_buckets, mock_get_s3client):
14 # mock function get_buckets return value
15 mock_get_buckets.return_value=['aaaa','bbb']
16
17 # the return value for get_s3_client is a MagicMock
18 mock_get_s3client.return_value=MagicMock()
19 # when s3_client.create_bucket is called it returns dictionary cow chicken
20 mock_get_s3client.return_value.create_bucket.return_value = {'cow':'chicken'}
21
22 # Execute lambda handler
23 event = {'first_name':'aaa','last_name':'bbb'}
24 context = None
25
26 response = lambda_handler(event, context)
27 self.assertEqual(response['message'],"Hello aaa bbb! <class 'dict'> {\"cow\": \"chicken\"}")
28
29 if __name__ == '__main__':
30 unittest.main()
requirements.txt
boto3 moto
lambda_function.py
1 import boto3
2 import os
3 import json
4 import datetime
5
6 def get_s3_client():
7 session = boto3.session.Session()
8 s3_client = session.client( service_name='s3', endpoint_url='http://motoserver:4000' )
9 return s3_client
10
11 def get_buckets(s3_client):
12 buckets=[]
13 for bucket in s3_client.list_buckets()['Buckets']:
14 buckets.append(bucket['Name'])
15 return buckets
16
17 def lambda_handler(event, context):
18 message = 'Hello {} {}!'.format(event['first_name'], event['last_name'])
19 s3_client = get_s3_client()
20
21 buckets=get_buckets(s3_client)
22
23 response = s3_client.create_bucket(Bucket='examplebucket')
24 assert isinstance(response,dict)
25
26 body = {
27 'message' : "%s %s %s"%(message , str(type(response)) , json.dumps(response) ),
28 'buckets' : buckets,
29 'currdatetime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
30 'AWS_ACCESS_KEY_ID' : os.environ["AWS_ACCESS_KEY_ID"],
31 'AWS_SECRET_ACCESS_KEY' : os.environ["AWS_SECRET_ACCESS_KEY"],
32 'AWS_DEFAULT_REGION' : os.environ["AWS_DEFAULT_REGION"],
33 'AWS_ENDPOINT_URL': os.environ['AWS_ENDPOINT_URL']
34 }
35
36 s3_client.put_object(Body=str(body), Bucket='examplebucket', Key='examplebucket/response.txt')
37 return body
38
39 """
40 deploy.sh
41 aws s3 ls
42 aws s3api get-object --bucket examplebucket --key examplebucket/response.txt r1.txt
43 cat r1.txt
44 """
deploy.sh
1 #!/bin/sh
2 export AWS_ACCESS_KEY_ID='testing'
3 export AWS_SECRET_ACCESS_KEY='testing'
4 export AWS_SECURITY_TOKEN='testing'
5 export AWS_SESSION_TOKEN='testing'
6 export AWS_DEFAULT_REGION='us-east-1'
7 export AWS_ENDPOINT_URL="http://localhost:4000"
8 # export DOCKER_HOST=unix:///var/run/docker.sock
9
10 ROLE_NAME=lambda-ex
11 LAMBDA_FUNCTION_NAME=py-my-function
12 ZIP_NAME=py-my-function.zip
13 MODULE_NAME=lambda_function
14
15 zip $ZIP_NAME $MODULE_NAME.py
16 aws lambda delete-function --function-name $LAMBDA_FUNCTION_NAME
17 aws iam delete-role --role-name $ROLE_NAME
18
19 aws iam create-role --role-name $ROLE_NAME --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'
20
21 ROLE_ARN=$(aws iam list-roles | jq ".Roles[0].Arn" | sed 's/\"//g')
22
23 echo "Role Arn $ROLE_ARN"
24 aws lambda create-function --function-name $LAMBDA_FUNCTION_NAME --zip-file fileb://$ZIP_NAME --handler $MODULE_NAME.lambda_handler --runtime python3.14 --role $ROLE_ARN --timeout 120
25 PAYLOAD=$( echo "{ \"first_name\": \"Bob\",\"last_name\":\"Squarepants\" }" | base64 )
26
27 echo "Invoke lambda"
28 aws lambda invoke --function-name $LAMBDA_FUNCTION_NAME --payload $PAYLOAD response.json
29
30 echo "Show response"
31 cat response.json | jq .
