diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-05 16:18:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-05 16:18:41 +0000 |
commit | b643c52cf29ce5bbab738b43290af3556efa1ca9 (patch) | |
tree | 21d5c53d7a9b696627a255777cefdf6f78968824 /ansible_collections/amazon/aws/tests/unit/plugins | |
parent | Releasing progress-linux version 9.5.1+dfsg-1~progress7.99u1. (diff) | |
download | ansible-b643c52cf29ce5bbab738b43290af3556efa1ca9.tar.xz ansible-b643c52cf29ce5bbab738b43290af3556efa1ca9.zip |
Merging upstream version 10.0.0+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/amazon/aws/tests/unit/plugins')
-rw-r--r-- | ansible_collections/amazon/aws/tests/unit/plugins/modules/test_lambda_event.py | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/ansible_collections/amazon/aws/tests/unit/plugins/modules/test_lambda_event.py b/ansible_collections/amazon/aws/tests/unit/plugins/modules/test_lambda_event.py new file mode 100644 index 000000000..c292329b4 --- /dev/null +++ b/ansible_collections/amazon/aws/tests/unit/plugins/modules/test_lambda_event.py @@ -0,0 +1,544 @@ +# +# (c) 2024 Red Hat Inc. +# +# This file is part of Ansible +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from contextlib import nullcontext as does_not_raise +from copy import deepcopy +from unittest.mock import MagicMock +from unittest.mock import patch + +import pytest + +from ansible_collections.amazon.aws.plugins.modules.lambda_event import get_qualifier +from ansible_collections.amazon.aws.plugins.modules.lambda_event import lambda_event_stream +from ansible_collections.amazon.aws.plugins.modules.lambda_event import set_default_values +from ansible_collections.amazon.aws.plugins.modules.lambda_event import validate_params + +mock_get_qualifier = "ansible_collections.amazon.aws.plugins.modules.lambda_event.get_qualifier" +mock_camel_dict_to_snake_dict = "ansible_collections.amazon.aws.plugins.modules.lambda_event.camel_dict_to_snake_dict" + + +@pytest.fixture +def ansible_aws_module(): + module = MagicMock() + module.check_mode = False + module.params = { + "state": "present", + "lambda_function_arn": None, + "event_source": "sqs", + "source_params": { + "source_arn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "batch_size": 200, + "starting_position": "LATEST", + }, + "alias": None, + "version": 0, + } + module.exit_json = MagicMock() + module.exit_json.side_effect = SystemExit(1) + module.fail_json_aws = MagicMock() + module.fail_json_aws.side_effect = SystemExit(2) + module.fail_json = MagicMock() + module.fail_json.side_effect = SystemExit(2) + module.client = MagicMock() + module.client.return_value = MagicMock() + module.boolean = MagicMock() + module.boolean.side_effect = lambda x: x.lower() in ["true", "1", "t", "y", "yes"] + return module + + +@pytest.mark.parametrize( + "module_params,expected", + [ + ({"version": 1}, "1"), + ({"alias": "ansible-test"}, "ansible-test"), + ({"version": 1, "alias": "ansible-test"}, "1"), + ({}, None), + ], +) +def test_get_qualifier(ansible_aws_module, module_params, expected): + ansible_aws_module.params.update(module_params) + assert get_qualifier(ansible_aws_module) == expected + + +@pytest.mark.parametrize( + "function_name,error_msg", + [ + ( + "invalid+function+name", + "Function name invalid+function+name is invalid. Names must contain only alphanumeric characters and hyphens.", + ), + ( + "this_invalid_function_name_has_more_than_64_character_limit_this_is_not_allowed_by_the_module", + 'Function name "this_invalid_function_name_has_more_than_64_character_limit_this_is_not_allowed_by_the_module" exceeds 64 character limit', + ), + ( + "arn:aws:lambda:us-east-2:123456789012:function:ansible-test-ansible-test-ansible-test-sqs-lambda-function:" + "ansible-test-ansible-test-ansible-test-sqs-lambda-function-alias", + 'ARN "arn:aws:lambda:us-east-2:123456789012:function:ansible-test-ansible-test-ansible-test-sqs-lambda-function:' + 'ansible-test-ansible-test-ansible-test-sqs-lambda-function-alias" exceeds 140 character limit', + ), + ], +) +def test_validate_params_function_name_errors(ansible_aws_module, function_name, error_msg): + ansible_aws_module.params.update({"lambda_function_arn": function_name}) + client = MagicMock() + client.get_function = MagicMock() + client.get_function.return_value = {} + with pytest.raises(SystemExit): + validate_params(ansible_aws_module, client) + + ansible_aws_module.fail_json.assert_called_once_with(msg=error_msg) + + +@pytest.mark.parametrize( + "qualifier", + [None, "ansible-test"], +) +@patch(mock_get_qualifier) +def test_validate_params_with_function_arn(m_get_qualifier, ansible_aws_module, qualifier): + function_name = "arn:aws:lambda:us-east-2:123456789012:function:sqs_consumer" + ansible_aws_module.params.update({"lambda_function_arn": function_name}) + m_get_qualifier.return_value = qualifier + + client = MagicMock() + client.get_function = MagicMock() + client.get_function.return_value = {} + + params = deepcopy(ansible_aws_module.params) + params["lambda_function_arn"] = f"{function_name}:{qualifier}" if qualifier else function_name + + validate_params(ansible_aws_module, client) + assert params == ansible_aws_module.params + m_get_qualifier.assert_called_once() + + +@pytest.mark.parametrize( + "qualifier", + [None, "ansible-test"], +) +@patch(mock_get_qualifier) +def test_validate_params_with_function_name(m_get_qualifier, ansible_aws_module, qualifier): + function_arn = "arn:aws:lambda:us-east-2:123456789012:function:sqs_consumer" + function_name = "sqs_consumer" + ansible_aws_module.params.update({"lambda_function_arn": function_name}) + m_get_qualifier.return_value = qualifier + + client = MagicMock() + client.get_function = MagicMock() + client.get_function.return_value = { + "Configuration": {"FunctionArn": function_arn}, + } + + params = deepcopy(ansible_aws_module.params) + params["lambda_function_arn"] = function_arn + + validate_params(ansible_aws_module, client) + + assert params == ansible_aws_module.params + m_get_qualifier.assert_called_once() + api_params = {"FunctionName": function_name} + if qualifier: + api_params.update({"Qualifier": qualifier}) + client.get_function.assert_called_once_with(**api_params) + + +EventSourceMappings = [ + { + "BatchSize": 10, + "EventSourceArn": "arn:aws:sqs:us-east-2:123456789012:sqs_consumer", + "FunctionArn": "arn:aws:lambda:us-east-2:123456789012:function:sqs_consumer", + "LastModified": "2024-02-08T15:24:57.014000+01:00", + "MaximumBatchingWindowInSeconds": 0, + "State": "Enabled", + "StateTransitionReason": "USER_INITIATED", + "UUID": "3ab96d4c-b0c4-4885-87d0-f58cb9c0a4cc", + } +] + + +@pytest.mark.parametrize( + "check_mode", + [True, False], +) +@pytest.mark.parametrize( + "existing_event_source", + [True, False], +) +@patch(mock_camel_dict_to_snake_dict) +def test_lambda_event_stream_with_state_absent( + mock_camel_dict_to_snake_dict, ansible_aws_module, check_mode, existing_event_source +): + function_name = "sqs_consumer" + ansible_aws_module.params.update({"lambda_function_arn": function_name, "state": "absent"}) + ansible_aws_module.check_mode = check_mode + + client = MagicMock() + client.list_event_source_mappings = MagicMock() + + client.list_event_source_mappings.return_value = { + "EventSourceMappings": EventSourceMappings if existing_event_source else [] + } + client.delete_event_source_mapping = MagicMock() + event_source_deleted = {"msg": "event source successfully deleted."} + client.delete_event_source_mapping.return_value = event_source_deleted + mock_camel_dict_to_snake_dict.side_effect = lambda x: x + + events = [] + changed = False + result = lambda_event_stream(ansible_aws_module, client) + changed = existing_event_source + if existing_event_source: + events = EventSourceMappings + if not check_mode: + events = event_source_deleted + client.delete_event_source_mapping.assert_called_once_with(UUID=EventSourceMappings[0]["UUID"]) + else: + client.delete_event_source_mapping.assert_not_called() + assert dict(changed=changed, events=events) == result + + +def test_lambda_event_stream_create_event_missing_starting_position(ansible_aws_module): + ansible_aws_module.params = { + "state": "present", + "lambda_function_arn": "sqs_consumer", + "event_source": "stream", + "source_params": { + "source_arn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "maximum_batching_window_in_seconds": 1, + "batch_size": 200, + }, + "alias": None, + "version": 0, + } + + client = MagicMock() + client.list_event_source_mappings = MagicMock() + client.list_event_source_mappings.return_value = {"EventSourceMappings": []} + + error_message = "Source parameter 'starting_position' is required for stream event notification." + with pytest.raises(SystemExit): + lambda_event_stream(ansible_aws_module, client) + ansible_aws_module.fail_json.assert_called_once_with(msg=error_message) + + +@pytest.mark.parametrize( + "check_mode", + [True, False], +) +@pytest.mark.parametrize( + "module_params,api_params", + [ + ( + { + "state": "present", + "lambda_function_arn": "sqs_consumer", + "event_source": "stream", + "source_params": { + "source_arn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "maximum_batching_window_in_seconds": 1, + "batch_size": 250, + "starting_position": "END", + "function_response_types": ["ReportBatchItemFailures"], + }, + "alias": None, + "version": 0, + }, + { + "FunctionName": "sqs_consumer", + "EventSourceArn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "StartingPosition": "END", + "Enabled": True, + "MaximumBatchingWindowInSeconds": 1, + "BatchSize": 250, + "FunctionResponseTypes": ["ReportBatchItemFailures"], + }, + ), + ( + { + "state": "present", + "lambda_function_arn": "sqs_consumer", + "event_source": "stream", + "source_params": { + "source_arn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "maximum_batching_window_in_seconds": 1, + "batch_size": 250, + "starting_position": "END", + "function_response_types": ["ReportBatchItemFailures"], + "enabled": "no", + }, + "alias": None, + "version": 0, + }, + { + "FunctionName": "sqs_consumer", + "EventSourceArn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "StartingPosition": "END", + "Enabled": False, + "MaximumBatchingWindowInSeconds": 1, + "BatchSize": 250, + "FunctionResponseTypes": ["ReportBatchItemFailures"], + }, + ), + ( + { + "state": "present", + "lambda_function_arn": "sqs_consumer", + "event_source": "sqs", + "source_params": { + "source_arn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "maximum_batching_window_in_seconds": 1, + "batch_size": 101, + }, + "alias": None, + "version": 0, + }, + { + "FunctionName": "sqs_consumer", + "EventSourceArn": "arn:aws:sqs:us-east-2:123456789012:ansible-test-sqs", + "Enabled": True, + "MaximumBatchingWindowInSeconds": 1, + "BatchSize": 101, + }, + ), + ], +) +@patch(mock_camel_dict_to_snake_dict) +def test_lambda_event_stream_create_event( + mock_camel_dict_to_snake_dict, ansible_aws_module, check_mode, module_params, api_params +): + ansible_aws_module.params = module_params + ansible_aws_module.check_mode = check_mode + + client = MagicMock() + client.list_event_source_mappings = MagicMock() + client.list_event_source_mappings.return_value = {"EventSourceMappings": []} + + client.create_event_source_mapping = MagicMock() + event_source_created = {"msg": "event source successfully created."} + client.create_event_source_mapping.return_value = event_source_created + mock_camel_dict_to_snake_dict.side_effect = lambda x: x + + result = lambda_event_stream(ansible_aws_module, client) + + events = [] + + if not check_mode: + events = event_source_created + client.create_event_source_mapping.assert_called_once_with(**api_params) + else: + client.create_event_source_mapping.assert_not_called() + + assert dict(changed=True, events=events) == result + + +@pytest.mark.parametrize( + "check_mode", + [True, False], +) +@pytest.mark.parametrize( + "module_source_params,current_mapping,api_params", + [ + ( + {"batch_size": 100, "enabled": "false"}, + {"BatchSize": 120, "State": "Enabled"}, + {"BatchSize": 100, "Enabled": False}, + ), + ( + {"batch_size": 100, "enabled": "true"}, + {"BatchSize": 100, "State": "Enabled"}, + {}, + ), + ], +) +@patch(mock_camel_dict_to_snake_dict) +def test_lambda_event_stream_update_event( + mock_camel_dict_to_snake_dict, ansible_aws_module, check_mode, module_source_params, current_mapping, api_params +): + function_name = "ansible-test-update-event-function" + ansible_aws_module.params.update({"lambda_function_arn": function_name}) + ansible_aws_module.params["source_params"].update(module_source_params) + ansible_aws_module.check_mode = check_mode + + client = MagicMock() + client.list_event_source_mappings = MagicMock() + existing_event_source = deepcopy(EventSourceMappings) + existing_event_source[0].update(current_mapping) + client.list_event_source_mappings.return_value = {"EventSourceMappings": existing_event_source} + + client.update_event_source_mapping = MagicMock() + event_source_updated = {"msg": "event source successfully updated."} + client.update_event_source_mapping.return_value = event_source_updated + mock_camel_dict_to_snake_dict.side_effect = lambda x: x + + result = lambda_event_stream(ansible_aws_module, client) + if not api_params: + assert dict(changed=False, events=existing_event_source) == result + client.update_event_source_mapping.assert_not_called() + elif check_mode: + assert dict(changed=True, events=existing_event_source) == result + client.update_event_source_mapping.assert_not_called() + else: + api_params.update({"FunctionName": function_name, "UUID": existing_event_source[0]["UUID"]}) + assert dict(changed=True, events=event_source_updated) == result + client.update_event_source_mapping.assert_called_once_with(**api_params) + + +@pytest.mark.parametrize( + "params, expected, exception, message, source_type", + [ + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052.fifo", + "enabled": True, + "batch_size": 100, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": None, + }, + None, + pytest.raises(SystemExit), + "For FIFO queues the maximum batch_size is 10.", + "sqs", + ), + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052.fifo", + "enabled": True, + "batch_size": 10, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": 1, + }, + None, + pytest.raises(SystemExit), + "maximum_batching_window_in_seconds is not supported by Amazon SQS FIFO event sources.", + "sqs", + ), + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052.fifo", + "enabled": True, + "batch_size": 10, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": None, + }, + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052.fifo", + "enabled": True, + "batch_size": 10, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": None, + }, + does_not_raise(), + None, + "sqs", + ), + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "batch_size": 11000, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": None, + }, + None, + pytest.raises(SystemExit), + "For standard queue batch_size must be lower than 10000.", + "sqs", + ), + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "batch_size": 100, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": None, + }, + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "batch_size": 100, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": 1, + }, + does_not_raise(), + None, + "sqs", + ), + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": None, + }, + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "batch_size": 100, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": 1, + }, + does_not_raise(), + None, + "stream", + ), + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "starting_position": None, + "function_response_types": None, + }, + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "batch_size": 10, + "starting_position": None, + "function_response_types": None, + }, + does_not_raise(), + None, + "sqs", + ), + ( + { + "source_arn": "arn:aws:sqs:us-east-1:123456789012:ansible-test-28277052", + "enabled": True, + "batch_size": 10, + "starting_position": None, + "function_response_types": None, + "maximum_batching_window_in_seconds": None, + }, + None, + pytest.raises(SystemExit), + "batch_size for streams must be between 100 and 10000", + "stream", + ), + ], +) +def test__set_default_values(params, expected, exception, message, source_type): + result = None + module = MagicMock() + module.check_mode = False + module.params = { + "event_source": source_type, + "source_params": params, + } + module.fail_json = MagicMock() + module.fail_json.side_effect = SystemExit(message) + with exception as e: + result = set_default_values(module, params) + assert message is None or message in str(e) + if expected is not None: + assert result == expected |