Skip to content

Commit

Permalink
Test fixups (#1163)
Browse files Browse the repository at this point in the history
expand module_utils.transformation unit tests

SUMMARY
Expands the module_utils.transformation unit tests
ensure that map_complex_type still returns transformed items if items exists that are not in the type_map.
ISSUE TYPE

Bugfix Pull Request
Feature Pull Request

COMPONENT NAME
plugins/module_utils/transformation.py
ADDITIONAL INFORMATION

Reviewed-by: Gonéri Le Bouder <goneri@lebouder.net>
(cherry picked from commit e3da3d5)
  • Loading branch information
tremble committed Oct 13, 2022
1 parent 1d8dc67 commit c7e47a7
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 25 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/1163-map_complex_type.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- module_utils.transformations - ensure that ``map_complex_type`` still returns transformed items if items exists that are not in the type_map (https://github.com/ansible-collections/amazon.aws/pull/1163).
2 changes: 1 addition & 1 deletion plugins/module_utils/transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def map_complex_type(complex_type, type_map):
complex_type[key],
type_map[key])
else:
return complex_type
new_type[key] = complex_type[key]
elif isinstance(complex_type, list):
for i in range(len(complex_type)):
new_type.append(map_complex_type(
Expand Down
26 changes: 13 additions & 13 deletions tests/unit/module_utils/cloud/test_cloud_retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class TestCloudRetry():
error_codes = [400, 500, 600]
custom_error_codes = [100, 200, 300]

class TestException(Exception):
class OurTestException(Exception):
"""
custom exception class for testing
"""
Expand Down Expand Up @@ -81,7 +81,7 @@ def test_retry_backoff(self):
def test_retry_func():
if test_retry_func.counter < 2:
test_retry_func.counter += 1
raise self.TestException(status=random.choice(TestCloudRetry.error_codes))
raise self.OurTestException(status=random.choice(TestCloudRetry.error_codes))
else:
return True

Expand All @@ -99,7 +99,7 @@ def test_retry_exponential_backoff(self):
def test_retry_func():
if test_retry_func.counter < 2:
test_retry_func.counter += 1
raise self.TestException(status=random.choice(TestCloudRetry.error_codes))
raise self.OurTestException(status=random.choice(TestCloudRetry.error_codes))
else:
return True

Expand All @@ -108,19 +108,19 @@ def test_retry_func():
assert ret is True

def test_retry_exponential_backoff_with_unexpected_exception(self):
unexpected_except = self.TestException(status=100)
unexpected_except = self.OurTestException(status=100)

@TestCloudRetry.UnitTestsRetry.exponential_backoff(retries=3, delay=1, backoff=1.1, max_delay=3,
catch_extra_error_codes=TestCloudRetry.error_codes)
def test_retry_func():
if test_retry_func.counter == 0:
test_retry_func.counter += 1
raise self.TestException(status=random.choice(TestCloudRetry.error_codes))
raise self.OurTestException(status=random.choice(TestCloudRetry.error_codes))
else:
raise unexpected_except

test_retry_func.counter = 0
with pytest.raises(self.TestException) as context:
with pytest.raises(self.OurTestException) as context:
test_retry_func()

assert context.value.status == unexpected_except.status
Expand All @@ -134,7 +134,7 @@ def test_retry_jitter_backoff(self):
def test_retry_func():
if test_retry_func.counter < 2:
test_retry_func.counter += 1
raise self.TestException(status=random.choice(TestCloudRetry.error_codes))
raise self.OurTestException(status=random.choice(TestCloudRetry.error_codes))
else:
return True

Expand All @@ -143,19 +143,19 @@ def test_retry_func():
assert ret is True

def test_retry_jittered_backoff_with_unexpected_exception(self):
unexpected_except = self.TestException(status=100)
unexpected_except = self.OurTestException(status=100)

@TestCloudRetry.UnitTestsRetry.jittered_backoff(retries=3, delay=1, max_delay=3,
catch_extra_error_codes=TestCloudRetry.error_codes)
def test_retry_func():
if test_retry_func.counter == 0:
test_retry_func.counter += 1
raise self.TestException(status=random.choice(TestCloudRetry.error_codes))
raise self.OurTestException(status=random.choice(TestCloudRetry.error_codes))
else:
raise unexpected_except

test_retry_func.counter = 0
with pytest.raises(self.TestException) as context:
with pytest.raises(self.OurTestException) as context:
test_retry_func()

assert context.value.status == unexpected_except.status
Expand All @@ -172,7 +172,7 @@ def build_response():
def test_retry_func():
if test_retry_func.counter < 2:
test_retry_func.counter += 1
raise self.TestException(build_response())
raise self.OurTestException(build_response())
else:
return True

Expand All @@ -188,13 +188,13 @@ def test_wrapped_function_called_several_times(self):
@TestCloudRetry.UnitTestsRetry.exponential_backoff(retries=2, delay=2, backoff=4, max_delay=100,
catch_extra_error_codes=TestCloudRetry.error_codes)
def _fail():
raise self.TestException(status=random.choice(TestCloudRetry.error_codes))
raise self.OurTestException(status=random.choice(TestCloudRetry.error_codes))

# run the method 3 times and assert that each it is retrying after 2secs
# the elapsed execution time should be closed to 2sec
for _i in range(3):
start = datetime.now()
with pytest.raises(self.TestException):
with pytest.raises(self.OurTestException):
_fail()
duration = (datetime.now() - start).seconds
assert duration == 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list


class AnsibleDictToBoto3FilterListTestSuite():
class TestAnsibleDictToBoto3FilterList():

# ========================================================
# ec2.ansible_dict_to_boto3_filter_list
Expand All @@ -28,7 +28,7 @@ def test_ansible_dict_with_string_to_boto3_filter_list(self):
]

converted_filters_list = ansible_dict_to_boto3_filter_list(filters)
self.assertEqual(converted_filters_list, filter_list_string)
assert converted_filters_list == filter_list_string

def test_ansible_dict_with_boolean_to_boto3_filter_list(self):
filters = {'enabled': True}
Expand All @@ -42,7 +42,7 @@ def test_ansible_dict_with_boolean_to_boto3_filter_list(self):
]

converted_filters_bool = ansible_dict_to_boto3_filter_list(filters)
self.assertEqual(converted_filters_bool, filter_list_boolean)
assert converted_filters_bool == filter_list_boolean

def test_ansible_dict_with_integer_to_boto3_filter_list(self):
filters = {'version': 1}
Expand All @@ -56,4 +56,18 @@ def test_ansible_dict_with_integer_to_boto3_filter_list(self):
]

