Added create_identity_pool and cleaned up test data.

This commit is contained in:
Barry Ruffner 2018-04-03 11:38:59 -07:00
parent f4f79b2a8e
commit 83f4419d03
6 changed files with 144 additions and 946 deletions

View File

@ -11,6 +11,7 @@ from .autoscaling import mock_autoscaling, mock_autoscaling_deprecated # flake8
from .awslambda import mock_lambda, mock_lambda_deprecated # flake8: noqa from .awslambda import mock_lambda, mock_lambda_deprecated # flake8: noqa
from .cloudformation import mock_cloudformation, mock_cloudformation_deprecated # flake8: noqa from .cloudformation import mock_cloudformation, mock_cloudformation_deprecated # flake8: noqa
from .cloudwatch import mock_cloudwatch, mock_cloudwatch_deprecated # flake8: noqa from .cloudwatch import mock_cloudwatch, mock_cloudwatch_deprecated # flake8: noqa
from .cognitoidentity import mock_cognitoidentity, mock_cognitoidentity_deprecated # flake8: noqa
from .datapipeline import mock_datapipeline, mock_datapipeline_deprecated # flake8: noqa from .datapipeline import mock_datapipeline, mock_datapipeline_deprecated # flake8: noqa
from .dynamodb import mock_dynamodb, mock_dynamodb_deprecated # flake8: noqa from .dynamodb import mock_dynamodb, mock_dynamodb_deprecated # flake8: noqa
from .dynamodb2 import mock_dynamodb2, mock_dynamodb2_deprecated # flake8: noqa from .dynamodb2 import mock_dynamodb2, mock_dynamodb2_deprecated # flake8: noqa

View File

@ -3,5 +3,5 @@ from .models import cognitoidentity_backends
from ..core.models import base_decorator, deprecated_base_decorator from ..core.models import base_decorator, deprecated_base_decorator
cognitoidentity_backend = cognitoidentity_backends['us-east-1'] cognitoidentity_backend = cognitoidentity_backends['us-east-1']
mock_datapipeline = base_decorator(cognitoidentity_backends) mock_cognitoidentity = base_decorator(cognitoidentity_backends)
mock_datapipeline_deprecated = deprecated_base_decorator(cognitoidentity_backends) mock_cognitoidentity_deprecated = deprecated_base_decorator(cognitoidentity_backends)

View File

