From 6c577091da23efe7ccf0b24fdd81a64fbff2dd1f Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Thu, 6 Oct 2016 19:52:23 +1000 Subject: [PATCH 1/8] lambderize the moto lambda --- moto/awslambda/models.py | 56 +++++++++-- moto/awslambda/responses.py | 2 +- tests/test_awslambda/test_lambda.py | 97 +++++++++++++------ .../test_cloudformation_stack_integration.py | 39 +++++--- 4 files changed, 147 insertions(+), 47 deletions(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index d5be3b3b..ff21805d 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -3,7 +3,11 @@ from __future__ import unicode_literals import base64 import datetime import hashlib +import io import json +import StringIO +import sys +import zipfile import boto.awslambda from moto.core import BaseBackend @@ -34,9 +38,13 @@ class LambdaFunction(object): self.version = '$LATEST' self.last_modified = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') if 'ZipFile' in self.code: - code = base64.b64decode(self.code['ZipFile']) - self.code_size = len(code) - self.code_sha_256 = hashlib.sha256(code).hexdigest() + to_unzip_code = base64.b64decode(self.code['ZipFile']) + zbuffer = io.BytesIO() + zbuffer.write(to_unzip_code) + zip_file = zipfile.ZipFile(zbuffer, 'r', zipfile.ZIP_DEFLATED) + self.code = zip_file.read("".join(zip_file.namelist())) + self.code_size = len(to_unzip_code) + self.code_sha_256 = hashlib.sha256(to_unzip_code).hexdigest() else: # validate s3 bucket try: @@ -93,15 +101,47 @@ class LambdaFunction(object): "Configuration": self.get_configuration(), } + def _invoke_lambda(self, code, event={}, context={}): + # TO DO: context not yet implemented + try: + codeOut = StringIO.StringIO() + codeErr = StringIO.StringIO() + mycode = "\n".join([self.code, 'print lambda_handler(%s, %s)' % (event, context)]) + #print "moto_lambda_debug: ", mycode + sys.stdout = codeOut + sys.stderr = codeErr + exec(mycode, {'event': event, 'context': context}) + exec_err = codeErr.getvalue() + exec_out = codeOut.getvalue() + result = "\n".join([exec_out, exec_err]) + except Exception as ex: + result = 'Exception %s, %s' % (ex, ex.message) + finally: + codeErr.close() + codeOut.close() + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + return result + + def is_json(self, test_str): + try: + response = json.loads(test_str) + except: + response = test_str + return response + def invoke(self, request, headers): payload = dict() # Get the invocation type: + invoke_type = request.headers.get("x-amz-invocation-type") + response = self._invoke_lambda(code=self.code, event=self.is_json(request.body)) if request.headers.get("x-amz-invocation-type") == "RequestResponse": - encoded = base64.b64encode("Some log file output...".encode('utf-8')) + encoded = base64.b64encode(response.encode('utf-8')) + payload['result'] = encoded headers["x-amz-log-result"] = encoded.decode('utf-8') - - payload["result"] = "Good" + elif request.headers.get("x-amz-invocation-type") == "Event": + payload['result'] = 'good' # nothing should be sent back possibly headers etc. return json.dumps(payload, indent=4) @@ -154,3 +194,7 @@ class LambdaBackend(BaseBackend): lambda_backends = {} for region in boto.awslambda.regions(): lambda_backends[region.name] = LambdaBackend() + +# Handle us forgotten regions, unless Lambda truly only runs out of US and EU????? +for region in ['ap-southeast-2']: + lambda_backends[region] = LambdaBackend() diff --git a/moto/awslambda/responses.py b/moto/awslambda/responses.py index 98458cc2..468a9576 100644 --- a/moto/awslambda/responses.py +++ b/moto/awslambda/responses.py @@ -43,7 +43,7 @@ class LambdaResponse(BaseResponse): if lambda_backend.has_function(function_name): fn = lambda_backend.get_function(function_name) payload = fn.invoke(request, headers) - return 200, headers, payload + return 202, headers, payload else: return 404, headers, "{}" diff --git a/tests/test_awslambda/test_lambda.py b/tests/test_awslambda/test_lambda.py index e706a013..ee17312a 100644 --- a/tests/test_awslambda/test_lambda.py +++ b/tests/test_awslambda/test_lambda.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals +import base64 import botocore.client import boto3 import hashlib @@ -8,44 +9,57 @@ import zipfile import sure # noqa from freezegun import freeze_time -from moto import mock_lambda, mock_s3 +from moto import mock_lambda, mock_s3, mock_ec2 -def get_test_zip_file(): +def _process_lamda(pfunc): zip_output = io.BytesIO() - zip_file = zipfile.ZipFile(zip_output, 'w') - zip_file.writestr('lambda_function.py', b'''\ -def handler(event, context): - return "hello world" -''') + zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED) + zip_file.writestr('lambda_function.zip', pfunc) zip_file.close() zip_output.seek(0) return zip_output.read() -@mock_lambda -def test_list_functions(): - conn = boto3.client('lambda', 'us-west-2') +def get_test_zip_file1(): + pfunc = b""" +def lambda_handler(event, context): + return (event, context) +""" + return _process_lamda(pfunc) - result = conn.list_functions() - result['Functions'].should.have.length_of(0) +def get_test_zip_file2(): + pfunc = b""" +def lambda_handler(event, context): + volume_id = event.get('volume_id') + print 'get volume details for %s' % volume_id + import boto3 + ec2 = boto3.resource('ec2', region_name='us-west-2') + vol = ec2.Volume(volume_id) + print 'Volume - %s state=%s, size=%s' % (volume_id, vol.state, vol.size) +""" + return _process_lamda(pfunc) @mock_lambda @mock_s3 +def test_list_functions(): + conn = boto3.client('lambda', 'us-west-2') + result = conn.list_functions() + result['Functions'].should.have.length_of(0) + +@mock_lambda @freeze_time('2015-01-01 00:00:00') def test_invoke_function(): conn = boto3.client('lambda', 'us-west-2') - - zip_content = get_test_zip_file() conn.create_function( FunctionName='testFunction', Runtime='python2.7', Role='test-iam-role', Handler='lambda_function.handler', Code={ - 'ZipFile': zip_content, + 'ZipFile': get_test_zip_file1(), }, Description='test lambda function', Timeout=3, @@ -53,8 +67,8 @@ def test_invoke_function(): Publish=True, ) - success_result = conn.invoke(FunctionName='testFunction', InvocationType='Event', Payload='{}') - success_result["StatusCode"].should.equal(200) + success_result = conn.invoke(FunctionName='testFunction', InvocationType='Event', Payload="Mostly Harmless") + success_result["StatusCode"].should.equal(202) conn.invoke.when.called_with( FunctionName='notAFunction', @@ -62,11 +76,42 @@ def test_invoke_function(): Payload='{}' ).should.throw(botocore.client.ClientError) - success_result = conn.invoke(FunctionName='testFunction', InvocationType='RequestResponse', Payload='{}') - success_result["StatusCode"].should.equal(200) + success_result = conn.invoke(FunctionName='testFunction', InvocationType='RequestResponse', Payload='{"msg": "So long and thanks for all the fish"}') + success_result["StatusCode"].should.equal(202) import base64 - base64.b64decode(success_result["LogResult"]).decode('utf-8').should.equal("Some log file output...") + base64.b64decode(success_result["LogResult"]).decode('utf-8').should.equal("({u'msg': u'So long and thanks for all the fish'}, {})\n\n") + +@mock_ec2 +@mock_lambda +@freeze_time('2015-01-01 00:00:00') +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.handler', + Code={ + 'ZipFile': get_test_zip_file2(), + }, + Description='test lambda function', + Timeout=3, + MemorySize=128, + Publish=True, + ) + + import json + success_result = conn.invoke(FunctionName='testFunction', InvocationType='RequestResponse', Payload=json.dumps({'volume_id': vol.id})) + success_result["StatusCode"].should.equal(202) + + import base64 + msg = 'get volume details for %s\nVolume - %s state=%s, size=%s\nNone\n\n' % (vol.id, vol.id, vol.state, vol.size) + base64.b64decode(success_result["LogResult"]).decode('utf-8').should.equal(msg) @mock_lambda @@ -101,7 +146,7 @@ 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_file() + 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') @@ -151,8 +196,7 @@ def test_create_function_from_aws_bucket(): @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_file() + zip_content = get_test_zip_file1() result = conn.create_function( FunctionName='testFunction', Runtime='python2.7', @@ -196,7 +240,7 @@ def test_get_function(): s3_conn = boto3.client('s3', 'us-west-2') s3_conn.create_bucket(Bucket='test-bucket') - zip_content = get_test_zip_file() + 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') @@ -245,14 +289,13 @@ def test_get_function(): }) - @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_file() + 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') @@ -289,7 +332,7 @@ def test_list_create_list_get_delete_list(): s3_conn = boto3.client('s3', 'us-west-2') s3_conn.create_bucket(Bucket='test-bucket') - zip_content = get_test_zip_file() + 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') diff --git a/tests/test_cloudformation/test_cloudformation_stack_integration.py b/tests/test_cloudformation/test_cloudformation_stack_integration.py index cbdb3d22..bd8b32fa 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_integration.py +++ b/tests/test_cloudformation/test_cloudformation_stack_integration.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import json +import base64 import boto import boto.cloudformation import boto.datapipeline @@ -1724,10 +1725,29 @@ def test_datapipeline(): stack_resources.should.have.length_of(1) stack_resources[0].physical_resource_id.should.equal(data_pipelines['pipelineIdList'][0]['id']) +def _process_lamda(pfunc): + import io + import zipfile + zip_output = io.BytesIO() + zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED) + zip_file.writestr('lambda_function.zip', pfunc) + zip_file.close() + zip_output.seek(0) + return zip_output.read() + + +def get_test_zip_file1(): + pfunc = b""" +def lambda_handler(event, context): + return (event, context) +""" + return _process_lamda(pfunc) + @mock_cloudformation @mock_lambda def test_lambda_function(): + # switch this to python as backend lambda only supports python execution. conn = boto3.client('lambda', 'us-east-1') template = { "AWSTemplateFormatVersion": "2010-09-09", @@ -1736,22 +1756,15 @@ def test_lambda_function(): "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": {"Fn::Join": [ - "\n", - """ - exports.handler = function(event, context) { - context.succeed(); - } - """.splitlines() - ]} + "ZipFile": base64.b64encode(get_test_zip_file1()) }, - "Handler": "index.handler", + "Handler": "lambda_function.handler", "Description": "Test function", "MemorySize": 128, "Role": "test-role", - "Runtime": "nodejs", + "Runtime": "python2.7" } - }, + } } } @@ -1765,10 +1778,10 @@ def test_lambda_function(): result = conn.list_functions() result['Functions'].should.have.length_of(1) result['Functions'][0]['Description'].should.equal('Test function') - result['Functions'][0]['Handler'].should.equal('index.handler') + result['Functions'][0]['Handler'].should.equal('lambda_function.handler') result['Functions'][0]['MemorySize'].should.equal(128) result['Functions'][0]['Role'].should.equal('test-role') - result['Functions'][0]['Runtime'].should.equal('nodejs') + result['Functions'][0]['Runtime'].should.equal('python2.7') @mock_cloudformation From 7c3005e58258a0bbc80379c46212e0cc2a5445f6 Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Fri, 7 Oct 2016 00:14:47 +1000 Subject: [PATCH 2/8] attmpt 2 to resolve StringIO not being within Python 3 anymore --- moto/awslambda/models.py | 17 +++++++++++------ tests/test_awslambda/test_lambda.py | 8 ++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index ff21805d..824bc13a 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -1,14 +1,19 @@ from __future__ import unicode_literals +import StringIO import base64 import datetime import hashlib import io import json -import StringIO import sys import zipfile +try: + from StringIO import StringIO +except: + from io import StringIO + import boto.awslambda from moto.core import BaseBackend from moto.s3.models import s3_backend @@ -104,18 +109,18 @@ class LambdaFunction(object): def _invoke_lambda(self, code, event={}, context={}): # TO DO: context not yet implemented try: - codeOut = StringIO.StringIO() - codeErr = StringIO.StringIO() - mycode = "\n".join([self.code, 'print lambda_handler(%s, %s)' % (event, context)]) + codeOut = StringIO() + codeErr = StringIO() + mycode = "\n".join([self.code, 'print lambda_handler(%s, %s)' % (event, context)]) #print "moto_lambda_debug: ", mycode sys.stdout = codeOut sys.stderr = codeErr - exec(mycode, {'event': event, 'context': context}) + exec mycode exec_err = codeErr.getvalue() exec_out = codeOut.getvalue() result = "\n".join([exec_out, exec_err]) except Exception as ex: - result = 'Exception %s, %s' % (ex, ex.message) + result = '%s\n\n\nException %s, %s' % (mycode, ex, ex.message) finally: codeErr.close() codeOut.close() diff --git a/tests/test_awslambda/test_lambda.py b/tests/test_awslambda/test_lambda.py index ee17312a..a82100bc 100644 --- a/tests/test_awslambda/test_lambda.py +++ b/tests/test_awslambda/test_lambda.py @@ -5,6 +5,7 @@ import botocore.client import boto3 import hashlib import io +import json import zipfile import sure # noqa @@ -67,7 +68,7 @@ def test_invoke_function(): Publish=True, ) - success_result = conn.invoke(FunctionName='testFunction', InvocationType='Event', Payload="Mostly Harmless") + success_result = conn.invoke(FunctionName='testFunction', InvocationType='Event', Payload='Mostly Harmless') success_result["StatusCode"].should.equal(202) conn.invoke.when.called_with( @@ -76,10 +77,9 @@ def test_invoke_function(): Payload='{}' ).should.throw(botocore.client.ClientError) - success_result = conn.invoke(FunctionName='testFunction', InvocationType='RequestResponse', Payload='{"msg": "So long and thanks for all the fish"}') + success_result = conn.invoke(FunctionName='testFunction', InvocationType='RequestResponse', + Payload=json.dumps({'msg': 'So long and thanks for all the fish'})) success_result["StatusCode"].should.equal(202) - - import base64 base64.b64decode(success_result["LogResult"]).decode('utf-8').should.equal("({u'msg': u'So long and thanks for all the fish'}, {})\n\n") @mock_ec2 From 5500cc3e6fd0f4768c51c626f125572e082cdddc Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Fri, 7 Oct 2016 00:18:39 +1000 Subject: [PATCH 3/8] attmpt 3 not liking Python 3 very much at the moment --- moto/awslambda/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 824bc13a..32718714 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -115,7 +115,7 @@ class LambdaFunction(object): #print "moto_lambda_debug: ", mycode sys.stdout = codeOut sys.stderr = codeErr - exec mycode + exec(mycode) exec_err = codeErr.getvalue() exec_out = codeOut.getvalue() result = "\n".join([exec_out, exec_err]) From 76266b616382700082f7bab09552b154f9068386 Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Fri, 7 Oct 2016 00:26:00 +1000 Subject: [PATCH 4/8] attmpt 4 thought i got rid of import StringIO - rockstar status not looking so good now --- moto/awslambda/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 32718714..0e24330c 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals -import StringIO import base64 import datetime import hashlib From de9d31bc0dc68b71404d8b9f262360f354dbb92b Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Fri, 7 Oct 2016 00:41:31 +1000 Subject: [PATCH 5/8] attmpt 5 --- moto/awslambda/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 0e24330c..684f1a24 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -107,11 +107,12 @@ class LambdaFunction(object): def _invoke_lambda(self, code, event={}, context={}): # TO DO: context not yet implemented + mycode = "\n".join([self.code, 'print lambda_handler(%s, %s)' % (event, context)]) + #print "moto_lambda_debug: ", mycode + try: codeOut = StringIO() codeErr = StringIO() - mycode = "\n".join([self.code, 'print lambda_handler(%s, %s)' % (event, context)]) - #print "moto_lambda_debug: ", mycode sys.stdout = codeOut sys.stderr = codeErr exec(mycode) From 95c90ae15f919a346ab5d8b5d60860e0c125e824 Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Fri, 7 Oct 2016 00:50:33 +1000 Subject: [PATCH 6/8] attmpt 6 is it the print statements or unicode? --- moto/awslambda/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 684f1a24..e857bd5c 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -107,8 +107,8 @@ class LambdaFunction(object): def _invoke_lambda(self, code, event={}, context={}): # TO DO: context not yet implemented - mycode = "\n".join([self.code, 'print lambda_handler(%s, %s)' % (event, context)]) - #print "moto_lambda_debug: ", mycode + mycode = "\n".join([self.code, 'print(lambda_handler(%s, %s))' % (event, context)]) + print("moto_lambda_debug: ", mycode) try: codeOut = StringIO() From dc98cf6f64b00ec53eda8a139cd58c36a85bc95e Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Mon, 10 Oct 2016 01:13:52 +1000 Subject: [PATCH 7/8] argh 2 days trying to work python3 into working python2 :( --- moto/awslambda/models.py | 51 ++++++++++------ tests/test_awslambda/test_lambda.py | 59 ++++++++++++++----- .../test_cloudformation_stack_integration.py | 4 +- 3 files changed, 78 insertions(+), 36 deletions(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index e857bd5c..563e7f43 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -42,7 +42,12 @@ class LambdaFunction(object): self.version = '$LATEST' self.last_modified = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') if 'ZipFile' in self.code: - to_unzip_code = base64.b64decode(self.code['ZipFile']) + # more hackery to handle unicode/bytes/str in python3 and python2 - argh! + try: + to_unzip_code = base64.b64decode(bytes(self.code['ZipFile'], 'utf-8')) + except Exception: + to_unzip_code = base64.b64decode(self.code['ZipFile']) + zbuffer = io.BytesIO() zbuffer.write(to_unzip_code) zip_file = zipfile.ZipFile(zbuffer, 'r', zipfile.ZIP_DEFLATED) @@ -105,10 +110,28 @@ class LambdaFunction(object): "Configuration": self.get_configuration(), } + def convert(self, s): + try: + return str(s, encoding='utf8') + except: + return s + + def is_json(self, test_str): + try: + response = json.loads(test_str) + except: + response = test_str + return response + def _invoke_lambda(self, code, event={}, context={}): # TO DO: context not yet implemented - mycode = "\n".join([self.code, 'print(lambda_handler(%s, %s))' % (event, context)]) - print("moto_lambda_debug: ", mycode) + try: + mycode = "\n".join(['import json', + self.convert(self.code), + self.convert('print(lambda_handler(%s, %s))' % (self.is_json(self.convert(event)), context))]) + print("moto_lambda_debug: ", mycode) + except Exception as ex: + print('fuck ', ex) try: codeOut = StringIO() @@ -118,35 +141,25 @@ class LambdaFunction(object): exec(mycode) exec_err = codeErr.getvalue() exec_out = codeOut.getvalue() - result = "\n".join([exec_out, exec_err]) + result = "\n".join([exec_out, self.convert(exec_err)]) except Exception as ex: - result = '%s\n\n\nException %s, %s' % (mycode, ex, ex.message) + result = '%s\n\n\nException %s' % (mycode, ex) finally: codeErr.close() codeOut.close() sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ - return result - - def is_json(self, test_str): - try: - response = json.loads(test_str) - except: - response = test_str - return response + return self.convert(result) def invoke(self, request, headers): payload = dict() # Get the invocation type: - invoke_type = request.headers.get("x-amz-invocation-type") - response = self._invoke_lambda(code=self.code, event=self.is_json(request.body)) + r = self._invoke_lambda(code=self.code, event=request.body) if request.headers.get("x-amz-invocation-type") == "RequestResponse": - encoded = base64.b64encode(response.encode('utf-8')) - payload['result'] = encoded + encoded = base64.b64encode(r.encode('utf-8')) headers["x-amz-log-result"] = encoded.decode('utf-8') - elif request.headers.get("x-amz-invocation-type") == "Event": - payload['result'] = 'good' # nothing should be sent back possibly headers etc. + payload['result'] = headers["x-amz-log-result"] return json.dumps(payload, indent=4) diff --git a/tests/test_awslambda/test_lambda.py b/tests/test_awslambda/test_lambda.py index a82100bc..6b0655d9 100644 --- a/tests/test_awslambda/test_lambda.py +++ b/tests/test_awslambda/test_lambda.py @@ -23,7 +23,7 @@ def _process_lamda(pfunc): def get_test_zip_file1(): - pfunc = b""" + pfunc = """ def lambda_handler(event, context): return (event, context) """ @@ -31,14 +31,14 @@ def lambda_handler(event, context): def get_test_zip_file2(): - pfunc = b""" + pfunc = """ def lambda_handler(event, context): volume_id = event.get('volume_id') - print 'get volume details for %s' % volume_id + print('get volume details for %s' % volume_id) import boto3 ec2 = boto3.resource('ec2', region_name='us-west-2') vol = ec2.Volume(volume_id) - print 'Volume - %s state=%s, size=%s' % (volume_id, vol.state, vol.size) + print('Volume - %s state=%s, size=%s' % (volume_id, vol.state, vol.size)) """ return _process_lamda(pfunc) @@ -52,7 +52,7 @@ def test_list_functions(): @mock_lambda @freeze_time('2015-01-01 00:00:00') -def test_invoke_function(): +def test_invoke_event_function(): conn = boto3.client('lambda', 'us-west-2') conn.create_function( FunctionName='testFunction', @@ -68,7 +68,7 @@ def test_invoke_function(): Publish=True, ) - success_result = conn.invoke(FunctionName='testFunction', InvocationType='Event', Payload='Mostly Harmless') + success_result = conn.invoke(FunctionName='testFunction', InvocationType='Event', Payload=json.dumps({'msg': 'Mostly Harmless'})) success_result["StatusCode"].should.equal(202) conn.invoke.when.called_with( @@ -77,10 +77,31 @@ def test_invoke_function(): Payload='{}' ).should.throw(botocore.client.ClientError) + +@mock_lambda +@freeze_time('2015-01-01 00:00:00') +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.handler', + Code={ + 'ZipFile': get_test_zip_file1(), + }, + Description='test lambda function', + Timeout=3, + MemorySize=128, + Publish=True, + ) + success_result = conn.invoke(FunctionName='testFunction', InvocationType='RequestResponse', Payload=json.dumps({'msg': 'So long and thanks for all the fish'})) success_result["StatusCode"].should.equal(202) - base64.b64decode(success_result["LogResult"]).decode('utf-8').should.equal("({u'msg': u'So long and thanks for all the fish'}, {})\n\n") + + #nasty hack - hope someone has better solution dealing with unicode tests working for Py2 and Py3. + base64.b64decode(success_result["LogResult"]).decode('utf-8').replace("u'", "'").should.equal("({'msg': 'So long and thanks for all the fish'}, {})\n\n") @mock_ec2 @mock_lambda @@ -111,7 +132,8 @@ def test_invoke_function_get_ec2_volume(): import base64 msg = 'get volume details for %s\nVolume - %s state=%s, size=%s\nNone\n\n' % (vol.id, vol.id, vol.state, vol.size) - base64.b64decode(success_result["LogResult"]).decode('utf-8').should.equal(msg) + # yet again hacky solution to allow code to run tests for python2 and python3 - pls someone fix :( + base64.b64decode(success_result["LogResult"]).decode('utf-8').replace("u'", "'").should.equal(msg) @mock_lambda @@ -145,8 +167,8 @@ def test_create_based_on_s3_with_missing_bucket(): 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') @@ -168,7 +190,8 @@ def test_create_function_from_aws_bucket(): "SubnetIds": ["subnet-123abc"], }, ) - result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + result['ResponseMetadata'].pop('RetryAttempts', None) # Botocore inserts retry attempts not seen in Python27 result.should.equal({ 'FunctionName': 'testFunction', 'FunctionArn': 'arn:aws:lambda:123456789012:function:testFunction', @@ -187,7 +210,6 @@ def test_create_function_from_aws_bucket(): "SubnetIds": ["subnet-123abc"], "VpcId": "vpc-123abc" }, - 'ResponseMetadata': {'HTTPStatusCode': 201}, }) @@ -210,7 +232,9 @@ def test_create_function_from_zipfile(): MemorySize=128, Publish=True, ) - result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + result['ResponseMetadata'].pop('RetryAttempts', None) # Botocore inserts retry attempts not seen in Python27 + result.should.equal({ 'FunctionName': 'testFunction', 'FunctionArn': 'arn:aws:lambda:123456789012:function:testFunction', @@ -260,7 +284,8 @@ def test_get_function(): ) result = conn.get_function(FunctionName='testFunction') - result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + result['ResponseMetadata'].pop('RetryAttempts', None) # Botocore inserts retry attempts not seen in Python27 result.should.equal({ "Code": { @@ -315,7 +340,9 @@ def test_delete_function(): ) success_result = conn.delete_function(FunctionName='testFunction') - success_result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + success_result['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + success_result['ResponseMetadata'].pop('RetryAttempts', None) # Botocore inserts retry attempts not seen in Python27 + success_result.should.equal({'ResponseMetadata': {'HTTPStatusCode': 204}}) conn.delete_function.when.called_with(FunctionName='testFunctionThatDoesntExist').should.throw(botocore.client.ClientError) @@ -380,7 +407,9 @@ def test_list_create_list_get_delete_list(): conn.list_functions()['Functions'].should.equal([expected_function_result['Configuration']]) func = conn.get_function(FunctionName='testFunction') - func['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + func['ResponseMetadata'].pop('HTTPHeaders', None) # this is hard to match against, so remove it + func['ResponseMetadata'].pop('RetryAttempts', None) # Botocore inserts retry attempts not seen in Python27 + func.should.equal(expected_function_result) conn.delete_function(FunctionName='testFunction') diff --git a/tests/test_cloudformation/test_cloudformation_stack_integration.py b/tests/test_cloudformation/test_cloudformation_stack_integration.py index bd8b32fa..d3928dc4 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_integration.py +++ b/tests/test_cloudformation/test_cloudformation_stack_integration.py @@ -1737,7 +1737,7 @@ def _process_lamda(pfunc): def get_test_zip_file1(): - pfunc = b""" + pfunc = """ def lambda_handler(event, context): return (event, context) """ @@ -1756,7 +1756,7 @@ def test_lambda_function(): "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": base64.b64encode(get_test_zip_file1()) + "ZipFile": base64.b64encode(get_test_zip_file1()).decode('utf-8') }, "Handler": "lambda_function.handler", "Description": "Test function", From c4ea3cf751e8f5899bcd4389315b8dd627b885da Mon Sep 17 00:00:00 2001 From: rocky4570fft Date: Mon, 10 Oct 2016 01:22:16 +1000 Subject: [PATCH 8/8] correct expletive and remove debug line --- moto/awslambda/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 563e7f43..260d2d33 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -129,9 +129,9 @@ class LambdaFunction(object): mycode = "\n".join(['import json', self.convert(self.code), self.convert('print(lambda_handler(%s, %s))' % (self.is_json(self.convert(event)), context))]) - print("moto_lambda_debug: ", mycode) + #print("moto_lambda_debug: ", mycode) except Exception as ex: - print('fuck ', ex) + print("Exception %s", ex) try: codeOut = StringIO()