converted_filters_int = ansible_dict_to_boto3_filter_list(filters)
self.assertEqual(converted_filters_int, filter_list_integer)
assert converted_filters_int == filter_list_integer

def test_ansible_dict_with_list_to_boto3_filter_list(self):
filters = {'version': ['1', '2', '3']}
filter_list_integer = [
{
'Name': 'version',
'Values': [
'1', '2', '3'
]
}
]

converted_filters_int = ansible_dict_to_boto3_filter_list(filters)
assert converted_filters_int == filter_list_integer
93 changes: 86 additions & 7 deletions tests/unit/module_utils/transformation/test_map_complex_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,93 @@

from ansible_collections.amazon.aws.plugins.module_utils.transformation import map_complex_type

from ansible_collections.amazon.aws.tests.unit.compat.mock import sentinel

class TestMapComplexTypeTestSuite():

def test_map_complex_type_over_dict(self):
type_map = {'minimum_healthy_percent': 'int', 'maximum_percent': 'int'}
complex_type_dict = {'minimum_healthy_percent': "75", 'maximum_percent': "150"}
complex_type_expected = {'minimum_healthy_percent': 75, 'maximum_percent': 150}
def test_map_complex_type_over_dict():
type_map = {'minimum_healthy_percent': 'int', 'maximum_percent': 'int'}
complex_type_dict = {'minimum_healthy_percent': "75", 'maximum_percent': "150"}
complex_type_expected = {'minimum_healthy_percent': 75, 'maximum_percent': 150}

complex_type_mapped = map_complex_type(complex_type_dict, type_map)
complex_type_mapped = map_complex_type(complex_type_dict, type_map)

assert complex_type_mapped == complex_type_expected
assert complex_type_mapped == complex_type_expected


def test_map_complex_type_empty():
type_map = {'minimum_healthy_percent': 'int', 'maximum_percent': 'int'}
assert map_complex_type({}, type_map) == {}
assert map_complex_type([], type_map) == []
assert map_complex_type(None, type_map) is None


def test_map_complex_type_no_type():
type_map = {'some_entry': 'int'}
complex_dict = {'another_entry': sentinel.UNSPECIFIED_MAPPING}
mapped_dict = map_complex_type(complex_dict, type_map)
assert mapped_dict == complex_dict
# we should have the original sentinel object, even if it's a new dictionary
assert mapped_dict['another_entry'] is sentinel.UNSPECIFIED_MAPPING


def test_map_complex_type_list():
type_map = {'some_entry': 'int'}
complex_dict = {'some_entry': ["1", "2", "3"]}
expected_dict = {'some_entry': [1, 2, 3]}
mapped_dict = map_complex_type(complex_dict, type_map)
assert mapped_dict == expected_dict


def test_map_complex_type_list_type():
type_map = {'some_entry': ['int']}
complex_dict = {'some_entry': ["1", "2", "3"]}
expected_dict = {'some_entry': [1, 2, 3]}
mapped_dict = map_complex_type(complex_dict, type_map)
assert mapped_dict == expected_dict

type_map = {'some_entry': ['int']}
complex_dict = {'some_entry': "1"}
expected_dict = {'some_entry': 1}
mapped_dict = map_complex_type(complex_dict, type_map)
assert mapped_dict == expected_dict


def test_map_complex_type_complex():
type_map = {
'my_integer': 'int',
'my_bool': 'bool',
'my_string': 'str',
'my_typelist_of_int': ['int'],
'my_maplist_of_int': 'int',
'my_unused': 'bool',
}
complex_dict = {
'my_integer': '-24',
'my_bool': 'true',
'my_string': 43,
'my_typelist_of_int': '5',
'my_maplist_of_int': ['-26', '47'],
'my_unconverted': sentinel.UNSPECIFIED_MAPPING,
}
expected_dict = {
'my_integer': -24,
'my_bool': True,
'my_string': '43',
'my_typelist_of_int': 5,
'my_maplist_of_int': [-26, 47],
'my_unconverted': sentinel.UNSPECIFIED_MAPPING,
}

mapped_dict = map_complex_type(complex_dict, type_map)

assert mapped_dict == expected_dict
assert mapped_dict['my_unconverted'] is sentinel.UNSPECIFIED_MAPPING
assert mapped_dict['my_bool'] is True


def test_map_complex_type_nested_list():
type_map = {'my_integer': 'int'}
complex_dict = [{'my_integer': '5'}, {'my_integer': '-24'}]
expected_dict = [{'my_integer': 5}, {'my_integer': -24}]
mapped_dict = map_complex_type(complex_dict, type_map)
assert mapped_dict == expected_dict

0 comments on commit c7e47a7

Please sign in to comment.