@ -1,10 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json
import datetime import datetime
import boto.cognito.identity import boto.cognito.identity
from moto.compat import OrderedDict from moto.compat import OrderedDict
from moto.core import BaseBackend, BaseModel from moto.core import BaseBackend, BaseModel
from .utils import get_random_pipeline_id, remove_capitalization_of_dict_keys from moto.core.utils import iso_8601_datetime_with_milliseconds
from .utils import get_random_identity_id, remove_capitalization_of_dict_keys
class CognitoIdentityObject(BaseModel): class CognitoIdentityObject(BaseModel):
@ -24,139 +26,91 @@ class CognitoIdentityObject(BaseModel):
class CognitoIdentity(BaseModel): class CognitoIdentity(BaseModel):
def __init__(self, name, unique_id, **kwargs): def __init__(self, region, identity_pool_name, **kwargs):
self.name = name self.identity_pool_name = identity_pool_name
# self.unique_id = unique_id self.allow_unauthenticated_identities = kwargs.get('allow_unauthenticated_identities', '')
# self.description = kwargs.get('description', '') self.supported_login_providers = kwargs.get('supported_login_providers', {})
self.identity_pool_id = get_random_identity_id() self.developer_provider_name = kwargs.get('developer_provider_name', '')
# self.creation_time = datetime.datetime.utcnow() self.open_id_connect_provider_arns = kwargs.get('open_id_connect_provider_arns', [])
# self.objects = [] self.cognito_identity_providers = kwargs.get('cognito_identity_providers', [])
# self.status = "PENDING" self.saml_provider_arns = kwargs.get('saml_provider_arns', [])
# self.tags = kwargs.get('tags', [])
@property self.identity_pool_id = get_random_identity_id(region)
def physical_resource_id(self): self.creation_time = datetime.datetime.utcnow()
return self.pipeline_id
def to_meta_json(self):
return {
"id": self.pipeline_id,
"name": self.name,
}
def to_json(self):
return {
"description": self.description,
"fields": [{
"key": "@pipelineState",
"stringValue": self.status,
}, {
"key": "description",
"stringValue": self.description
}, {
"key": "name",
"stringValue": self.name
}, {
"key": "@creationTime",
"stringValue": datetime.datetime.strftime(self.creation_time, '%Y-%m-%dT%H-%M-%S'),
}, {
"key": "@id",
"stringValue": self.pipeline_id,
}, {
"key": "@sphere",
"stringValue": "PIPELINE"
}, {
"key": "@version",
"stringValue": "1"
}, {
"key": "@userId",
"stringValue": "924374875933"
}, {
"key": "@accountId",
"stringValue": "924374875933"
}, {
"key": "uniqueId",
"stringValue": self.unique_id
}],
"name": self.name,
"pipelineId": self.pipeline_id,
"tags": self.tags
}
def set_pipeline_objects(self, pipeline_objects):
self.objects = [
PipelineObject(pipeline_object['id'], pipeline_object[
'name'], pipeline_object['fields'])
for pipeline_object in remove_capitalization_of_dict_keys(pipeline_objects)
]
def activate(self):
self.status = "SCHEDULED"
@classmethod
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
datapipeline_backend = cognitoidentity_backends[region_name]
properties = cloudformation_json["Properties"]
cloudformation_unique_id = "cf-" + properties["Name"]
pipeline = datapipeline_backend.create_pipeline(
properties["Name"], cloudformation_unique_id)
datapipeline_backend.put_pipeline_definition(
pipeline.pipeline_id, properties["PipelineObjects"])
if properties["Activate"]:
pipeline.activate()
return pipeline
class CognitoIdentityBackend(BaseBackend): class CognitoIdentityBackend(BaseBackend):
def __init__(self, region): def __init__(self, region):
super(CognitoIdentityBackend, self).__init__()
self.region = region self.region = region
self.identity_pools = OrderedDict() self.identity_pools = OrderedDict()
def create_identity_pool(self, identity_pool_name, allow_unauthenticated_identities, , region='us-east-1',**kwargs): def reset(self):
identity_pool = CognitoIdentity(identity_pool_name, allow_unauthenticated_identities, **kwargs) region = self.region
self.identity_pools[identity_pool.identity_pool_name] = identity_pool self.__dict__ = {}
return identity_pool self.__init__(region)
def delete_identity_pool(self, identity_pool_id): def create_identity_pool(self, identity_pool_name, allow_unauthenticated_identities,
pass supported_login_providers, developer_provider_name, open_id_connect_provider_arns,
cognito_identity_providers, saml_provider_arns):
def list_pipelines(self): new_identity = CognitoIdentity(self.region, identity_pool_name,
return self.pipelines.values() allow_unauthenticated_identities=allow_unauthenticated_identities,
supported_login_providers=supported_login_providers,
developer_provider_name=developer_provider_name,
open_id_connect_provider_arns=open_id_connect_provider_arns,
cognito_identity_providers=cognito_identity_providers,
saml_provider_arns=saml_provider_arns)
self.identity_pools[new_identity.identity_pool_id] = new_identity
def describe_pipelines(self, pipeline_ids): response = json.dumps({
pipelines = [pipeline for pipeline in self.pipelines.values( 'IdentityPoolId': new_identity.identity_pool_id,
) if pipeline.pipeline_id in pipeline_ids] 'IdentityPoolName': new_identity.identity_pool_name,
return pipelines 'AllowUnauthenticatedIdentities': new_identity.allow_unauthenticated_identities,
'SupportedLoginProviders': new_identity.supported_login_providers,
'DeveloperProviderName': new_identity.developer_provider_name,
'OpenIdConnectProviderARNs': new_identity.open_id_connect_provider_arns,
'CognitoIdentityProviders': new_identity.cognito_identity_providers,
'SamlProviderARNs': new_identity.saml_provider_arns
})
def get_pipeline(self, pipeline_id): return response
return self.pipelines[pipeline_id]
def delete_pipeline(self, pipeline_id):
self.pipelines.pop(pipeline_id, None)
def put_pipeline_definition(self, pipeline_id, pipeline_objects): def get_id(self):
pipeline = self.get_pipeline(pipeline_id) identity_id = {'IdentityId': get_random_identity_id(self.region)}
pipeline.set_pipeline_objects(pipeline_objects) return json.dumps(identity_id)
def get_pipeline_definition(self, pipeline_id): def get_credentials_for_identity(self, identity_id):
pipeline = self.get_pipeline(pipeline_id) duration = 90
return pipeline.objects now = datetime.datetime.utcnow()
expiration = now + datetime.timedelta(seconds=duration)
def describe_objects(self, object_ids, pipeline_id): expiration_str = str(iso_8601_datetime_with_milliseconds(expiration))
pipeline = self.get_pipeline(pipeline_id) return json.dumps({
pipeline_objects = [ "Credentials": {
pipeline_object for pipeline_object in pipeline.objects "AccessKeyId": "TESTACCESSKEY12345",
if pipeline_object.object_id in object_ids "Expiration": expiration_str,
] "SecretKey": "ABCSECRETKEY",
return pipeline_objects "SessionToken": "ABC12345"
},
def activate_pipeline(self, pipeline_id): "IdentityId": identity_id
pipeline = self.get_pipeline(pipeline_id) })
pipeline.activate()
def get_open_id_token_for_developer_identity(self, identity_id):
duration = 90
now = datetime.datetime.utcnow()
expiration = now + datetime.timedelta(seconds=duration)
expiration_str = str(iso_8601_datetime_with_milliseconds(expiration))
return json.dumps({
"Credentials": {
"AccessKeyId": "TESTACCESSKEY12345",
"Expiration": expiration_str,
"SecretKey": "ABCSECRETKEY",
"SessionToken": "ABC12345"
},
"IdentityId": identity_id
})
cognitoidentity_backends = {} cognitoidentity_backends = {}
for region in boto.cognito.identity.regions(): for region in boto.cognito.identity.regions():

