From 0bec1b701f2a975a926fb388351861ea2a1dab25 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Tue, 21 Jan 2025 04:16:58 -0500 Subject: [PATCH 1/2] added missing initialization for dcv checker --- .../mpic_dcv_checker_lambda_function.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/aws_lambda_mpic/mpic_dcv_checker_lambda/mpic_dcv_checker_lambda_function.py b/src/aws_lambda_mpic/mpic_dcv_checker_lambda/mpic_dcv_checker_lambda_function.py index 7b9c357..fff2c3a 100644 --- a/src/aws_lambda_mpic/mpic_dcv_checker_lambda/mpic_dcv_checker_lambda_function.py +++ b/src/aws_lambda_mpic/mpic_dcv_checker_lambda/mpic_dcv_checker_lambda_function.py @@ -12,6 +12,9 @@ def __init__(self): self.perspective_code = os.environ['AWS_REGION'] self.dcv_checker = MpicDcvChecker(self.perspective_code) + async def initialize(self): + await self.dcv_checker.initialize() + def process_invocation(self, dcv_request: DcvCheckRequest): try: event_loop = asyncio.get_running_loop() @@ -39,13 +42,26 @@ def process_invocation(self, dcv_request: DcvCheckRequest): _handler = None +async def initialize_handler() -> MpicDcvCheckerLambdaHandler: + handler = MpicDcvCheckerLambdaHandler() + await handler.initialize() + return handler + + def get_handler() -> MpicDcvCheckerLambdaHandler: """ Singleton pattern to avoid recreating the handler on every Lambda invocation """ global _handler if _handler is None: - _handler = MpicDcvCheckerLambdaHandler() + try: + event_loop = asyncio.get_running_loop() + except RuntimeError: + # No running event loop, create a new one + event_loop = asyncio.new_event_loop() + asyncio.set_event_loop(event_loop) + + _handler = event_loop.run_until_complete(initialize_handler()) return _handler From 9fe11198df804d97cbbe2e5f31a5fa7601edd280 Mon Sep 17 00:00:00 2001 From: Dmitry Sharkov Date: Tue, 21 Jan 2025 04:47:34 -0500 Subject: [PATCH 2/2] added unit test to protect fix --- .../test_dcv_checker_lambda.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/unit/aws_lambda_mpic/test_dcv_checker_lambda.py b/tests/unit/aws_lambda_mpic/test_dcv_checker_lambda.py index fa8e944..d59dc70 100644 --- a/tests/unit/aws_lambda_mpic/test_dcv_checker_lambda.py +++ b/tests/unit/aws_lambda_mpic/test_dcv_checker_lambda.py @@ -1,5 +1,12 @@ +import asyncio import time +from asyncio import StreamReader +from unittest.mock import MagicMock, AsyncMock + import pytest +from aiohttp import ClientResponse +from multidict import CIMultiDictProxy, CIMultiDict +from yarl import URL import aws_lambda_mpic.mpic_dcv_checker_lambda.mpic_dcv_checker_lambda_function as mpic_dcv_checker_lambda_function from open_mpic_core.common_domain.validation_error import MpicValidationError @@ -9,6 +16,7 @@ from open_mpic_core_test.test_util.valid_check_creator import ValidCheckCreator +# noinspection PyMethodMayBeStatic class TestDcvCheckerLambda: @staticmethod @pytest.fixture(scope='class') @@ -53,6 +61,31 @@ def lambda_handler__should_return_appropriate_status_code_given_errors_in_respon result = mpic_dcv_checker_lambda_function.lambda_handler(dcv_check_request, None) assert result == mock_return_value + def lambda_handler__should_ensure_dcv_checker_is_fully_initialized_to_perform_http_based_checks(self, set_env_variables, mocker): + dcv_check_request = ValidCheckCreator.create_valid_http_check_request() + expected_challenge_value = dcv_check_request.dcv_check_parameters.validation_details.challenge_value + + # this test requires getting pretty far into the Dcv Checker execution; need to mock an aiohttp.ClientResponse + event_loop = asyncio.get_event_loop() + response = ClientResponse( + method='GET', url=URL('http://example.com'), writer=MagicMock(), continue100=None, + timer=AsyncMock(), request_info=AsyncMock(), traces=[], loop=event_loop, session=AsyncMock() + ) + response.status = 200 + response.content = StreamReader(loop=event_loop) + response.content.feed_data(bytes(expected_challenge_value.encode('utf-8'))) + response.content.feed_eof() + response._headers = CIMultiDictProxy(CIMultiDict({ + 'Content-Type': 'text/plain; charset=utf-8', 'Content-Length': str(len(expected_challenge_value)) + })) + + mocker.patch( + 'aiohttp.ClientSession.get', + side_effect=lambda *args, **kwargs: AsyncMock(__aenter__=AsyncMock(return_value=response)) + ) + result = mpic_dcv_checker_lambda_function.lambda_handler(dcv_check_request, None) + assert result['statusCode'] == 200 + @staticmethod def create_dcv_check_response(): return DcvCheckResponse(perspective_code='us-east-1', check_passed=True,