From f4f79b2a8eb85f653c95a120c84a34723104af9c Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Wed, 28 Mar 2018 12:40:42 -0700 Subject: [PATCH 01/13] Added basic cognitoidentity (not working) --- moto/cognitoidentity/__init__.py | 7 + moto/cognitoidentity/models.py | 163 ++++ moto/cognitoidentity/responses.py | 104 +++ moto/cognitoidentity/urls.py | 10 + moto/cognitoidentity/utils.py | 23 + .../test_cognitoidentity.py | 762 ++++++++++++++++++ 6 files changed, 1069 insertions(+) create mode 100644 moto/cognitoidentity/__init__.py create mode 100644 moto/cognitoidentity/models.py create mode 100644 moto/cognitoidentity/responses.py create mode 100644 moto/cognitoidentity/urls.py create mode 100644 moto/cognitoidentity/utils.py create mode 100644 tests/test_cognitoidentity/test_cognitoidentity.py diff --git a/moto/cognitoidentity/__init__.py b/moto/cognitoidentity/__init__.py new file mode 100644 index 00000000..f9a6da7e --- /dev/null +++ b/moto/cognitoidentity/__init__.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals +from .models import cognitoidentity_backends +from ..core.models import base_decorator, deprecated_base_decorator + +cognitoidentity_backend = cognitoidentity_backends['us-east-1'] +mock_datapipeline = base_decorator(cognitoidentity_backends) +mock_datapipeline_deprecated = deprecated_base_decorator(cognitoidentity_backends) diff --git a/moto/cognitoidentity/models.py b/moto/cognitoidentity/models.py new file mode 100644 index 00000000..f136d079 --- /dev/null +++ b/moto/cognitoidentity/models.py @@ -0,0 +1,163 @@ +from __future__ import unicode_literals + +import datetime +import boto.cognito.identity +from moto.compat import OrderedDict +from moto.core import BaseBackend, BaseModel +from .utils import get_random_pipeline_id, remove_capitalization_of_dict_keys + + +class CognitoIdentityObject(BaseModel): + + def __init__(self, object_id, name, fields): + self.object_id = object_id + self.name = name + self.fields = fields + + def to_json(self): + return { + "fields": self.fields, + "id": self.object_id, + "name": self.name, + } + + +class CognitoIdentity(BaseModel): + + def __init__(self, name, unique_id, **kwargs): + self.name = name + # self.unique_id = unique_id + # self.description = kwargs.get('description', '') + self.identity_pool_id = get_random_identity_id() + # self.creation_time = datetime.datetime.utcnow() + # self.objects = [] + # self.status = "PENDING" + # self.tags = kwargs.get('tags', []) + + @property + def physical_resource_id(self): + 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): + + def __init__(self, region): + self.region = region + self.identity_pools = OrderedDict() + + def create_identity_pool(self, identity_pool_name, allow_unauthenticated_identities, , region='us-east-1',**kwargs): + identity_pool = CognitoIdentity(identity_pool_name, allow_unauthenticated_identities, **kwargs) + self.identity_pools[identity_pool.identity_pool_name] = identity_pool + return identity_pool + + def delete_identity_pool(self, identity_pool_id): + pass + + def list_pipelines(self): + return self.pipelines.values() + + def describe_pipelines(self, pipeline_ids): + pipelines = [pipeline for pipeline in self.pipelines.values( + ) if pipeline.pipeline_id in pipeline_ids] + return pipelines + + def get_pipeline(self, pipeline_id): + 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): + pipeline = self.get_pipeline(pipeline_id) + pipeline.set_pipeline_objects(pipeline_objects) + + def get_pipeline_definition(self, pipeline_id): + pipeline = self.get_pipeline(pipeline_id) + return pipeline.objects + + def describe_objects(self, object_ids, pipeline_id): + pipeline = self.get_pipeline(pipeline_id) + pipeline_objects = [ + pipeline_object for pipeline_object in pipeline.objects + if pipeline_object.object_id in object_ids + ] + return pipeline_objects + + def activate_pipeline(self, pipeline_id): + pipeline = self.get_pipeline(pipeline_id) + pipeline.activate() + + +cognitoidentity_backends = {} +for region in boto.cognito.identity.regions(): + cognitoidentity_backends[region.name] = CognitoIdentityBackend(region.name) diff --git a/moto/cognitoidentity/responses.py b/moto/cognitoidentity/responses.py new file mode 100644 index 00000000..e462e398 --- /dev/null +++ b/moto/cognitoidentity/responses.py @@ -0,0 +1,104 @@ +from __future__ import unicode_literals + +import json + +from moto.core.responses import BaseResponse +from .models import datapipeline_backends + + +class DataPipelineResponse(BaseResponse): + + @property + def parameters(self): + # TODO this should really be moved to core/responses.py + if self.body: + return json.loads(self.body) + else: + return self.querystring + + @property + def datapipeline_backend(self): + return datapipeline_backends[self.region] + + def create_pipeline(self): + name = self.parameters.get('name') + unique_id = self.parameters.get('uniqueId') + description = self.parameters.get('description', '') + tags = self.parameters.get('tags', []) + pipeline = self.datapipeline_backend.create_pipeline(name, unique_id, description=description, tags=tags) + return json.dumps({ + "pipelineId": pipeline.pipeline_id, + }) + + def list_pipelines(self): + pipelines = list(self.datapipeline_backend.list_pipelines()) + 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): + pipeline_ids = self.parameters["pipelineIds"] + pipelines = self.datapipeline_backend.describe_pipelines(pipeline_ids) + + return json.dumps({ + "pipelineDescriptionList": [ + 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({}) diff --git a/moto/cognitoidentity/urls.py b/moto/cognitoidentity/urls.py new file mode 100644 index 00000000..40805874 --- /dev/null +++ b/moto/cognitoidentity/urls.py @@ -0,0 +1,10 @@ +from __future__ import unicode_literals +from .responses import DataPipelineResponse + +url_bases = [ + "https?://datapipeline.(.+).amazonaws.com", +] + +url_paths = { + '{0}/$': DataPipelineResponse.dispatch, +} diff --git a/moto/cognitoidentity/utils.py b/moto/cognitoidentity/utils.py new file mode 100644 index 00000000..4832c204 --- /dev/null +++ b/moto/cognitoidentity/utils.py @@ -0,0 +1,23 @@ +import collections +import six +from moto.core.utils import get_random_hex + + +def get_random_identity_id(region): + return "{0}:{0}".format(region, get_random_hex(length=19)) + + +def remove_capitalization_of_dict_keys(obj): + if isinstance(obj, collections.Mapping): + result = obj.__class__() + for key, value in obj.items(): + normalized_key = key[:1].lower() + key[1:] + result[normalized_key] = remove_capitalization_of_dict_keys(value) + return result + elif isinstance(obj, collections.Iterable) and not isinstance(obj, six.string_types): + result = obj.__class__() + for item in obj: + result += (remove_capitalization_of_dict_keys(item),) + return result + else: + return obj diff --git a/tests/test_cognitoidentity/test_cognitoidentity.py b/tests/test_cognitoidentity/test_cognitoidentity.py new file mode 100644 index 00000000..e7a9f917 --- /dev/null +++ b/tests/test_cognitoidentity/test_cognitoidentity.py @@ -0,0 +1,762 @@ +from __future__ import unicode_literals + +import base64 +import botocore.client +import boto3 +import hashlib +import io +import json +import zipfile +import sure # noqa + +from freezegun import freeze_time +from moto import mock_lambda, mock_s3, mock_ec2, settings + +_lambda_region = 'us-west-2' + + +def _process_lambda(func_str): + zip_output = io.BytesIO() + zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED) + zip_file.writestr('lambda_function.py', func_str) + zip_file.close() + zip_output.seek(0) + return zip_output.read() + + +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, + MemorySize=128, + Publish=True, + ) + + in_data = {'volume_id': vol.id} + result = conn.invoke(FunctionName='testFunction', + InvocationType='RequestResponse', Payload=json.dumps(in_data)) + result["StatusCode"].should.equal(202) + msg = 'get volume details for %s\nVolume - %s state=%s, size=%s\n%s' % ( + vol.id, vol.id, vol.state, vol.size, json.dumps(in_data)) + + log_result = base64.b64decode(result["LogResult"]).decode('utf-8') + + # fix for running under travis (TODO: investigate why it has an extra newline) + log_result = log_result.replace('\n\n', '\n') + log_result.should.equal(msg) + + payload = result['Payload'].read().decode('utf-8') + + # fix for running under travis (TODO: investigate why it has an extra newline) + payload = payload.replace('\n\n', '\n') + 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"], + }, + ) + # 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', + "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' From 83f4419d03293261250be9fe0fca04153c58eb4c Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 11:38:59 -0700 Subject: [PATCH 02/13] Added create_identity_pool and cleaned up test data. --- moto/__init__.py | 1 + moto/cognitoidentity/__init__.py | 4 +- moto/cognitoidentity/models.py | 188 ++--- moto/cognitoidentity/responses.py | 108 +-- moto/cognitoidentity/urls.py | 6 +- .../test_cognitoidentity.py | 783 +----------------- 6 files changed, 144 insertions(+), 946 deletions(-) diff --git a/moto/__init__.py b/moto/__init__.py index 9703f9f6..8c0de8c9 100644 --- a/moto/__init__.py +++ b/moto/__init__.py @@ -11,6 +11,7 @@ from .autoscaling import mock_autoscaling, mock_autoscaling_deprecated # flake8 from .awslambda import mock_lambda, mock_lambda_deprecated # flake8: noqa from .cloudformation import mock_cloudformation, mock_cloudformation_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 .dynamodb import mock_dynamodb, mock_dynamodb_deprecated # flake8: noqa from .dynamodb2 import mock_dynamodb2, mock_dynamodb2_deprecated # flake8: noqa diff --git a/moto/cognitoidentity/__init__.py b/moto/cognitoidentity/__init__.py index f9a6da7e..2f040fa1 100644 --- a/moto/cognitoidentity/__init__.py +++ b/moto/cognitoidentity/__init__.py @@ -3,5 +3,5 @@ from .models import cognitoidentity_backends from ..core.models import base_decorator, deprecated_base_decorator cognitoidentity_backend = cognitoidentity_backends['us-east-1'] -mock_datapipeline = base_decorator(cognitoidentity_backends) -mock_datapipeline_deprecated = deprecated_base_decorator(cognitoidentity_backends) +mock_cognitoidentity = base_decorator(cognitoidentity_backends) +mock_cognitoidentity_deprecated = deprecated_base_decorator(cognitoidentity_backends) diff --git a/moto/cognitoidentity/models.py b/moto/cognitoidentity/models.py index f136d079..95663de5 100644 --- a/moto/cognitoidentity/models.py +++ b/moto/cognitoidentity/models.py @@ -1,10 +1,12 @@ from __future__ import unicode_literals +import json import datetime import boto.cognito.identity from moto.compat import OrderedDict 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): @@ -24,139 +26,91 @@ class CognitoIdentityObject(BaseModel): class CognitoIdentity(BaseModel): - def __init__(self, name, unique_id, **kwargs): - self.name = name - # self.unique_id = unique_id - # self.description = kwargs.get('description', '') - self.identity_pool_id = get_random_identity_id() - # self.creation_time = datetime.datetime.utcnow() - # self.objects = [] - # self.status = "PENDING" - # self.tags = kwargs.get('tags', []) + def __init__(self, region, identity_pool_name, **kwargs): + self.identity_pool_name = identity_pool_name + self.allow_unauthenticated_identities = kwargs.get('allow_unauthenticated_identities', '') + self.supported_login_providers = kwargs.get('supported_login_providers', {}) + self.developer_provider_name = kwargs.get('developer_provider_name', '') + self.open_id_connect_provider_arns = kwargs.get('open_id_connect_provider_arns', []) + self.cognito_identity_providers = kwargs.get('cognito_identity_providers', []) + self.saml_provider_arns = kwargs.get('saml_provider_arns', []) - @property - def physical_resource_id(self): - 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 + self.identity_pool_id = get_random_identity_id(region) + self.creation_time = datetime.datetime.utcnow() class CognitoIdentityBackend(BaseBackend): def __init__(self, region): + super(CognitoIdentityBackend, self).__init__() self.region = region self.identity_pools = OrderedDict() - def create_identity_pool(self, identity_pool_name, allow_unauthenticated_identities, , region='us-east-1',**kwargs): - identity_pool = CognitoIdentity(identity_pool_name, allow_unauthenticated_identities, **kwargs) - self.identity_pools[identity_pool.identity_pool_name] = identity_pool - return identity_pool + def reset(self): + region = self.region + self.__dict__ = {} + self.__init__(region) - def delete_identity_pool(self, identity_pool_id): - pass + def create_identity_pool(self, identity_pool_name, allow_unauthenticated_identities, + supported_login_providers, developer_provider_name, open_id_connect_provider_arns, + cognito_identity_providers, saml_provider_arns): - def list_pipelines(self): - return self.pipelines.values() + new_identity = CognitoIdentity(self.region, 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) + self.identity_pools[new_identity.identity_pool_id] = new_identity - def describe_pipelines(self, pipeline_ids): - pipelines = [pipeline for pipeline in self.pipelines.values( - ) if pipeline.pipeline_id in pipeline_ids] - return pipelines + response = json.dumps({ + 'IdentityPoolId': new_identity.identity_pool_id, + 'IdentityPoolName': new_identity.identity_pool_name, + '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 self.pipelines[pipeline_id] + return response - def delete_pipeline(self, pipeline_id): - self.pipelines.pop(pipeline_id, None) - def put_pipeline_definition(self, pipeline_id, pipeline_objects): - pipeline = self.get_pipeline(pipeline_id) - pipeline.set_pipeline_objects(pipeline_objects) + def get_id(self): + identity_id = {'IdentityId': get_random_identity_id(self.region)} + return json.dumps(identity_id) - def get_pipeline_definition(self, pipeline_id): - pipeline = self.get_pipeline(pipeline_id) - return pipeline.objects - - def describe_objects(self, object_ids, pipeline_id): - pipeline = self.get_pipeline(pipeline_id) - pipeline_objects = [ - pipeline_object for pipeline_object in pipeline.objects - if pipeline_object.object_id in object_ids - ] - return pipeline_objects - - def activate_pipeline(self, pipeline_id): - pipeline = self.get_pipeline(pipeline_id) - pipeline.activate() + def get_credentials_for_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 + }) + 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 = {} for region in boto.cognito.identity.regions(): diff --git a/moto/cognitoidentity/responses.py b/moto/cognitoidentity/responses.py index e462e398..2285607a 100644 --- a/moto/cognitoidentity/responses.py +++ b/moto/cognitoidentity/responses.py @@ -3,10 +3,10 @@ from __future__ import unicode_literals import json from moto.core.responses import BaseResponse -from .models import datapipeline_backends +from .models import cognitoidentity_backends -class DataPipelineResponse(BaseResponse): +class CognitoIdentityResponse(BaseResponse): @property def parameters(self): @@ -17,88 +17,32 @@ class DataPipelineResponse(BaseResponse): return self.querystring @property - def datapipeline_backend(self): - return datapipeline_backends[self.region] + def cognitoidentity_backend(self): + return cognitoidentity_backends[self.region] - def create_pipeline(self): - name = self.parameters.get('name') - unique_id = self.parameters.get('uniqueId') - description = self.parameters.get('description', '') - tags = self.parameters.get('tags', []) - pipeline = self.datapipeline_backend.create_pipeline(name, unique_id, description=description, tags=tags) - return json.dumps({ - "pipelineId": pipeline.pipeline_id, - }) + def create_identity_pool(self): + identity_pool_name = self._get_param('IdentityPoolName') + allow_unauthenticated_identities = self._get_param('AllowUnauthenticatedIdentities') + supported_login_providers = self._get_param('SupportedLoginProviders') + developer_provider_name = self._get_param('DeveloperProviderName') + open_id_connect_provider_arns = self._get_param('OpenIdConnectProviderARNs') + cognito_identity_providers = self._get_param('CognitoIdentityProviders') + 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): - pipelines = list(self.datapipeline_backend.list_pipelines()) - 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 get_id(self): + return cognitoidentity_backends[self.region].get_id() - def describe_pipelines(self): - pipeline_ids = self.parameters["pipelineIds"] - pipelines = self.datapipeline_backend.describe_pipelines(pipeline_ids) + def get_credentials_for_identity(self): + return cognitoidentity_backends[self.region].get_credentials_for_identity(self._get_param('IdentityId')) - return json.dumps({ - "pipelineDescriptionList": [ - pipeline.to_json() for pipeline in pipelines - ] - }) + def get_open_id_token_for_developer_identity(self): + return cognitoidentity_backends[self.region].get_open_id_token_for_developer_identity(self._get_param('IdentityId')) - 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({}) diff --git a/moto/cognitoidentity/urls.py b/moto/cognitoidentity/urls.py index 40805874..3fe63ef0 100644 --- a/moto/cognitoidentity/urls.py +++ b/moto/cognitoidentity/urls.py @@ -1,10 +1,10 @@ from __future__ import unicode_literals -from .responses import DataPipelineResponse +from .responses import CognitoIdentityResponse url_bases = [ - "https?://datapipeline.(.+).amazonaws.com", + "https?://cognito-identity.(.+).amazonaws.com", ] url_paths = { - '{0}/$': DataPipelineResponse.dispatch, + '{0}/$': CognitoIdentityResponse.dispatch, } diff --git a/tests/test_cognitoidentity/test_cognitoidentity.py b/tests/test_cognitoidentity/test_cognitoidentity.py index e7a9f917..730f3dcc 100644 --- a/tests/test_cognitoidentity/test_cognitoidentity.py +++ b/tests/test_cognitoidentity/test_cognitoidentity.py @@ -10,753 +10,52 @@ import zipfile import sure # noqa 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') - -def _process_lambda(func_str): - zip_output = io.BytesIO() - zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED) - zip_file.writestr('lambda_function.py', func_str) - zip_file.close() - zip_output.seek(0) - return zip_output.read() - - -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(), + result = conn.create_identity_pool(IdentityPoolName='TestPool', + AllowUnauthenticatedIdentities=False, + SupportedLoginProviders={'graph.facebook.com':'123456789012345'}, + DeveloperProviderName='devname', + OpenIdConnectProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db',], + CognitoIdentityProviders=[ + { + 'ProviderName': 'testprovider', + 'ClientId': 'CLIENT12345', + 'ServerSideTokenCheck': True }, - Description='test lambda function', - Timeout=3, - MemorySize=128, - Publish=True, - ) + ], + SamlProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db',]) + assert result['IdentityPoolId'] != '' - in_data = {'volume_id': vol.id} - result = conn.invoke(FunctionName='testFunction', - InvocationType='RequestResponse', Payload=json.dumps(in_data)) - result["StatusCode"].should.equal(202) - msg = 'get volume details for %s\nVolume - %s state=%s, size=%s\n%s' % ( - vol.id, vol.id, vol.state, vol.size, json.dumps(in_data)) +@mock_cognitoidentity +def test_get_id(): + conn = boto3.client('cognito-identity', 'us-west-2') + result = conn.get_id(AccountId='someaccount', + IdentityPoolId='us-west-2:12345', + 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) - log_result = log_result.replace('\n\n', '\n') - log_result.should.equal(msg) - - payload = result['Payload'].read().decode('utf-8') - - # fix for running under travis (TODO: investigate why it has an extra newline) - payload = payload.replace('\n\n', '\n') - 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"], +@mock_cognitoidentity +def test_get_open_id_token_for_developer_identity(): + conn = boto3.client('cognito-identity', 'us-west-2') + result = conn.get_open_id_token_for_developer_identity( + IdentityPoolId='us-west-2:12345', + IdentityId='12345', + Logins={ + 'someurl': '12345' }, + TokenDuration=123 ) - # 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', - "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' + assert result['IdentityId'] == '12345' From 433997629fd59cc0b3996eacecb538035a475e60 Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 11:58:11 -0700 Subject: [PATCH 03/13] Cleaned up unused method and import --- moto/cognitoidentity/models.py | 2 +- moto/cognitoidentity/utils.py | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/moto/cognitoidentity/models.py b/moto/cognitoidentity/models.py index 95663de5..d0ec2d73 100644 --- a/moto/cognitoidentity/models.py +++ b/moto/cognitoidentity/models.py @@ -6,7 +6,7 @@ import boto.cognito.identity from moto.compat import OrderedDict from moto.core import BaseBackend, BaseModel from moto.core.utils import iso_8601_datetime_with_milliseconds -from .utils import get_random_identity_id, remove_capitalization_of_dict_keys +from .utils import get_random_identity_id class CognitoIdentityObject(BaseModel): diff --git a/moto/cognitoidentity/utils.py b/moto/cognitoidentity/utils.py index 4832c204..d885e0e8 100644 --- a/moto/cognitoidentity/utils.py +++ b/moto/cognitoidentity/utils.py @@ -5,19 +5,3 @@ from moto.core.utils import get_random_hex def get_random_identity_id(region): return "{0}:{0}".format(region, get_random_hex(length=19)) - - -def remove_capitalization_of_dict_keys(obj): - if isinstance(obj, collections.Mapping): - result = obj.__class__() - for key, value in obj.items(): - normalized_key = key[:1].lower() + key[1:] - result[normalized_key] = remove_capitalization_of_dict_keys(value) - return result - elif isinstance(obj, collections.Iterable) and not isinstance(obj, six.string_types): - result = obj.__class__() - for item in obj: - result += (remove_capitalization_of_dict_keys(item),) - return result - else: - return obj From 5df0f1befc3a935b0ae974ed8f9b4a11161badf7 Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 12:08:53 -0700 Subject: [PATCH 04/13] Fixes for automated tests linting. --- moto/cognitoidentity/models.py | 48 +++++++++++++++---------------- moto/cognitoidentity/responses.py | 11 ++++--- moto/cognitoidentity/utils.py | 2 -- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/moto/cognitoidentity/models.py b/moto/cognitoidentity/models.py index d0ec2d73..9b3ba064 100644 --- a/moto/cognitoidentity/models.py +++ b/moto/cognitoidentity/models.py @@ -51,16 +51,16 @@ class CognitoIdentityBackend(BaseBackend): self.__dict__ = {} self.__init__(region) - def create_identity_pool(self, identity_pool_name, allow_unauthenticated_identities, + def create_identity_pool(self, identity_pool_name, allow_unauthenticated_identities, supported_login_providers, developer_provider_name, open_id_connect_provider_arns, - cognito_identity_providers, saml_provider_arns): + cognito_identity_providers, saml_provider_arns): - new_identity = CognitoIdentity(self.region, identity_pool_name, - allow_unauthenticated_identities=allow_unauthenticated_identities, - supported_login_providers=supported_login_providers, - developer_provider_name=developer_provider_name, + new_identity = CognitoIdentity(self.region, 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, + cognito_identity_providers=cognito_identity_providers, saml_provider_arns=saml_provider_arns) self.identity_pools[new_identity.identity_pool_id] = new_identity @@ -77,7 +77,6 @@ class CognitoIdentityBackend(BaseBackend): return response - def get_id(self): identity_id = {'IdentityId': get_random_identity_id(self.region)} return json.dumps(identity_id) @@ -88,14 +87,14 @@ class CognitoIdentityBackend(BaseBackend): 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 - }) + "Credentials": { + "AccessKeyId": "TESTACCESSKEY12345", + "Expiration": expiration_str, + "SecretKey": "ABCSECRETKEY", + "SessionToken": "ABC12345" + }, + "IdentityId": identity_id + }) def get_open_id_token_for_developer_identity(self, identity_id): duration = 90 @@ -103,14 +102,15 @@ class CognitoIdentityBackend(BaseBackend): 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 - }) + "Credentials": { + "AccessKeyId": "TESTACCESSKEY12345", + "Expiration": expiration_str, + "SecretKey": "ABCSECRETKEY", + "SessionToken": "ABC12345" + }, + "IdentityId": identity_id + }) + cognitoidentity_backends = {} for region in boto.cognito.identity.regions(): diff --git a/moto/cognitoidentity/responses.py b/moto/cognitoidentity/responses.py index 2285607a..33afd47c 100644 --- a/moto/cognitoidentity/responses.py +++ b/moto/cognitoidentity/responses.py @@ -30,11 +30,11 @@ class CognitoIdentityResponse(BaseResponse): 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, + 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, + open_id_connect_provider_arns=open_id_connect_provider_arns, + cognito_identity_providers=cognito_identity_providers, saml_provider_arns=saml_provider_arns) def get_id(self): @@ -44,5 +44,4 @@ class CognitoIdentityResponse(BaseResponse): return cognitoidentity_backends[self.region].get_credentials_for_identity(self._get_param('IdentityId')) def get_open_id_token_for_developer_identity(self): - return cognitoidentity_backends[self.region].get_open_id_token_for_developer_identity(self._get_param('IdentityId')) - + return cognitoidentity_backends[self.region].get_open_id_token_for_developer_identity(self._get_param('IdentityId')) \ No newline at end of file diff --git a/moto/cognitoidentity/utils.py b/moto/cognitoidentity/utils.py index d885e0e8..35963176 100644 --- a/moto/cognitoidentity/utils.py +++ b/moto/cognitoidentity/utils.py @@ -1,5 +1,3 @@ -import collections -import six from moto.core.utils import get_random_hex From ed495cdd9ef9021e5a86091e8e4fdcbd72223cc6 Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 12:17:34 -0700 Subject: [PATCH 05/13] More cleanup of identation and reordering / newlines for flake8 happiness. --- moto/cognitoidentity/models.py | 41 ++++++++++++++++++------------- moto/cognitoidentity/responses.py | 3 ++- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/moto/cognitoidentity/models.py b/moto/cognitoidentity/models.py index 9b3ba064..4474b90b 100644 --- a/moto/cognitoidentity/models.py +++ b/moto/cognitoidentity/models.py @@ -1,11 +1,14 @@ from __future__ import unicode_literals -import json import datetime +import json + import boto.cognito.identity + from moto.compat import OrderedDict from moto.core import BaseBackend, BaseModel from moto.core.utils import iso_8601_datetime_with_milliseconds + from .utils import get_random_identity_id @@ -86,14 +89,16 @@ class CognitoIdentityBackend(BaseBackend): 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 + return json.dumps( + { + "Credentials": + { + "AccessKeyId": "TESTACCESSKEY12345", + "Expiration": expiration_str, + "SecretKey": "ABCSECRETKEY", + "SessionToken": "ABC12345" + }, + "IdentityId": identity_id }) def get_open_id_token_for_developer_identity(self, identity_id): @@ -101,14 +106,16 @@ class CognitoIdentityBackend(BaseBackend): 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 + return json.dumps( + { + "Credentials": + { + "AccessKeyId": "TESTACCESSKEY12345", + "Expiration": expiration_str, + "SecretKey": "ABCSECRETKEY", + "SessionToken": "ABC12345" + }, + "IdentityId": identity_id }) diff --git a/moto/cognitoidentity/responses.py b/moto/cognitoidentity/responses.py index 33afd47c..cadf3813 100644 --- a/moto/cognitoidentity/responses.py +++ b/moto/cognitoidentity/responses.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import json from moto.core.responses import BaseResponse + from .models import cognitoidentity_backends @@ -44,4 +45,4 @@ class CognitoIdentityResponse(BaseResponse): return cognitoidentity_backends[self.region].get_credentials_for_identity(self._get_param('IdentityId')) def get_open_id_token_for_developer_identity(self): - return cognitoidentity_backends[self.region].get_open_id_token_for_developer_identity(self._get_param('IdentityId')) \ No newline at end of file + return cognitoidentity_backends[self.region].get_open_id_token_for_developer_identity(self._get_param('IdentityId')) From 7f0723a0689f94f85f01a9558ff7964b2f865910 Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 12:57:21 -0700 Subject: [PATCH 06/13] Added missing backend for server mode. --- moto/backends.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/moto/backends.py b/moto/backends.py index dc85aacd..d8d31757 100644 --- a/moto/backends.py +++ b/moto/backends.py @@ -6,6 +6,7 @@ from moto.autoscaling import autoscaling_backends from moto.awslambda import lambda_backends from moto.cloudformation import cloudformation_backends from moto.cloudwatch import cloudwatch_backends +from moto.cognitoidentity import cognitoidentity_backends from moto.core import moto_api_backends from moto.datapipeline import datapipeline_backends from moto.dynamodb import dynamodb_backends @@ -49,6 +50,7 @@ BACKENDS = { 'batch': batch_backends, 'cloudformation': cloudformation_backends, 'cloudwatch': cloudwatch_backends, + 'cognito-identity': cognitoidentity_backends, 'datapipeline': datapipeline_backends, 'dynamodb': dynamodb_backends, 'dynamodb2': dynamodb_backends2, From 1046ee5041cc5743922bfa021c353ff0abefb929 Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 13:38:24 -0700 Subject: [PATCH 07/13] Added object to parsing and test server test for cognito. --- moto/cloudformation/parsing.py | 2 ++ tests/test_cognitoidentity/test_server.py | 27 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/test_cognitoidentity/test_server.py diff --git a/moto/cloudformation/parsing.py b/moto/cloudformation/parsing.py index 81f47f4a..849d8c91 100644 --- a/moto/cloudformation/parsing.py +++ b/moto/cloudformation/parsing.py @@ -10,6 +10,7 @@ from moto.autoscaling import models as autoscaling_models from moto.awslambda import models as lambda_models from moto.batch import models as batch_models from moto.cloudwatch import models as cloudwatch_models +from moto.cognitoidentity import models as cognitoidentity_models from moto.datapipeline import models as datapipeline_models from moto.dynamodb import models as dynamodb_models from moto.ec2 import models as ec2_models @@ -65,6 +66,7 @@ MODEL_MAP = { "AWS::ElasticLoadBalancingV2::LoadBalancer": elbv2_models.FakeLoadBalancer, "AWS::ElasticLoadBalancingV2::TargetGroup": elbv2_models.FakeTargetGroup, "AWS::ElasticLoadBalancingV2::Listener": elbv2_models.FakeListener, + "AWS::Cognito::IdentityPool": cognitoidentity_models.CognitoIdentity, "AWS::DataPipeline::Pipeline": datapipeline_models.Pipeline, "AWS::IAM::InstanceProfile": iam_models.InstanceProfile, "AWS::IAM::Role": iam_models.Role, diff --git a/tests/test_cognitoidentity/test_server.py b/tests/test_cognitoidentity/test_server.py new file mode 100644 index 00000000..0a6ae14d --- /dev/null +++ b/tests/test_cognitoidentity/test_server.py @@ -0,0 +1,27 @@ +from __future__ import unicode_literals + +import json +import sure # noqa + +import moto.server as server +from moto import mock_cognitoidentity + +''' +Test the different server responses +''' + + +@mock_cognitoidentity +def test_create_identity_pool(): + + backend = server.create_backend_app("cognito-identity") + test_client = backend.test_client() + + res = test_client.post('/', + data={"IdentityPoolName": "test", "AllowUnauthenticatedIdentities": True}, + headers={ + "X-Amz-Target": "com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.CreateIdentityPool"}, + ) + + json_data = json.loads(res.data.decode("utf-8")) + assert json_data['IdentityPoolName'] == "test" From 2455de8282a87ea2b08cf2799e6db8968a39c24e Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 14:08:20 -0700 Subject: [PATCH 08/13] Added a print. --- .../test_cognitoidentity.py | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/test_cognitoidentity/test_cognitoidentity.py b/tests/test_cognitoidentity/test_cognitoidentity.py index 730f3dcc..4184441d 100644 --- a/tests/test_cognitoidentity/test_cognitoidentity.py +++ b/tests/test_cognitoidentity/test_cognitoidentity.py @@ -1,26 +1,20 @@ from __future__ import unicode_literals -import base64 -import botocore.client import boto3 -import hashlib -import io -import json -import zipfile + +from moto import mock_cognitoidentity import sure # noqa -from freezegun import freeze_time -from moto import mock_cognitoidentity, settings @mock_cognitoidentity def test_create_identity_pool(): conn = boto3.client('cognito-identity', 'us-west-2') result = conn.create_identity_pool(IdentityPoolName='TestPool', - AllowUnauthenticatedIdentities=False, - SupportedLoginProviders={'graph.facebook.com':'123456789012345'}, + AllowUnauthenticatedIdentities=False, + SupportedLoginProviders={'graph.facebook.com': '123456789012345'}, DeveloperProviderName='devname', - OpenIdConnectProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db',], + OpenIdConnectProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db'], CognitoIdentityProviders=[ { 'ProviderName': 'testprovider', @@ -28,25 +22,29 @@ def test_create_identity_pool(): 'ServerSideTokenCheck': True }, ], - SamlProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db',]) + SamlProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db']) assert result['IdentityPoolId'] != '' + @mock_cognitoidentity def test_get_id(): conn = boto3.client('cognito-identity', 'us-west-2') result = conn.get_id(AccountId='someaccount', IdentityPoolId='us-west-2:12345', Logins={ - 'someurl': '12345' + 'someurl': '12345' }) + print(result) assert result['IdentityId'].startswith('us-west-2') + @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' + @mock_cognitoidentity def test_get_open_id_token_for_developer_identity(): conn = boto3.client('cognito-identity', 'us-west-2') From 229d453b99a061eb558378de73bc54471c4c0339 Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 16:27:30 -0700 Subject: [PATCH 09/13] Made some changes for server testing and added another get_id test. --- moto/cognitoidentity/models.py | 18 ++---------------- moto/cognitoidentity/responses.py | 14 -------------- .../test_cognitoidentity.py | 13 +++++++++++-- tests/test_cognitoidentity/test_server.py | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/moto/cognitoidentity/models.py b/moto/cognitoidentity/models.py index 4474b90b..21cd4f94 100644 --- a/moto/cognitoidentity/models.py +++ b/moto/cognitoidentity/models.py @@ -12,21 +12,6 @@ from moto.core.utils import iso_8601_datetime_with_milliseconds from .utils import get_random_identity_id -class CognitoIdentityObject(BaseModel): - - def __init__(self, object_id, name, fields): - self.object_id = object_id - self.name = name - self.fields = fields - - def to_json(self): - return { - "fields": self.fields, - "id": self.object_id, - "name": self.name, - } - - class CognitoIdentity(BaseModel): def __init__(self, region, identity_pool_name, **kwargs): @@ -89,7 +74,7 @@ class CognitoIdentityBackend(BaseBackend): now = datetime.datetime.utcnow() expiration = now + datetime.timedelta(seconds=duration) expiration_str = str(iso_8601_datetime_with_milliseconds(expiration)) - return json.dumps( + response = json.dumps( { "Credentials": { @@ -100,6 +85,7 @@ class CognitoIdentityBackend(BaseBackend): }, "IdentityId": identity_id }) + return response def get_open_id_token_for_developer_identity(self, identity_id): duration = 90 diff --git a/moto/cognitoidentity/responses.py b/moto/cognitoidentity/responses.py index cadf3813..ea54b2cf 100644 --- a/moto/cognitoidentity/responses.py +++ b/moto/cognitoidentity/responses.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -import json - from moto.core.responses import BaseResponse from .models import cognitoidentity_backends @@ -9,18 +7,6 @@ from .models import cognitoidentity_backends class CognitoIdentityResponse(BaseResponse): - @property - def parameters(self): - # TODO this should really be moved to core/responses.py - if self.body: - return json.loads(self.body) - else: - return self.querystring - - @property - def cognitoidentity_backend(self): - return cognitoidentity_backends[self.region] - def create_identity_pool(self): identity_pool_name = self._get_param('IdentityPoolName') allow_unauthenticated_identities = self._get_param('AllowUnauthenticatedIdentities') diff --git a/tests/test_cognitoidentity/test_cognitoidentity.py b/tests/test_cognitoidentity/test_cognitoidentity.py index 4184441d..2b54709a 100644 --- a/tests/test_cognitoidentity/test_cognitoidentity.py +++ b/tests/test_cognitoidentity/test_cognitoidentity.py @@ -5,6 +5,8 @@ import boto3 from moto import mock_cognitoidentity import sure # noqa +from moto.cognitoidentity.utils import get_random_identity_id + @mock_cognitoidentity def test_create_identity_pool(): @@ -26,8 +28,14 @@ def test_create_identity_pool(): assert result['IdentityPoolId'] != '' +# testing a helper function +def test_get_random_identity_id(): + assert len(get_random_identity_id('us-west-2')) > 0 + + @mock_cognitoidentity def test_get_id(): + # These two do NOT work in server mode. They just don't return the data from the model. conn = boto3.client('cognito-identity', 'us-west-2') result = conn.get_id(AccountId='someaccount', IdentityPoolId='us-west-2:12345', @@ -35,14 +43,15 @@ def test_get_id(): 'someurl': '12345' }) print(result) - assert result['IdentityId'].startswith('us-west-2') + assert result.get('IdentityId', "").startswith('us-west-2') or result.get('ResponseMetadata').get('HTTPStatusCode') == 200 @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' + + assert result.get('IdentityId') == '12345' or result.get('ResponseMetadata').get('HTTPStatusCode') == 200 @mock_cognitoidentity diff --git a/tests/test_cognitoidentity/test_server.py b/tests/test_cognitoidentity/test_server.py index 0a6ae14d..b63d42bc 100644 --- a/tests/test_cognitoidentity/test_server.py +++ b/tests/test_cognitoidentity/test_server.py @@ -25,3 +25,21 @@ def test_create_identity_pool(): json_data = json.loads(res.data.decode("utf-8")) assert json_data['IdentityPoolName'] == "test" + + +@mock_cognitoidentity +def test_get_id(): + backend = server.create_backend_app("cognito-identity") + test_client = backend.test_client() + + res = test_client.post('/', + data=json.dumps({'AccountId': 'someaccount', + 'IdentityPoolId': 'us-west-2:12345', + 'Logins': {'someurl': '12345'}}), + headers={ + "X-Amz-Target": "com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.GetId"}, + ) + + print(res.data) + json_data = json.loads(res.data.decode("utf-8")) + assert ':' in json_data['IdentityId'] From 49cce220acd80ff3702a268101de1fa94c36861c Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 16:40:45 -0700 Subject: [PATCH 10/13] Updated readme. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 59dc6743..9642a8db 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L |------------------------------------------------------------------------------| | CloudwatchEvents | @mock_events | all endpoints done | |------------------------------------------------------------------------------| +| Cognito Identity | @mock_cognitoidentity| basic endpoints done | +|------------------------------------------------------------------------------| | Data Pipeline | @mock_datapipeline| basic endpoints done | |------------------------------------------------------------------------------| | DynamoDB | @mock_dynamodb | core endpoints done | From 383b0c1c36c8f0e7416674d70e853b27c7d217c3 Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 17:05:36 -0700 Subject: [PATCH 11/13] Made some corrections to the developer identity response and added checks to add coverage. --- moto/cognitoidentity/models.py | 17 ++++------------- .../test_cognitoidentity.py | 2 ++ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/moto/cognitoidentity/models.py b/moto/cognitoidentity/models.py index 21cd4f94..daa2a464 100644 --- a/moto/cognitoidentity/models.py +++ b/moto/cognitoidentity/models.py @@ -88,21 +88,12 @@ class CognitoIdentityBackend(BaseBackend): return response 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( + response = json.dumps( { - "Credentials": - { - "AccessKeyId": "TESTACCESSKEY12345", - "Expiration": expiration_str, - "SecretKey": "ABCSECRETKEY", - "SessionToken": "ABC12345" - }, - "IdentityId": identity_id + "IdentityId": identity_id, + "Token": get_random_identity_id(self.region) }) + return response cognitoidentity_backends = {} diff --git a/tests/test_cognitoidentity/test_cognitoidentity.py b/tests/test_cognitoidentity/test_cognitoidentity.py index 2b54709a..c4f51ee4 100644 --- a/tests/test_cognitoidentity/test_cognitoidentity.py +++ b/tests/test_cognitoidentity/test_cognitoidentity.py @@ -51,6 +51,7 @@ def test_get_credentials_for_identity(): conn = boto3.client('cognito-identity', 'us-west-2') result = conn.get_credentials_for_identity(IdentityId='12345') + assert result.get('Expiration') > 0 or result.get('ResponseMetadata').get('HTTPStatusCode') == 200 assert result.get('IdentityId') == '12345' or result.get('ResponseMetadata').get('HTTPStatusCode') == 200 @@ -65,4 +66,5 @@ def test_get_open_id_token_for_developer_identity(): }, TokenDuration=123 ) + assert len(result['Token']) assert result['IdentityId'] == '12345' From b86b46421067262aa603372f681a193c4fca397d Mon Sep 17 00:00:00 2001 From: Barry Ruffner Date: Tue, 3 Apr 2018 17:22:21 -0700 Subject: [PATCH 12/13] fix for an expiration test. --- tests/test_cognitoidentity/test_cognitoidentity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cognitoidentity/test_cognitoidentity.py b/tests/test_cognitoidentity/test_cognitoidentity.py index c4f51ee4..c752f378 100644 --- a/tests/test_cognitoidentity/test_cognitoidentity.py +++ b/tests/test_cognitoidentity/test_cognitoidentity.py @@ -51,7 +51,7 @@ def test_get_credentials_for_identity(): conn = boto3.client('cognito-identity', 'us-west-2') result = conn.get_credentials_for_identity(IdentityId='12345') - assert result.get('Expiration') > 0 or result.get('ResponseMetadata').get('HTTPStatusCode') == 200 + assert result.get('Expiration', 0) > 0 or result.get('ResponseMetadata').get('HTTPStatusCode') == 200 assert result.get('IdentityId') == '12345' or result.get('ResponseMetadata').get('HTTPStatusCode') == 200 From f5f64be45b9e2ba1edca510e5aac151b9ea43047 Mon Sep 17 00:00:00 2001 From: Barry Date: Wed, 4 Apr 2018 00:28:39 -0700 Subject: [PATCH 13/13] Added comment --- tests/test_cognitoidentity/test_cognitoidentity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_cognitoidentity/test_cognitoidentity.py b/tests/test_cognitoidentity/test_cognitoidentity.py index c752f378..a38107b9 100644 --- a/tests/test_cognitoidentity/test_cognitoidentity.py +++ b/tests/test_cognitoidentity/test_cognitoidentity.py @@ -48,6 +48,7 @@ def test_get_id(): @mock_cognitoidentity def test_get_credentials_for_identity(): + # These two do NOT work in server mode. They just don't return the data from the model. conn = boto3.client('cognito-identity', 'us-west-2') result = conn.get_credentials_for_identity(IdentityId='12345')