View File

@ -3,10 +3,10 @@ from __future__ import unicode_literals
import json import json
from moto.core.responses import BaseResponse from moto.core.responses import BaseResponse
from .models import datapipeline_backends from .models import cognitoidentity_backends
class DataPipelineResponse(BaseResponse): class CognitoIdentityResponse(BaseResponse):
@property @property
def parameters(self): def parameters(self):
@ -17,88 +17,32 @@ class DataPipelineResponse(BaseResponse):
return self.querystring return self.querystring
@property @property
def datapipeline_backend(self): def cognitoidentity_backend(self):
return datapipeline_backends[self.region] return cognitoidentity_backends[self.region]
def create_pipeline(self): def create_identity_pool(self):
name = self.parameters.get('name') identity_pool_name = self._get_param('IdentityPoolName')
unique_id = self.parameters.get('uniqueId') allow_unauthenticated_identities = self._get_param('AllowUnauthenticatedIdentities')
description = self.parameters.get('description', '') supported_login_providers = self._get_param('SupportedLoginProviders')
tags = self.parameters.get('tags', []) developer_provider_name = self._get_param('DeveloperProviderName')
pipeline = self.datapipeline_backend.create_pipeline(name, unique_id, description=description, tags=tags) open_id_connect_provider_arns = self._get_param('OpenIdConnectProviderARNs')
return json.dumps({ cognito_identity_providers = self._get_param('CognitoIdentityProviders')
"pipelineId": pipeline.pipeline_id, saml_provider_arns = self._get_param('SamlProviderARNs')
}) return cognitoidentity_backends[self.region].create_identity_pool(
identity_pool_name=identity_pool_name,
allow_unauthenticated_identities=allow_unauthenticated_identities,
supported_login_providers=supported_login_providers,
developer_provider_name=developer_provider_name,
open_id_connect_provider_arns=open_id_connect_provider_arns,
cognito_identity_providers=cognito_identity_providers,
saml_provider_arns=saml_provider_arns)
def list_pipelines(self): def get_id(self):
pipelines = list(self.datapipeline_backend.list_pipelines()) return cognitoidentity_backends[self.region].get_id()
pipeline_ids = [pipeline.pipeline_id for pipeline in pipelines]
max_pipelines = 50
marker = self.parameters.get('marker')
if marker:
start = pipeline_ids.index(marker) + 1
else:
start = 0
pipelines_resp = pipelines[start:start + max_pipelines]
has_more_results = False
marker = None
if start + max_pipelines < len(pipeline_ids) - 1:
has_more_results = True
marker = pipelines_resp[-1].pipeline_id
return json.dumps({
"hasMoreResults": has_more_results,
"marker": marker,
"pipelineIdList": [
pipeline.to_meta_json() for pipeline in pipelines_resp
]
})
def describe_pipelines(self): def get_credentials_for_identity(self):
pipeline_ids = self.parameters["pipelineIds"] return cognitoidentity_backends[self.region].get_credentials_for_identity(self._get_param('IdentityId'))
pipelines = self.datapipeline_backend.describe_pipelines(pipeline_ids)
return json.dumps({ def get_open_id_token_for_developer_identity(self):
"pipelineDescriptionList": [ return cognitoidentity_backends[self.region].get_open_id_token_for_developer_identity(self._get_param('IdentityId'))
pipeline.to_json() for pipeline in pipelines
]
})
def delete_pipeline(self):
pipeline_id = self.parameters["pipelineId"]
self.datapipeline_backend.delete_pipeline(pipeline_id)
return json.dumps({})
def put_pipeline_definition(self):
pipeline_id = self.parameters["pipelineId"]
pipeline_objects = self.parameters["pipelineObjects"]
self.datapipeline_backend.put_pipeline_definition(
pipeline_id, pipeline_objects)
return json.dumps({"errored": False})
def get_pipeline_definition(self):
pipeline_id = self.parameters["pipelineId"]
pipeline_definition = self.datapipeline_backend.get_pipeline_definition(
pipeline_id)
return json.dumps({
"pipelineObjects": [pipeline_object.to_json() for pipeline_object in pipeline_definition]
})
def describe_objects(self):
pipeline_id = self.parameters["pipelineId"]
object_ids = self.parameters["objectIds"]
pipeline_objects = self.datapipeline_backend.describe_objects(
object_ids, pipeline_id)
return json.dumps({
"hasMoreResults": False,
"marker": None,
"pipelineObjects": [
pipeline_object.to_json() for pipeline_object in pipeline_objects
]
})
def activate_pipeline(self):
pipeline_id = self.parameters["pipelineId"]
self.datapipeline_backend.activate_pipeline(pipeline_id)
return json.dumps({})

