try:
    from unittest import mock
except ImportError:
    import mock

import copy
import json
import random
import time
import unittest
from datetime import datetime

from lambdarest import create_lambda_handler


def assert_not_called(mock):
    assert mock.call_count == 0


def assert_called_once(mock):
    assert mock.call_count == 1


class TestLambdarestFunctions(unittest.TestCase):
    def setUp(self):
        self.event = {
            "resource": "/",
            "httpMethod": "POST",
            "headers": None,
            "queryStringParameters": None,
            "pathParameters": None,
            "stageVariables": None,
            "requestContext": {
                "accountId": "1234123542134",
                "resourceId": "erd49w",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": None,
                    "accountId": "23424534543",
                    "cognitoIdentityId": None,
                    "caller": "asdfasdfasfdasfdas",
                    "apiKey": "asdfasdfasdfas",
                    "sourceIp": "127.0.0.1",
                    "accessKey": "asdfasdfasdfasfd",
                    "cognitoAuthenticationType": None,
                    "cognitoAuthenticationProvider": None,
                    "userArn": "arn:aws:iam::123214323",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)",
                    "user": "asdfsadsfads",
                },
                "resourcePath": "/test",
                "httpMethod": "POST",
                "apiId": "90o718c6bk",
            },
            "body": None,
            "isBase64Encoded": False,
        }
        self.context = {"foo": "bar"}
        self.lambda_handler = create_lambda_handler()
        self.lambda_handler_application_load_balancer = create_lambda_handler(
            application_load_balancer=True
        )

    def test_post_validation_success(self):
        json_body = dict(
            items=[
                dict(
                    source="segment",
                    ingestion="segment s3 integration",
                    project_id="segment-logs/abcde",
                    data_container="gzip",
                    data_format="json",
                    data_state="raw",
                    files=[
                        dict(
                            key="segment-logz/abcde/asdf/1234.gz",
                            start="2017-01-31T22:06:46.102Z",
                            end="2017-01-31T23:06:37.831Z",
                        ),
                        dict(
                            key="segment-logz/abcde/asdfg/5678.gz",
                            start="2017-01-31T20:06:46.102Z",
                            end="2017-01-31T21:06:37.831Z",
                        ),
                    ],
                    schema='{"foo":"bar"}',
                    iam="sadfasdf",
                    start="2017-01-31T20:06:46.102Z",
                    end="2017-01-31T23:06:37.831Z",
                )
            ]
        )
        self.event["body"] = json.dumps(json_body)
        # create deep copy for testing purposes, self.event is mutable
        assert_event = copy.deepcopy(self.event)
        assert_event["context"] = self.context
        assert_event["json"] = dict(body=json_body, query={})

        post_mock = mock.Mock(return_value="foo")
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(result, {"body": "foo", "statusCode": 200, "headers": {}})
        post_mock.assert_called_with(assert_event)

    def test_schema_valid(self):
        json_body = dict(foo="hej", time="2017-01-31T21:06:37.831Z")
        post_schema = {
            "$schema": "http://json-schema.org/draft-04/schema#",
            "type": "object",
            "properties": {
                "foo": {"type": "string"},
                "time": {"type": "string", "format": "date-time"},
            },
        }

        self.event["body"] = json.dumps(json_body)
        # create deep copy for testing purposes, self.event is mutable
        assert_event = copy.deepcopy(self.event)
        assert_event["context"] = self.context
        assert_event["json"] = dict(body=json_body, query={})
        post_mock = mock.Mock(return_value="foo")
        self.lambda_handler.handle("post", schema=post_schema)(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(result, {"body": "foo", "statusCode": 200, "headers": {}})
        post_mock.assert_called_with(assert_event)

    def test_schema_invalid(self):
        json_body = dict(my_integer="this is not an integer")
        post_schema = {
            "$schema": "http://json-schema.org/draft-04/schema#",
            "type": "object",
            "properties": {
                "body": {
                    "type": "object",
                    "properties": {"my_integer": {"type": "integer"}},
                }
            },
        }

        self.event["body"] = json.dumps(json_body)
        # create deep copy for testing purposes, self.event is mutable
        assert_event = copy.deepcopy(self.event)
        assert_event["context"] = self.context
        assert_event["json"] = dict(body=json_body, query={})
        post_mock = mock.Mock(return_value="foo")
        self.lambda_handler.handle("post", schema=post_schema)(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            result, {"body": "Validation Error", "statusCode": 400, "headers": {}}
        )

    def test_schema_with_oneof_invalid(self):
        json_body = dict(typeA="foobar")
        post_schema = {
            "$schema": "http://json-schema.org/draft-04/schema#",
            "type": "object",
            "properties": {
                "body": {
                    "type": "object",
                    "oneOf": [
                        {"$ref": "#/definitions/typeA"},
                        {"$ref": "#/definitions/typeB"},
                    ],
                }
            },
            "definitions": {
                "typeA": {
                    "properties": {"propertyA": {"type": "string"}},
                    "required": ["propertyA"],
                },
                "typeB": {
                    "properties": {"propertyB": {"type": "string"}},
                    "required": ["propertyB"],
                },
            },
        }

        self.event["body"] = json.dumps(json_body)
        # create deep copy for testing purposes, self.event is mutable
        assert_event = copy.deepcopy(self.event)
        assert_event["context"] = self.context
        assert_event["json"] = dict(body=json_body, query={})
        post_mock = mock.Mock(return_value="foo")
        self.lambda_handler.handle("post", schema=post_schema)(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            result, {"body": "Validation Error", "statusCode": 400, "headers": {}}
        )

    def test_that_it_returns_bad_request_if_not_given_lambda_proxy_input(self):
        json_body = dict(my_integer="this is not an integer")

        event = json.dumps(json_body)

        post_mock = mock.Mock(return_value="foo")
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(event, self.context)
        self.assertEqual(
            result,
            {
                "body": "Bad request, maybe not using Lambda Proxy?",
                "statusCode": 500,
                "headers": {},
            },
        )

    def test_that_it_unpacks_and_validates_query_params(self):
        json_body = dict(my_integer="this is not an integer")
        queryStringParameters = dict(
            foo='"keys"', bar='{"baz":20}', baz="1,2,3", apples="1"
        )

        self.event["body"] = json.dumps(json_body)
        self.event["queryStringParameters"] = queryStringParameters

        def side_effect(event):
            return "foobar"

        post_mock = mock.MagicMock(side_effect=side_effect)

        post_schema = {
            "$schema": "http://json-schema.org/draft-04/schema#",
            "type": "object",
            "properties": {
                "query": {  # here we adress the unpacked query params
                    "type": "object",
                    "properties": {
                        "foo": {"type": "string"},
                        "bar": {
                            "type": "object",
                            "properties": {"baz": {"type": "number"}},
                        },
                        "baz": {"type": "array", "items": {"type": "number"}},
                        "apples": {"type": "number"},
                    },
                }
            },
        }
        self.lambda_handler.handle("post", schema=post_schema)(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(result, {"body": "foobar", "statusCode": 200, "headers": {}})

    def test_that_it_works_without_body_or_queryStringParameters(self):
        post_mock = mock.Mock(return_value="foo")
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(result, {"body": "foo", "headers": {}, "statusCode": 200})

    def test_that_it_works_with_empty_dict_and_status_code_as_response(self):
        post_mock = mock.Mock(return_value=({}, 200))
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(result, {"body": "{}", "headers": {}, "statusCode": 200})

    def test_that_specified_path_works(self):
        json_body = {}

        self.event["body"] = json.dumps(json_body)
        self.event["httpMethod"] = "GET"

        get_mock1 = mock.Mock(return_value="foo")
        get_mock2 = mock.Mock(return_value="bar")

        self.lambda_handler.handle("get", path="/foo/bar")(get_mock1)  # decorate mock
        self.lambda_handler.handle("get", path="/bar/foo")(get_mock2)  # decorate mock

        self.event["resource"] = "/foo/bar"
        result1 = self.lambda_handler(self.event, self.context)
        self.assertEqual(result1, {"body": "foo", "statusCode": 200, "headers": {}})

        self.event["resource"] = "/bar/foo"
        result2 = self.lambda_handler(self.event, self.context)
        self.assertEqual(result2, {"body": "bar", "statusCode": 200, "headers": {}})

    def test_that_apigw_with_basepath_works(self):
        json_body = {}

        self.event["body"] = json.dumps(json_body)
        self.event["httpMethod"] = "GET"

        get_mock1 = mock.Mock(return_value="foo")

        self.lambda_handler.handle("get", path="/foo/bar")(get_mock1)  # decorate mock

        self.event["path"] = "/v1/foo/bar"
        self.event["resource"] = "/foo/bar"
        result1 = self.lambda_handler(self.event, self.context)
        self.assertEqual(result1, {"body": "foo", "statusCode": 200, "headers": {}})

    def test_that_uppercase_works(self):
        json_body = {}

        self.event["body"] = json.dumps(json_body)
        self.event["httpMethod"] = "GET"

        def test_wordcase(request, foo):
            return foo

        self.lambda_handler.handle("get", path="/foo/bar/<string:foo>")(
            test_wordcase
        )  # decorate mock

        self.event["resource"] = "/foo/bar/foobar"
        result1 = self.lambda_handler(self.event, self.context)
        self.assertEqual(result1, {"body": "foobar", "statusCode": 200, "headers": {}})

        self.event["resource"] = "/foo/bar/FOOBAR"
        result2 = self.lambda_handler(self.event, self.context)
        self.assertEqual(result2, {"body": "FOOBAR", "statusCode": 200, "headers": {}})

    def test_that_apigw_with_proxy_param_works(self):
        json_body = {}

        self.event["body"] = json.dumps(json_body)
        self.event["httpMethod"] = "GET"

        get_mock1 = mock.Mock(return_value="foo")

        self.lambda_handler.handle("get", path="/foo/<path:path>")(
            get_mock1
        )  # decorate mock

        self.event["path"] = "/v1/foo/foobar"
        self.event["pathParameters"] = {"proxy": "foobar"}
        self.event["resource"] = "/foo/{proxy+}"
        result1 = self.lambda_handler(self.event, self.context)
        self.assertEqual(result1, {"body": "foo", "statusCode": 200, "headers": {}})

    def test_that_no_path_specified_match_all(self):
        random.seed(time.mktime(datetime.now().timetuple()))

        json_body = {}
        self.event["body"] = json.dumps(json_body)
        self.event["httpMethod"] = "PUT"

        get_mock = mock.Mock(return_value="foo")

        self.lambda_handler.handle("put", path="*")(get_mock)

        r = range(1000)
        for i in range(10):
            # test with a non-deterministic path
            self.event["resource"] = "/foo/{}/".format(random.choice(r))
            result = self.lambda_handler(self.event, self.context)
            self.assertEqual(result, {"body": "foo", "statusCode": 200, "headers": {}})

    def test_exception_in_handler_should_be_reraised(self):
        json_body = {}
        self.event["body"] = json.dumps(json_body)
        self.event["httpMethod"] = "GET"
        self.event["resource"] = "/foo/bar"

        def divide_by_zero(_):
            return 1 / 0

        self.lambda_handler = create_lambda_handler(error_handler=None)
        self.lambda_handler.handle("get", path="/foo/bar")(divide_by_zero)

        with self.assertRaises(ZeroDivisionError):
            self.lambda_handler(self.event, self.context)

    def test_that_alb_param_parm_works(self):
        json_body = {}

        self.event["body"] = json.dumps(json_body)
        self.event["httpMethod"] = "GET"
        self.event["queryStringParameters"] = {}
        self.event["headers"] = {}
        del self.event["resource"]
        del self.event["stageVariables"]

        def mock_handler(event, id):
            return "foo:" + id

        get_mock1 = mock.Mock(wraps=mock_handler)

        self.lambda_handler_application_load_balancer.handle(
            "get", path="/foo/<id>/bar"
        )(
            get_mock1
        )  # decorate mock

        self.event["path"] = "/foo/foobar/bar"
        result1 = self.lambda_handler_application_load_balancer(
            self.event, self.context
        )
        self.assertEqual(
            result1,
            {
                "body": "foo:foobar",
                "statusCode": 200,
                "headers": {},
                "statusDescription": "HTTP OK",
                "isBase64Encoded": False,
            },
        )

    def test_placeholder_filling(self):
        def my_own_get(_, object_id, foo):
            return [{"object_id": int(object_id)}, {"foo": foo}]

        self.lambda_handler.handle(
            "get", path="/object/<int:object_id>/props/<string:foo>/get"
        )(my_own_get)
        ##### TEST #####

        input_event = {
            "body": "{}",
            "httpMethod": "GET",
            "path": "/v1/object/777/props/bar/get",
            "resource": "/object/{object_id}/props/{foo}/get",
            "pathParameters": {"object_id": "777", "foo": "bar"},
        }
        result = self.lambda_handler(event=input_event)
        assert result == {
            "body": '[{"object_id": 777}, {"foo": "bar"}]',
            "statusCode": 200,
            "headers": {},
        }

    def test_incomplete_placeholder_filling(self):
        def my_own_get_1(_, object_id, foo):
            return [{"object_id": int(object_id)}, {"foo": foo}]

        self.lambda_handler.handle(
            "get", path="/incomplete_object/<int:object_id>/props/<string:foo>/get"
        )(my_own_get_1)
        ##### TEST #####

        input_event = {
            "body": "{}",
            "httpMethod": "GET",
            "path": "/v1/object/777/props/bar/get",
            "resource": "/object/{object_id}/props/{foo}/get",
            "pathParameters": {"object_id": "777"},
        }
        result = self.lambda_handler(event=input_event)

        assert result["statusCode"] == 404

    def test_that_html_is_not_surrounded_by_double_quotes(self):
        post_mock = mock.Mock(
            return_value="<html><head></head><body>Hello world!</body></html>"
        )
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            result,
            {
                "body": "<html><head></head><body>Hello world!</body></html>",
                "headers": {},
                "statusCode": 200,
            },
        )

    def test_that_standard_dict_responses_are_returned_as_is(self):
        post_mock = mock.Mock(
            return_value={"body": "something went wrong", "statusCode": 500}
        )
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            result, {"body": "something went wrong", "headers": {}, "statusCode": 500}
        )

    def test_that_standard_dict_responses_without_a_body_are_returned_as_is(self):
        post_mock = mock.Mock(
            return_value={
                "statusCode": 302,
                "headers": {"Location": "https://example.com"},
            }
        )
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            result, {"headers": {"Location": "https://example.com"}, "statusCode": 302}
        )

    def test_that_standard_dict_responses_without_a_body_are_returned_as_is_multiHeader(
        self,
    ):
        post_mock = mock.Mock(
            return_value={
                "statusCode": 302,
                "multiValueHeaders": {"Location": ["https://example.com"]},
            }
        )
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            result,
            {
                "multiValueHeaders": {"Location": ["https://example.com"]},
                "statusCode": 302,
            },
        )

    def test_that_dict_responses_that_happen_to_have_a_body_key_retain_previous_behavior(
        self,
    ):
        post_mock = mock.Mock(
            return_value={"foo": "bar", "body": "hurts", "more": "data"}
        )
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            json.loads(result["body"]), {"foo": "bar", "body": "hurts", "more": "data"}
        )
        self.assertEqual(result["headers"], {})
        self.assertEqual(result["statusCode"], 200)

    def test_that_json_encoding_body_list(self):
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle("post")(post_mock)  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(json.loads(result["body"]), [{"foo": "bar"}])
        self.assertEqual(result["headers"], {})
        self.assertEqual(result["statusCode"], 200)

    # test matrix for scopes
    #                     Scopes requested
    #                   none | single | multiple
    # Scopes provided:
    #         missing        |        |   A
    #            none    B   |        |
    #          single        |   C    |
    #        multiple    D   |        |   E
    #         invalid    F   |   G    |

    def test_scopes_A(self):
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle(
            "post", scopes=["resource.method1", "resource3.method2"]
        )(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(self.event, self.context)
        self.assertEqual(
            result, {"body": "Permission denied", "statusCode": 403, "headers": {}}
        )

    def test_scopes_B(self):
        event_with_empty_scopes = {
            "resource": "/",
            "httpMethod": "POST",
            "headers": None,
            "queryStringParameters": None,
            "pathParameters": None,
            "stageVariables": None,
            "requestContext": {
                "accountId": "1234123542134",
                "authorizer": {"scopes": "[]"},
                "resourceId": "erd49w",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": None,
                    "accountId": "23424534543",
                    "cognitoIdentityId": None,
                    "caller": "asdfasdfasfdasfdas",
                    "apiKey": "asdfasdfasdfas",
                    "sourceIp": "127.0.0.1",
                    "accessKey": "asdfasdfasdfasfd",
                    "cognitoAuthenticationType": None,
                    "cognitoAuthenticationProvider": None,
                    "userArn": "arn:aws:iam::123214323",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)",
                    "user": "asdfsadsfads",
                },
                "resourcePath": "/test",
                "httpMethod": "POST",
                "apiId": "90o718c6bk",
            },
            "body": None,
            "isBase64Encoded": False,
        }
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle(
            "post", scopes=["resource.method1", "resource3.method2"]
        )(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(event_with_empty_scopes, self.context)
        self.assertEqual(
            result, {"body": "Permission denied", "statusCode": 403, "headers": {}}
        )

    def test_scopes_C(self):
        event_with_single_scope = {
            "resource": "/",
            "httpMethod": "POST",
            "headers": None,
            "queryStringParameters": None,
            "pathParameters": None,
            "stageVariables": None,
            "requestContext": {
                "accountId": "1234123542134",
                "authorizer": {"scopes": '["resource1.method2"]'},
                "resourceId": "erd49w",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": None,
                    "accountId": "23424534543",
                    "cognitoIdentityId": None,
                    "caller": "asdfasdfasfdasfdas",
                    "apiKey": "asdfasdfasdfas",
                    "sourceIp": "127.0.0.1",
                    "accessKey": "asdfasdfasdfasfd",
                    "cognitoAuthenticationType": None,
                    "cognitoAuthenticationProvider": None,
                    "userArn": "arn:aws:iam::123214323",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)",
                    "user": "asdfsadsfads",
                },
                "resourcePath": "/test",
                "httpMethod": "POST",
                "apiId": "90o718c6bk",
            },
            "body": None,
            "isBase64Encoded": False,
        }
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle("post", scopes=["resource1.method2"])(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(event_with_single_scope, self.context)
        self.assertEqual(
            result, {"body": '[{"foo": "bar"}]', "statusCode": 200, "headers": {}}
        )

    def test_scopes_D(self):
        event_with_multiple_scopes = {
            "resource": "/",
            "httpMethod": "POST",
            "headers": None,
            "queryStringParameters": None,
            "pathParameters": None,
            "stageVariables": None,
            "requestContext": {
                "accountId": "1234123542134",
                "authorizer": {"scopes": '["resource1.method2", "resouce2.method3"]'},
                "resourceId": "erd49w",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": None,
                    "accountId": "23424534543",
                    "cognitoIdentityId": None,
                    "caller": "asdfasdfasfdasfdas",
                    "apiKey": "asdfasdfasdfas",
                    "sourceIp": "127.0.0.1",
                    "accessKey": "asdfasdfasdfasfd",
                    "cognitoAuthenticationType": None,
                    "cognitoAuthenticationProvider": None,
                    "userArn": "arn:aws:iam::123214323",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)",
                    "user": "asdfsadsfads",
                },
                "resourcePath": "/test",
                "httpMethod": "POST",
                "apiId": "90o718c6bk",
            },
            "body": None,
            "isBase64Encoded": False,
        }
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle("post", scopes=[])(post_mock)  # decorate mock
        result = self.lambda_handler(event_with_multiple_scopes, self.context)
        self.assertEqual(
            result, {"body": '[{"foo": "bar"}]', "statusCode": 200, "headers": {}}
        )

    def test_scopes_E(self):
        event_with_multiple_scopes = {
            "resource": "/",
            "httpMethod": "POST",
            "headers": None,
            "queryStringParameters": None,
            "pathParameters": None,
            "stageVariables": None,
            "requestContext": {
                "accountId": "1234123542134",
                "authorizer": {"scopes": '["resource1.method2", "resouce2.method3"]'},
                "resourceId": "erd49w",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": None,
                    "accountId": "23424534543",
                    "cognitoIdentityId": None,
                    "caller": "asdfasdfasfdasfdas",
                    "apiKey": "asdfasdfasdfas",
                    "sourceIp": "127.0.0.1",
                    "accessKey": "asdfasdfasdfasfd",
                    "cognitoAuthenticationType": None,
                    "cognitoAuthenticationProvider": None,
                    "userArn": "arn:aws:iam::123214323",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)",
                    "user": "asdfsadsfads",
                },
                "resourcePath": "/test",
                "httpMethod": "POST",
                "apiId": "90o718c6bk",
            },
            "body": None,
            "isBase64Encoded": False,
        }
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle(
            "post", scopes=["resouce2.method3", "resouce3.method1"]
        )(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(event_with_multiple_scopes, self.context)
        self.assertEqual(
            result, {"body": "Permission denied", "statusCode": 403, "headers": {}}
        )

    def test_scopes_F(self):
        event_with_invalid_scopes = {
            "resource": "/",
            "httpMethod": "POST",
            "headers": None,
            "queryStringParameters": None,
            "pathParameters": None,
            "stageVariables": None,
            "requestContext": {
                "accountId": "1234123542134",
                "authorizer": {"scopes": "{[invalid json}"},
                "resourceId": "erd49w",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": None,
                    "accountId": "23424534543",
                    "cognitoIdentityId": None,
                    "caller": "asdfasdfasfdasfdas",
                    "apiKey": "asdfasdfasdfas",
                    "sourceIp": "127.0.0.1",
                    "accessKey": "asdfasdfasdfasfd",
                    "cognitoAuthenticationType": None,
                    "cognitoAuthenticationProvider": None,
                    "userArn": "arn:aws:iam::123214323",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)",
                    "user": "asdfsadsfads",
                },
                "resourcePath": "/test",
                "httpMethod": "POST",
                "apiId": "90o718c6bk",
            },
            "body": None,
            "isBase64Encoded": False,
        }
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle("post", scopes=[])(post_mock)  # decorate mock
        result = self.lambda_handler(event_with_invalid_scopes, self.context)
        self.assertEqual(
            result, {"body": '[{"foo": "bar"}]', "statusCode": 200, "headers": {}}
        )

    def test_scopes_G(self):
        event_with_invalid_scopes = {
            "resource": "/",
            "httpMethod": "POST",
            "headers": None,
            "queryStringParameters": None,
            "pathParameters": None,
            "stageVariables": None,
            "requestContext": {
                "accountId": "1234123542134",
                "authorizer": {"scopes": "{[invalid json}"},
                "resourceId": "erd49w",
                "stage": "test-invoke-stage",
                "requestId": "test-invoke-request",
                "identity": {
                    "cognitoIdentityPoolId": None,
                    "accountId": "23424534543",
                    "cognitoIdentityId": None,
                    "caller": "asdfasdfasfdasfdas",
                    "apiKey": "asdfasdfasdfas",
                    "sourceIp": "127.0.0.1",
                    "accessKey": "asdfasdfasdfasfd",
                    "cognitoAuthenticationType": None,
                    "cognitoAuthenticationProvider": None,
                    "userArn": "arn:aws:iam::123214323",
                    "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)",
                    "user": "asdfsadsfads",
                },
                "resourcePath": "/test",
                "httpMethod": "POST",
                "apiId": "90o718c6bk",
            },
            "body": None,
            "isBase64Encoded": False,
        }
        post_mock = mock.Mock(return_value=[{"foo": "bar"}])
        self.lambda_handler.handle("post", scopes=["resource1.method2"])(
            post_mock
        )  # decorate mock
        result = self.lambda_handler(event_with_invalid_scopes, self.context)
        self.assertEqual(
            result, {"body": "Permission denied", "statusCode": 403, "headers": {}}
        )