From b34386dd18071ea2403c0c77878dacc6e48b1203 Mon Sep 17 00:00:00 2001 From: Matthew Wedgwood Date: Tue, 19 Feb 2019 07:25:50 -0800 Subject: [PATCH] fix(start-api): Accept non-integer statusCode JSON values (#1013) --- samcli/local/apigw/local_apigw_service.py | 6 +++++- .../local/start_api/test_start_api.py | 8 ++++++++ tests/integration/testdata/start_api/main.py | 5 +++++ .../testdata/start_api/template.yaml | 13 +++++++++++++ .../local/apigw/test_local_apigw_service.py | 18 ++++++++++++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/samcli/local/apigw/local_apigw_service.py b/samcli/local/apigw/local_apigw_service.py index fb71e0ed6a01..e1d2a9114a55 100644 --- a/samcli/local/apigw/local_apigw_service.py +++ b/samcli/local/apigw/local_apigw_service.py @@ -211,7 +211,11 @@ def _parse_lambda_output(lambda_output, binary_types, flask_request): body = json_output.get("body") or "no data" is_base_64_encoded = json_output.get("isBase64Encoded") or False - if not isinstance(status_code, int) or status_code <= 0: + try: + status_code = int(status_code) + if status_code <= 0: + raise ValueError + except ValueError: message = "statusCode must be a positive int" LOG.error(message) raise TypeError(message) diff --git a/tests/integration/local/start_api/test_start_api.py b/tests/integration/local/start_api/test_start_api.py index c32c2429f8c5..577c6acbcb8a 100644 --- a/tests/integration/local/start_api/test_start_api.py +++ b/tests/integration/local/start_api/test_start_api.py @@ -324,6 +324,14 @@ def test_default_status_code(self): self.assertEquals(response.status_code, 200) self.assertEquals(response.json(), {'hello': 'world'}) + def test_string_status_code(self): + """ + Test that an integer-string can be returned as the status code + """ + response = requests.get(self.url + "/stringstatuscode") + + self.assertEquals(response.status_code, 200) + def test_default_body(self): """ Test that if no body is given, the response is 'no data' diff --git a/tests/integration/testdata/start_api/main.py b/tests/integration/testdata/start_api/main.py index 98e1cae3f668..9304ec849561 100644 --- a/tests/integration/testdata/start_api/main.py +++ b/tests/integration/testdata/start_api/main.py @@ -35,6 +35,11 @@ def only_set_body_handler(event, context): return {"body": json.dumps({"hello": "world"})} +def string_status_code_handler(event, context): + + return {"statusCode": "200", "body": json.dumps({"hello": "world"})} + + def sleep_10_sec_handler(event, context): # sleep thread for 10s. This is useful for testing multiple requests time.sleep(10) diff --git a/tests/integration/testdata/start_api/template.yaml b/tests/integration/testdata/start_api/template.yaml index 8ece84b2cfef..d3ec04ec57e5 100644 --- a/tests/integration/testdata/start_api/template.yaml +++ b/tests/integration/testdata/start_api/template.yaml @@ -111,6 +111,19 @@ Resources: Method: Get Path: /onlysetbody + StringStatusCodeFunction: + Type: AWS::Serverless::Function + Properties: + Handler: main.string_status_code_handler + Runtime: python3.6 + CodeUri: . + Events: + StringStatusCodePath: + Type: Api + Properties: + Method: Get + Path: /stringstatuscode + SleepFunction0: Type: AWS::Serverless::Function Properties: diff --git a/tests/unit/local/apigw/test_local_apigw_service.py b/tests/unit/local/apigw/test_local_apigw_service.py index 234554decae7..712674ff368f 100644 --- a/tests/unit/local/apigw/test_local_apigw_service.py +++ b/tests/unit/local/apigw/test_local_apigw_service.py @@ -341,6 +341,15 @@ def test_status_code_not_int(self): binary_types=[], flask_request=Mock()) + def test_status_code_int_str(self): + lambda_output = '{"statusCode": "200", "headers": {}, "body": "{\\"message\\":\\"Hello from Lambda\\"}", ' \ + '"isBase64Encoded": false}' + + (status_code, _, _) = LocalApigwService._parse_lambda_output(lambda_output, + binary_types=[], + flask_request=Mock()) + self.assertEquals(status_code, 200) + def test_status_code_negative_int(self): lambda_output = '{"statusCode": -1, "headers": {}, "body": "{\\"message\\":\\"Hello from Lambda\\"}", ' \ '"isBase64Encoded": false}' @@ -350,6 +359,15 @@ def test_status_code_negative_int(self): binary_types=[], flask_request=Mock()) + def test_status_code_negative_int_str(self): + lambda_output = '{"statusCode": "-1", "headers": {}, "body": "{\\"message\\":\\"Hello from Lambda\\"}", ' \ + '"isBase64Encoded": false}' + + with self.assertRaises(TypeError): + LocalApigwService._parse_lambda_output(lambda_output, + binary_types=[], + flask_request=Mock()) + def test_lambda_output_list_not_dict(self): lambda_output = '[]'