View File

@ -1,10 +1,10 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from .responses import DataPipelineResponse from .responses import CognitoIdentityResponse
url_bases = [ url_bases = [
"https?://datapipeline.(.+).amazonaws.com", "https?://cognito-identity.(.+).amazonaws.com",
] ]
url_paths = { url_paths = {
'{0}/$': DataPipelineResponse.dispatch, '{0}/$': CognitoIdentityResponse.dispatch,
} }

View File

@ -10,753 +10,52 @@ import zipfile
import sure # noqa import sure # noqa
from freezegun import freeze_time from freezegun import freeze_time
from moto import mock_lambda, mock_s3, mock_ec2, settings from moto import mock_cognitoidentity, settings
_lambda_region = 'us-west-2' @mock_cognitoidentity
def test_create_identity_pool():
conn = boto3.client('cognito-identity', 'us-west-2')
result = conn.create_identity_pool(IdentityPoolName='TestPool',
def _process_lambda(func_str): AllowUnauthenticatedIdentities=False,
zip_output = io.BytesIO() SupportedLoginProviders={'graph.facebook.com':'123456789012345'},
zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED) DeveloperProviderName='devname',
zip_file.writestr('lambda_function.py', func_str) OpenIdConnectProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db',],
zip_file.close() CognitoIdentityProviders=[
zip_output.seek(0) {
return zip_output.read() 'ProviderName': 'testprovider',
'ClientId': 'CLIENT12345',
'ServerSideTokenCheck': True
def get_test_zip_file1():
pfunc = """
def lambda_handler(event, context):
return event
"""
return _process_lambda(pfunc)
def get_test_zip_file2():
func_str = """
import boto3
def lambda_handler(event, context):
ec2 = boto3.resource('ec2', region_name='us-west-2', endpoint_url='http://{base_url}')
volume_id = event.get('volume_id')
vol = ec2.Volume(volume_id)
print('get volume details for %s\\nVolume - %s state=%s, size=%s' % (volume_id, volume_id, vol.state, vol.size))
return event
""".format(base_url="motoserver:5000" if settings.TEST_SERVER_MODE else "ec2.us-west-2.amazonaws.com")
return _process_lambda(func_str)
@mock_lambda
def test_list_functions():
conn = boto3.client('lambda', 'us-west-2')
result = conn.list_functions()
result['Functions'].should.have.length_of(0)
@mock_lambda
def test_invoke_requestresponse_function():
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'ZipFile': get_test_zip_file1(),
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
in_data = {'msg': 'So long and thanks for all the fish'}
success_result = conn.invoke(FunctionName='testFunction', InvocationType='RequestResponse',
Payload=json.dumps(in_data))
success_result["StatusCode"].should.equal(202)
result_obj = json.loads(
base64.b64decode(success_result["LogResult"]).decode('utf-8'))
result_obj.should.equal(in_data)
payload = success_result["Payload"].read().decode('utf-8')
json.loads(payload).should.equal(in_data)
@mock_lambda
def test_invoke_event_function():
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'ZipFile': get_test_zip_file1(),
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
conn.invoke.when.called_with(
FunctionName='notAFunction',
InvocationType='Event',
Payload='{}'
).should.throw(botocore.client.ClientError)
in_data = {'msg': 'So long and thanks for all the fish'}
success_result = conn.invoke(
FunctionName='testFunction', InvocationType='Event', Payload=json.dumps(in_data))
success_result["StatusCode"].should.equal(202)
json.loads(success_result['Payload'].read().decode(
'utf-8')).should.equal({})
if settings.TEST_SERVER_MODE:
@mock_ec2
@mock_lambda
def test_invoke_function_get_ec2_volume():
conn = boto3.resource("ec2", "us-west-2")
vol = conn.create_volume(Size=99, AvailabilityZone='us-west-2')
vol = conn.Volume(vol.id)
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'ZipFile': get_test_zip_file2(),
}, },
Description='test lambda function', ],
Timeout=3, SamlProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db',])
MemorySize=128, assert result['IdentityPoolId'] != ''
Publish=True,
)
in_data = {'volume_id': vol.id} @mock_cognitoidentity
result = conn.invoke(FunctionName='testFunction', def test_get_id():
InvocationType='RequestResponse', Payload=json.dumps(in_data)) conn = boto3.client('cognito-identity', 'us-west-2')
result["StatusCode"].should.equal(202) result = conn.get_id(AccountId='someaccount',
msg = 'get volume details for %s\nVolume - %s state=%s, size=%s\n%s' % ( IdentityPoolId='us-west-2:12345',
vol.id, vol.id, vol.state, vol.size, json.dumps(in_data)) Logins={
'someurl': '12345'
})
assert result['IdentityId'].startswith('us-west-2')
log_result = base64.b64decode(result["LogResult"]).decode('utf-8') @mock_cognitoidentity
def test_get_credentials_for_identity():
conn = boto3.client('cognito-identity', 'us-west-2')
result = conn.get_credentials_for_identity(IdentityId='12345')
assert result['IdentityId'] == '12345'
# fix for running under travis (TODO: investigate why it has an extra newline) @mock_cognitoidentity
log_result = log_result.replace('\n\n', '\n') def test_get_open_id_token_for_developer_identity():
log_result.should.equal(msg) conn = boto3.client('cognito-identity', 'us-west-2')
result = conn.get_open_id_token_for_developer_identity(
payload = result['Payload'].read().decode('utf-8') IdentityPoolId='us-west-2:12345',
IdentityId='12345',
# fix for running under travis (TODO: investigate why it has an extra newline) Logins={
payload = payload.replace('\n\n', '\n') 'someurl': '12345'
payload.should.equal(msg)
@mock_lambda
def test_create_based_on_s3_with_missing_bucket():
conn = boto3.client('lambda', 'us-west-2')
conn.create_function.when.called_with(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'S3Bucket': 'this-bucket-does-not-exist',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
VpcConfig={
"SecurityGroupIds": ["sg-123abc"],
"SubnetIds": ["subnet-123abc"],
},
).should.throw(botocore.client.ClientError)
@mock_lambda
@mock_s3
@freeze_time('2015-01-01 00:00:00')
def test_create_function_from_aws_bucket():
s3_conn = boto3.client('s3', 'us-west-2')
s3_conn.create_bucket(Bucket='test-bucket')
zip_content = get_test_zip_file2()
s3_conn.put_object(Bucket='test-bucket', Key='test.zip', Body=zip_content)
conn = boto3.client('lambda', 'us-west-2')
result = conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
VpcConfig={
"SecurityGroupIds": ["sg-123abc"],
"SubnetIds": ["subnet-123abc"],
}, },
TokenDuration=123
) )
# this is hard to match against, so remove it assert result['IdentityId'] == '12345'
result['ResponseMetadata'].pop('HTTPHeaders', None)
# Botocore inserts retry attempts not seen in Python27
result['ResponseMetadata'].pop('RetryAttempts', None)
result.pop('LastModified')
result.should.equal({
'FunctionName': 'testFunction',
'FunctionArn': 'arn:aws:lambda:{}:123456789012:function:testFunction:$LATEST'.format(_lambda_region),
'Runtime': 'python2.7',
'Role': 'test-iam-role',
'Handler': 'lambda_function.lambda_handler',
"CodeSha256": hashlib.sha256(zip_content).hexdigest(),
"CodeSize": len(zip_content),
'Description': 'test lambda function',
'Timeout': 3,
'MemorySize': 128,
'Version': '$LATEST',
'VpcConfig': {
"SecurityGroupIds": ["sg-123abc"],
"SubnetIds": ["subnet-123abc"],
"VpcId": "vpc-123abc"
},
'ResponseMetadata': {'HTTPStatusCode': 201},
})
@mock_lambda
@freeze_time('2015-01-01 00:00:00')
def test_create_function_from_zipfile():
conn = boto3.client('lambda', 'us-west-2')
zip_content = get_test_zip_file1()
result = conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'ZipFile': zip_content,
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
# this is hard to match against, so remove it
result['ResponseMetadata'].pop('HTTPHeaders', None)
# Botocore inserts retry attempts not seen in Python27
result['ResponseMetadata'].pop('RetryAttempts', None)
result.pop('LastModified')
result.should.equal({
'FunctionName': 'testFunction',
'FunctionArn': 'arn:aws:lambda:{}:123456789012:function:testFunction:$LATEST'.format(_lambda_region),
'Runtime': 'python2.7',
'Role': 'test-iam-role',
'Handler': 'lambda_function.lambda_handler',
'CodeSize': len(zip_content),
'Description': 'test lambda function',
'Timeout': 3,
'MemorySize': 128,
'CodeSha256': hashlib.sha256(zip_content).hexdigest(),
'Version': '$LATEST',
'VpcConfig': {
"SecurityGroupIds": [],
"SubnetIds": [],
},
'ResponseMetadata': {'HTTPStatusCode': 201},
})
@mock_lambda
@mock_s3
@freeze_time('2015-01-01 00:00:00')
def test_get_function():
s3_conn = boto3.client('s3', 'us-west-2')
s3_conn.create_bucket(Bucket='test-bucket')
zip_content = get_test_zip_file1()
s3_conn.put_object(Bucket='test-bucket', Key='test.zip', Body=zip_content)
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
result = conn.get_function(FunctionName='testFunction')
# this is hard to match against, so remove it
result['ResponseMetadata'].pop('HTTPHeaders', None)
# Botocore inserts retry attempts not seen in Python27
result['ResponseMetadata'].pop('RetryAttempts', None)
result['Configuration'].pop('LastModified')
result['Code']['Location'].should.equal('s3://awslambda-{0}-tasks.s3-{0}.amazonaws.com/test.zip'.format(_lambda_region))
result['Code']['RepositoryType'].should.equal('S3')
result['Configuration']['CodeSha256'].should.equal(hashlib.sha256(zip_content).hexdigest())
result['Configuration']['CodeSize'].should.equal(len(zip_content))
result['Configuration']['Description'].should.equal('test lambda function')
result['Configuration'].should.contain('FunctionArn')
result['Configuration']['FunctionName'].should.equal('testFunction')
result['Configuration']['Handler'].should.equal('lambda_function.lambda_handler')
result['Configuration']['MemorySize'].should.equal(128)
result['Configuration']['Role'].should.equal('test-iam-role')
result['Configuration']['Runtime'].should.equal('python2.7')
result['Configuration']['Timeout'].should.equal(3)
result['Configuration']['Version'].should.equal('$LATEST')
result['Configuration'].should.contain('VpcConfig')
# Test get function with
result = conn.get_function(FunctionName='testFunction', Qualifier='$LATEST')
result['Configuration']['Version'].should.equal('$LATEST')
@mock_lambda
@mock_s3
def test_delete_function():
s3_conn = boto3.client('s3', 'us-west-2')
s3_conn.create_bucket(Bucket='test-bucket')
zip_content = get_test_zip_file2()
s3_conn.put_object(Bucket='test-bucket', Key='test.zip', Body=zip_content)
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
success_result = conn.delete_function(FunctionName='testFunction')
# this is hard to match against, so remove it
success_result['ResponseMetadata'].pop('HTTPHeaders', None)
# Botocore inserts retry attempts not seen in Python27
success_result['ResponseMetadata'].pop('RetryAttempts', None)
success_result.should.equal({'ResponseMetadata': {'HTTPStatusCode': 204}})
conn.delete_function.when.called_with(
FunctionName='testFunctionThatDoesntExist').should.throw(botocore.client.ClientError)
@mock_lambda
@mock_s3
def test_publish():
s3_conn = boto3.client('s3', 'us-west-2')
s3_conn.create_bucket(Bucket='test-bucket')
zip_content = get_test_zip_file2()
s3_conn.put_object(Bucket='test-bucket', Key='test.zip', Body=zip_content)
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
function_list = conn.list_functions()
function_list['Functions'].should.have.length_of(1)
latest_arn = function_list['Functions'][0]['FunctionArn']
conn.publish_version(FunctionName='testFunction')
function_list = conn.list_functions()
function_list['Functions'].should.have.length_of(2)
# #SetComprehension ;-)
published_arn = list({f['FunctionArn'] for f in function_list['Functions']} - {latest_arn})[0]
published_arn.should.contain('testFunction:1')
conn.delete_function(FunctionName='testFunction', Qualifier='1')
function_list = conn.list_functions()
function_list['Functions'].should.have.length_of(1)
function_list['Functions'][0]['FunctionArn'].should.contain('testFunction:$LATEST')
@mock_lambda
@mock_s3
@freeze_time('2015-01-01 00:00:00')
def test_list_create_list_get_delete_list():
"""
test `list -> create -> list -> get -> delete -> list` integration
"""
s3_conn = boto3.client('s3', 'us-west-2')
s3_conn.create_bucket(Bucket='test-bucket')
zip_content = get_test_zip_file2()
s3_conn.put_object(Bucket='test-bucket', Key='test.zip', Body=zip_content)
conn = boto3.client('lambda', 'us-west-2')
conn.list_functions()['Functions'].should.have.length_of(0)
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
expected_function_result = {
"Code": {
"Location": "s3://awslambda-{0}-tasks.s3-{0}.amazonaws.com/test.zip".format(_lambda_region),
"RepositoryType": "S3"
},
"Configuration": {
"CodeSha256": hashlib.sha256(zip_content).hexdigest(),
"CodeSize": len(zip_content),
"Description": "test lambda function",
"FunctionArn": 'arn:aws:lambda:{}:123456789012:function:testFunction:$LATEST'.format(_lambda_region),
"FunctionName": "testFunction",
"Handler": "lambda_function.lambda_handler",
"MemorySize": 128,
"Role": "test-iam-role",
"Runtime": "python2.7",
"Timeout": 3,
"Version": '$LATEST',
"VpcConfig": {
"SecurityGroupIds": [],
"SubnetIds": [],
}
},
'ResponseMetadata': {'HTTPStatusCode': 200},
}
func = conn.list_functions()['Functions'][0]
func.pop('LastModified')
func.should.equal(expected_function_result['Configuration'])
func = conn.get_function(FunctionName='testFunction')
# this is hard to match against, so remove it
func['ResponseMetadata'].pop('HTTPHeaders', None)
# Botocore inserts retry attempts not seen in Python27
func['ResponseMetadata'].pop('RetryAttempts', None)
func['Configuration'].pop('LastModified')
func.should.equal(expected_function_result)
conn.delete_function(FunctionName='testFunction')
conn.list_functions()['Functions'].should.have.length_of(0)
@mock_lambda
def test_invoke_lambda_error():
lambda_fx = """
def lambda_handler(event, context):
raise Exception('failsauce')
"""
zip_output = io.BytesIO()
zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED)
zip_file.writestr('lambda_function.py', lambda_fx)
zip_file.close()
zip_output.seek(0)
client = boto3.client('lambda', region_name='us-east-1')
client.create_function(
FunctionName='test-lambda-fx',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
Code={
'ZipFile': zip_output.read()
},
)
result = client.invoke(
FunctionName='test-lambda-fx',
InvocationType='RequestResponse',
LogType='Tail'
)
assert 'FunctionError' in result
assert result['FunctionError'] == 'Handled'
@mock_lambda
@mock_s3
def test_tags():
"""
test list_tags -> tag_resource -> list_tags -> tag_resource -> list_tags -> untag_resource -> list_tags integration
"""
s3_conn = boto3.client('s3', 'us-west-2')
s3_conn.create_bucket(Bucket='test-bucket')
zip_content = get_test_zip_file2()
s3_conn.put_object(Bucket='test-bucket', Key='test.zip', Body=zip_content)
conn = boto3.client('lambda', 'us-west-2')
function = conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
# List tags when there are none
conn.list_tags(
Resource=function['FunctionArn']
)['Tags'].should.equal(dict())
# List tags when there is one
conn.tag_resource(
Resource=function['FunctionArn'],
Tags=dict(spam='eggs')
)['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
conn.list_tags(
Resource=function['FunctionArn']
)['Tags'].should.equal(dict(spam='eggs'))
# List tags when another has been added
conn.tag_resource(
Resource=function['FunctionArn'],
Tags=dict(foo='bar')
)['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
conn.list_tags(
Resource=function['FunctionArn']
)['Tags'].should.equal(dict(spam='eggs', foo='bar'))
# Untag resource
conn.untag_resource(
Resource=function['FunctionArn'],
TagKeys=['spam', 'trolls']
)['ResponseMetadata']['HTTPStatusCode'].should.equal(204)
conn.list_tags(
Resource=function['FunctionArn']
)['Tags'].should.equal(dict(foo='bar'))
# Untag a tag that does not exist (no error and no change)
conn.untag_resource(
Resource=function['FunctionArn'],
TagKeys=['spam']
)['ResponseMetadata']['HTTPStatusCode'].should.equal(204)
@mock_lambda
def test_tags_not_found():
"""
Test list_tags and tag_resource when the lambda with the given arn does not exist
"""
conn = boto3.client('lambda', 'us-west-2')
conn.list_tags.when.called_with(
Resource='arn:aws:lambda:123456789012:function:not-found'
).should.throw(botocore.client.ClientError)
conn.tag_resource.when.called_with(
Resource='arn:aws:lambda:123456789012:function:not-found',
Tags=dict(spam='eggs')
).should.throw(botocore.client.ClientError)
conn.untag_resource.when.called_with(
Resource='arn:aws:lambda:123456789012:function:not-found',
TagKeys=['spam']
).should.throw(botocore.client.ClientError)
@mock_lambda
def test_invoke_async_function():
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.lambda_handler',
Code={'ZipFile': get_test_zip_file1()},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
success_result = conn.invoke_async(
FunctionName='testFunction',
InvokeArgs=json.dumps({'test': 'event'})
)
success_result['Status'].should.equal(202)
@mock_lambda
@freeze_time('2015-01-01 00:00:00')
def test_get_function_created_with_zipfile():
conn = boto3.client('lambda', 'us-west-2')
zip_content = get_test_zip_file1()
result = conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.handler',
Code={
'ZipFile': zip_content,
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
response = conn.get_function(
FunctionName='testFunction'
)
response['Configuration'].pop('LastModified')
response['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
assert len(response['Code']) == 2
assert response['Code']['RepositoryType'] == 'S3'
assert response['Code']['Location'].startswith('s3://awslambda-{0}-tasks.s3-{0}.amazonaws.com'.format(_lambda_region))
response['Configuration'].should.equal(
{
"CodeSha256": hashlib.sha256(zip_content).hexdigest(),
"CodeSize": len(zip_content),
"Description": "test lambda function",
"FunctionArn":'arn:aws:lambda:{}:123456789012:function:testFunction:$LATEST'.format(_lambda_region),
"FunctionName": "testFunction",
"Handler": "lambda_function.handler",
"MemorySize": 128,
"Role": "test-iam-role",
"Runtime": "python2.7",
"Timeout": 3,
"Version": '$LATEST',
"VpcConfig": {
"SecurityGroupIds": [],
"SubnetIds": [],
}
},
)
@mock_lambda
def add_function_permission():
conn = boto3.client('lambda', 'us-west-2')
zip_content = get_test_zip_file1()
result = conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.handler',
Code={
'ZipFile': zip_content,
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
response = conn.add_permission(
FunctionName='testFunction',
StatementId='1',
Action="lambda:InvokeFunction",
Principal='432143214321',
SourceArn="arn:aws:lambda:us-west-2:account-id:function:helloworld",
SourceAccount='123412341234',
EventSourceToken='blah',
Qualifier='2'
)
assert 'Statement' in response
res = json.loads(response['Statement'])
assert res['Action'] == "lambda:InvokeFunction"
@mock_lambda
def get_function_policy():
conn = boto3.client('lambda', 'us-west-2')
zip_content = get_test_zip_file1()
result = conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_function.handler',
Code={
'ZipFile': zip_content,
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
response = conn.add_permission(
FunctionName='testFunction',
StatementId='1',
Action="lambda:InvokeFunction",
Principal='432143214321',
SourceArn="arn:aws:lambda:us-west-2:account-id:function:helloworld",
SourceAccount='123412341234',
EventSourceToken='blah',
Qualifier='2'
)
response = conn.get_policy(
FunctionName='testFunction'
)
assert 'Policy' in response
assert isinstance(response['Policy'], str)
res = json.loads(response['Policy'])
assert res['Statement'][0]['Action'] == 'lambda:InvokeFunction'