Skip to content

Commit

Permalink
rds_instance_info/tests: add unit-tests
Browse files Browse the repository at this point in the history
Extend the unit-test coverage of the `rds_instance_info` module.

- break up `instance_info()`
- use exception to handle the API failures
  • Loading branch information
goneri committed Oct 6, 2022
1 parent 6d0d5ad commit bfa0ad1
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 12 deletions.
42 changes: 30 additions & 12 deletions plugins/modules/rds_instance_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,24 @@ def _describe_db_instances(conn, **params):
return results


def instance_info(module, conn):
instance_name = module.params.get('db_instance_identifier')
filters = module.params.get('filters')
class RdsInstanceInfoFailure(Exception):
def __init__(self, original_e, user_message):
self.original_e = original_e
self.user_message = user_message
super().__init__(self)


def get_instance_tags(conn, arn):
try:
return boto3_tag_list_to_ansible_dict(
conn.list_tags_for_resource(ResourceName=arn,
aws_retry=True)['TagList'])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
raise RdsInstanceInfoFailure(e, "Couldn't get tags for instance %s" % arn)

params = dict()

def instance_info(conn, instance_name, filters):
params = {}
if instance_name:
params['DBInstanceIdentifier'] = instance_name
if filters:
Expand All @@ -390,16 +403,15 @@ def instance_info(module, conn):
try:
results = _describe_db_instances(conn, **params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, "Couldn't get instance information")
raise RdsInstanceInfoFailure(e, "Couldn't get instance information")

for instance in results:
try:
instance['Tags'] = boto3_tag_list_to_ansible_dict(conn.list_tags_for_resource(ResourceName=instance['DBInstanceArn'],
aws_retry=True)['TagList'])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, "Couldn't get tags for instance %s" % instance['DBInstanceIdentifier'])
instance['Tags'] = get_instance_tags(conn, arn=instance['DBInstanceArn'])

return dict(changed=False, instances=[camel_dict_to_snake_dict(instance, ignore_list=['Tags']) for instance in results])
return {
"changed": False,
"instances": [camel_dict_to_snake_dict(instance, ignore_list=['Tags']) for instance in results]
}


def main():
Expand All @@ -415,7 +427,13 @@ def main():

conn = module.client('rds', retry_decorator=AWSRetry.jittered_backoff(retries=10))

module.exit_json(**instance_info(module, conn))
instance_name = module.params.get('db_instance_identifier')
filters = module.params.get('filters')

try:
module.exit_json(**instance_info(conn, instance_name, filters))
except RdsInstanceInfoFailure as e:
module.fail_json_aws(e.original_e, e.user_message)


if __name__ == '__main__':
Expand Down
121 changes: 121 additions & 0 deletions tests/unit/plugins/modules/test_rds_instance_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# (c) 2022 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 ansible_collections.amazon.aws.plugins.modules import rds_instance_info
from unittest.mock import MagicMock, Mock, patch, ANY
import ansible.module_utils.basic
import botocore.exceptions
import pytest


mod_name = "ansible_collections.amazon.aws.plugins.modules.rds_instance_info"


def a_boto_exception():
return botocore.exceptions.UnknownServiceError(
service_name="Whoops", known_service_names="Oula"
)


@patch(mod_name + "._describe_db_instances")
@patch(mod_name + ".get_instance_tags")
def test_instance_info_one_instance(m_get_instance_tags, m_describe_db_instances):
conn = MagicMock()
instance_name = "my-instance"
m_get_instance_tags.return_value = []
m_describe_db_instances.return_value = [
{
"DBInstanceIdentifier": instance_name,
"DBInstanceArn": "arn:aws:rds:us-east-2:123456789012:og:" + instance_name,
}
]
rds_instance_info.instance_info(conn, instance_name, filters={})

m_describe_db_instances.assert_called_with(conn, DBInstanceIdentifier=instance_name)
m_get_instance_tags.assert_called_with(
conn, arn="arn:aws:rds:us-east-2:123456789012:og:" + instance_name
)


@patch(mod_name + "._describe_db_instances")
@patch(mod_name + ".get_instance_tags")
def test_instance_info_all_instances(m_get_instance_tags, m_describe_db_instances):
conn = MagicMock()
m_get_instance_tags.return_value = []
m_describe_db_instances.return_value = [
{
"DBInstanceIdentifier": "first-instance",
"DBInstanceArn": "arn:aws:rds:us-east-2:123456789012:og:first-instance",
},
{
"DBInstanceIdentifier": "second-instance",
"DBInstanceArn": "arn:aws:rds:us-east-2:123456789012:og:second-instance",
},
]
rds_instance_info.instance_info(conn, instance_name=None, filters={"engine": "postgres"})

m_describe_db_instances.assert_called_with(conn, Filters=[{'Name': 'engine', 'Values': ['postgres']}])
assert m_get_instance_tags.call_count == 2
m_get_instance_tags.assert_called_with(
conn, arn="arn:aws:rds:us-east-2:123456789012:og:second-instance"
)


def test_get_instance_tags():
conn = MagicMock()
conn.list_tags_for_resource.return_value = {
"TagList": [
{"Key": "My-tag", "Value": "the-value$"},
],
"NextToken": "some-token",
}

tags = rds_instance_info.get_instance_tags(
conn, "arn:aws:rds:us-east-2:123456789012:og:second-instance"
)
conn.list_tags_for_resource.assert_called_with(
ResourceName="arn:aws:rds:us-east-2:123456789012:og:second-instance",
aws_retry=True,
)
assert tags == {"My-tag": "the-value$"}


def test_api_failure_get_tag():
conn = MagicMock()
conn.list_tags_for_resource.side_effect = a_boto_exception()

with pytest.raises(rds_instance_info.RdsInstanceInfoFailure):
rds_instance_info.get_instance_tags(conn, "arn:blabla")


def test_api_failure_describe():
conn = MagicMock()
conn.get_paginator.side_effect = a_boto_exception()

with pytest.raises(rds_instance_info.RdsInstanceInfoFailure):
rds_instance_info.instance_info(conn, None, {})


@patch(mod_name + ".AnsibleAWSModule")
def test_main_success(m_AnsibleAWSModule):
m_module = MagicMock()
m_AnsibleAWSModule.return_value = m_module

rds_instance_info.main()

m_module.client.assert_called_with("rds", retry_decorator=ANY)
m_module.exit_json.assert_called_with(changed=False, instances=[])


@patch(mod_name + "._describe_db_instances")
@patch(mod_name + ".AnsibleAWSModule")
def test_main_failure(m_AnsibleAWSModule, m_describe_db_instances):
m_module = MagicMock()
m_AnsibleAWSModule.return_value = m_module
m_describe_db_instances.side_effect = a_boto_exception()

rds_instance_info.main()

m_module.client.assert_called_with("rds", retry_decorator=ANY)
m_module.fail_json_aws.assert_called_with(ANY, "Couldn't get instance information")

0 comments on commit bfa0ad1

Please sign in to comment.