Repository: ansible-collections/community.aws

Issue:
rds_instance - Broken check_mode and idempotence
### Summary

When adding integration tests for adding iam_roles support for rds_instance, I noticed check_mode tests fail on idempotence checks, as well as some other checks like adding sgs on check_mode, etc.

### Issue Type

Bug Report

### Component Name

rds_instance

### Ansible Version

```console (paste below)
$ ansible --version

```


### Collection Versions

```console (paste below)
$ ansible-galaxy collection list
```


### AWS SDK versions

```console (paste below)
$ pip show boto boto3 botocore
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed

```


### OS / Environment

_No response_

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
    - name: Create DB instance with IAM roles (idempotence) - check_mode
      rds_instance:
        id: "{{ instance_id }}"
        state: present
        engine: postgres
        engine_version: "{{ postgres_db_engine_version }}"
        username: "{{ username }}"
        password: "{{ password }}"
        db_instance_class: "{{ postgres_db_instance_class }}"
        allocated_storage: "{{ allocated_storage }}"
        allow_major_version_upgrade: yes
        iam_roles:
          - role_arn: "{{ s3_integration_role_1.arn }}"
            feature_name: 's3Export'
          - role_arn: "{{ s3_integration_role_2.arn }}"
            feature_name: 'Lambda'
          - role_arn: "{{ s3_integration_role_3.arn }}"
            feature_name: 's3Import'
      register: result
      check_mode: yes

    - assert:
        that:
          - not result.changed
```


### Expected Results

expected check_mode to not modify anything and return the correct `changed`

### Actual Results

in idempotence tests, check_mode returned `changed = True`. When adding sg on check_mode, the sgs were actually added.

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/rds_instance.py`](https://github.com/['ansible-collections/amazon.aws', 'ansible-collections/community.aws', 'ansible-collections/community.vmware']/blob/main/plugins/modules/rds_instance.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @jillr @markuman @s-hertel @tremble
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@markuman @alinabuzachis I found the issue to be with the `allow_major_version_upgrade` parameter. I now see that it's never returned by `describe_db_instance`, so I guess idempotency wont hold in this case. same with the `master_user_password` it seems. 

Resolving patch:
diff --git a/plugins/modules/rds_instance.py b/plugins/modules/rds_instance.py
--- a/plugins/modules/rds_instance.py
+++ b/plugins/modules/rds_instance.py
@@ -205,6 +205,23 @@
         description:
           - Set to true to conduct the reboot through a MultiAZ failover.
         type: bool
+    iam_roles:
+        description:
+          - List of Amazon Web Services Identity and Access Management (IAM) roles to associate with DB instance.
+        type: list
+        elements: dict
+        suboptions:
+          feature_name:
+            description:
+              - The name of the feature associated with the IAM role.
+            type: str
+            required: yes
+          role_arn:
+            description:
+              - The ARN of the IAM role to associate with the DB instance.
+            type: str
+            required: yes
+        version_added: 3.3.0
     iops:
         description:
           - The Provisioned IOPS (I/O operations per second) value. Is only set when using I(storage_type) is set to io1.
@@ -316,6 +333,12 @@
             a publicly resolvable DNS name, which resolves to a public IP address. A value of false specifies an internal
             instance with a DNS name that resolves to a private IP address.
         type: bool
+    purge_iam_roles:
+        description:
+          - Set to C(True) to remove any IAM roles that aren't specified in the task and are associated with the instance.
+        type: bool
+        default: False
+        version_added: 3.3.0
     restore_time:
         description:
           - If using I(creation_source=instance) this indicates the UTC date and time to restore from the source instance.
@@ -462,7 +485,49 @@
     vpc_security_group_ids:
       - sg-0be17ba10c9286b0b
     purge_security_groups: false
-    register: result
+  register: result
+
+# Add IAM role to db instance
+- name: Create IAM policy
+  community.aws.iam_managed_policy:
+    policy_name: "my-policy"
+    policy: "{{ lookup('file','files/policy.json') }}"
+    state: present
+  register: iam_policy
+
+- name: Create IAM role
+  community.aws.iam_role:
+    assume_role_policy_document: "{{ lookup('file','files/assume_policy.json') }}"
+    name: "my-role"
+    state: present
+    managed_policy: "{{ iam_policy.policy.arn }}"
+  register: iam_role
+
+- name: Create DB instance with added IAM role
+  community.aws.rds_instance:
+    id: "my-instance-id"
+    state: present
+    engine: postgres
+    engine_version: 14.2
+    username: "{{ username }}"
+    password: "{{ password }}"
+    db_instance_class: db.m6g.large
+    allocated_storage: "{{ allocated_storage }}"
+    iam_roles:
+      - role_arn: "{{ iam_role.arn }}"
+        feature_name: 's3Export'
+
+- name: Remove IAM role from DB instance
+  community.aws.rds_instance:
+    id: "my-instance-id"
+    state: present
+    engine: postgres
+    engine_version: 14.2
+    username: "{{ username }}"
+    password: "{{ password }}"
+    db_instance_class: db.m6g.large
+    allocated_storage: "{{ allocated_storage }}"
+    purge_iam_roles: yes
 '''
 
 RETURN = r'''
@@ -780,16 +845,23 @@
 from ansible_collections.amazon.aws.plugins.module_utils.core import get_boto3_client_method_parameters
 from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
 from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
 from ansible_collections.amazon.aws.plugins.module_utils.rds import arg_spec_to_rds_params
 from ansible_collections.amazon.aws.plugins.module_utils.rds import call_method
+from ansible_collections.amazon.aws.plugins.module_utils.rds import compare_iam_roles
 from ansible_collections.amazon.aws.plugins.module_utils.rds import ensure_tags
 from ansible_collections.amazon.aws.plugins.module_utils.rds import get_final_identifier
 from ansible_collections.amazon.aws.plugins.module_utils.rds import get_rds_method_attribute
 from ansible_collections.amazon.aws.plugins.module_utils.rds import get_tags
+from ansible_collections.amazon.aws.plugins.module_utils.rds import update_iam_roles
+
 
 valid_engines = ['aurora', 'aurora-mysql', 'aurora-postgresql', 'mariadb', 'mysql', 'oracle-ee', 'oracle-ee-cdb',
                  'oracle-se2', 'oracle-se2-cdb', 'postgres', 'sqlserver-ee', 'sqlserver-se', 'sqlserver-ex', 'sqlserver-web']
 
+valid_engines_iam_roles = ['aurora-postgresql', 'oracle-ee', 'oracle-ee-cdb', 'oracle-se2', 'oracle-se2-cdb',
+                           'postgres', 'sqlserver-ee', 'sqlserver-se', 'sqlserver-ex', 'sqlserver-web']
+
 
 def get_rds_method_attribute_name(instance, state, creation_source, read_replica):
     method_name = None
@@ -945,23 +1017,21 @@ def get_current_attributes_with_inconsistent_keys(instance):
     options['DBSecurityGroups'] = [sg['DBSecurityGroupName'] for sg in instance['DBSecurityGroups'] if sg['Status'] in ['adding', 'active']]
     options['VpcSecurityGroupIds'] = [sg['VpcSecurityGroupId'] for sg in instance['VpcSecurityGroups'] if sg['Status'] in ['adding', 'active']]
     options['DBParameterGroupName'] = [parameter_group['DBParameterGroupName'] for parameter_group in instance['DBParameterGroups']]
-    options['AllowMajorVersionUpgrade'] = None
     options['EnableIAMDatabaseAuthentication'] = instance['IAMDatabaseAuthenticationEnabled']
     # PerformanceInsightsEnabled is not returned on older RDS instances it seems
     options['EnablePerformanceInsights'] = instance.get('PerformanceInsightsEnabled', False)
-    options['MasterUserPassword'] = None
     options['NewDBInstanceIdentifier'] = instance['DBInstanceIdentifier']
 
+    # Neither of these are returned via describe_db_instances, so if either is specified during a check_mode run, changed=True
+    options['AllowMajorVersionUpgrade'] = None
+    options['MasterUserPassword'] = None
+
     return options
 
 
 def get_changing_options_with_inconsistent_keys(modify_params, instance, purge_cloudwatch_logs, purge_security_groups):
     changing_params = {}
     current_options = get_current_attributes_with_inconsistent_keys(instance)
-
-    if current_options.get("MaxAllocatedStorage") is None:
-        current_options["MaxAllocatedStorage"] = None
-
     for option in current_options:
         current_option = current_options[option]
         desired_option = modify_params.pop(option, None)
@@ -982,9 +1052,14 @@ def get_changing_options_with_inconsistent_keys(modify_params, instance, purge_c
                 if desired_option in current_option:
                     continue
 
-        if current_option == desired_option:
+        # Current option and desired option are the same - continue loop
+        if option != 'ProcessorFeatures' and current_option == desired_option:
+            continue
+
+        if option == 'ProcessorFeatures' and current_option == boto3_tag_list_to_ansible_dict(desired_option, 'Name', 'Value'):
             continue
 
+        # Current option and desired option are different - add to changing_params list
         if option == 'ProcessorFeatures' and desired_option == []:
             changing_params['UseDefaultProcessorFeatures'] = True
         elif option == 'CloudwatchLogsExportConfiguration':
@@ -1074,13 +1149,48 @@ def update_instance(client, module, instance, instance_id):
 def promote_replication_instance(client, module, instance, read_replica):
     changed = False
     if read_replica is False:
-        changed = bool(instance.get('ReadReplicaSourceDBInstanceIdentifier') or instance.get('StatusInfos'))
-    if changed:
-        try:
-            call_method(client, module, method_name='promote_read_replica', parameters={'DBInstanceIdentifier': instance['DBInstanceIdentifier']})
-            changed = True
-        except is_boto3_error_message('DB Instance is not a read replica'):
-            pass
+        # 'StatusInfos' only exists when the instance is a read replica
+        # See https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/describe-db-instances.html
+        if bool(instance.get('StatusInfos')):
+            try:
+                result, changed = call_method(client, module, method_name='promote_read_replica',
+                                              parameters={'DBInstanceIdentifier': instance['DBInstanceIdentifier']})
+            except is_boto3_error_message('DB Instance is not a read replica'):
+                pass
+    return changed
+
+
+def ensure_iam_roles(client, module, instance_id):
+    '''
+    Ensure specified IAM roles are associated with DB instance
+
+        Parameters:
+            client: RDS client
+            module: AWSModule
+            instance_id: DB's instance ID
+
+        Returns:
+            changed (bool): True if changes were successfully made to DB instance's IAM roles; False if not
+    '''
+    instance = camel_dict_to_snake_dict(get_instance(client, module, instance_id), ignore_list=['Tags', 'ProcessorFeatures'])
+
+    # Ensure engine type supports associating IAM roles
+    engine = instance.get('engine')
+    if engine not in valid_engines_iam_roles:
+        module.fail_json(msg='DB engine {0} is not valid for adding IAM roles. Valid engines are {1}'.format(engine, valid_engines_iam_roles))
+
+    changed = False
+    purge_iam_roles = module.params.get('purge_iam_roles')
+    target_roles = module.params.get('iam_roles') if module.params.get('iam_roles') else []
+    existing_roles = instance.get('associated_roles', [])
+    roles_to_add, roles_to_remove = compare_iam_roles(existing_roles, target_roles, purge_iam_roles)
+    if bool(roles_to_add or roles_to_remove):
+        changed = True
+        # Don't update on check_mode
+        if module.check_mode:
+            module.exit_json(changed=changed, **instance)
+        else:
+            update_iam_roles(client, module, instance_id, roles_to_add, roles_to_remove)
     return changed
 
 
@@ -1121,6 +1231,7 @@ def main():
         creation_source=dict(choices=['snapshot', 's3', 'instance']),
         force_update_password=dict(type='bool', default=False, no_log=False),
         purge_cloudwatch_logs_exports=dict(type='bool', default=True),
+        purge_iam_roles=dict(type='bool', default=False),
         purge_tags=dict(type='bool', default=True),
         read_replica=dict(type='bool'),
         wait=dict(type='bool', default=True),
@@ -1154,6 +1265,7 @@ def main():
         engine_version=dict(),
         final_db_snapshot_identifier=dict(aliases=['final_snapshot_identifier']),
         force_failover=dict(type='bool'),
+        iam_roles=dict(type='list', elements='dict'),
         iops=dict(type='int'),
         kms_key_id=dict(),
         license_model=dict(),
@@ -1230,6 +1342,13 @@ def main():
     if module.params['preferred_maintenance_window']:
         module.params['preferred_maintenance_window'] = module.params['preferred_maintenance_window'].lower()
 
+    # Throw warning regarding case when allow_major_version_upgrade is specified in check_mode
+    # describe_rds_instance never returns this value, so on check_mode, it will always return changed=True
+    # In non-check mode runs, changed will return the correct value, so no need to warn there.
+    # see: amazon.aws.module_util.rds.handle_errors.
+    if module.params.get('allow_major_version_upgrade') and module.check_mode:
+        module.warn('allow_major_version_upgrade is not returned when describing db instances, so changed will always be `True` on check mode runs.')
+
     client = module.client('rds')
     changed = False
     state = module.params['state']
@@ -1239,17 +1358,30 @@ def main():
     method_name = get_rds_method_attribute_name(instance, state, module.params['creation_source'], module.params['read_replica'])
 
     if method_name:
+
+        # Exit on create/delete if check_mode
+        if module.check_mode and method_name in ['create_db_instance', 'delete_db_instance']:
+            module.exit_json(changed=True, **camel_dict_to_snake_dict(instance, ignore_list=['Tags', 'ProcessorFeatures']))
+
         raw_parameters = arg_spec_to_rds_params(dict((k, module.params[k]) for k in module.params if k in parameter_options))
-        parameters = get_parameters(client, module, raw_parameters, method_name)
+        parameters_to_modify = get_parameters(client, module, raw_parameters, method_name)
 
-        if parameters:
-            result, changed = call_method(client, module, method_name, parameters)
+        if parameters_to_modify:
+            # Exit on check_mode when parameters to modify
+            if module.check_mode:
+                module.exit_json(changed=True, **camel_dict_to_snake_dict(instance, ignore_list=['Tags', 'ProcessorFeatures']))
+            result, changed = call_method(client, module, method_name, parameters_to_modify)
 
         instance_id = get_final_identifier(method_name, module)
 
-        # Check tagging/promoting/rebooting/starting/stopping instance
-        if state != 'absent' and (not module.check_mode or instance):
-            changed |= update_instance(client, module, instance, instance_id)
+        if state != 'absent':
+            # Check tagging/promoting/rebooting/starting/stopping instance
+            if not module.check_mode or instance:
+                changed |= update_instance(client, module, instance, instance_id)
+
+            # Check IAM roles
+            if module.params.get('iam_roles') or module.params.get('purge_iam_roles'):
+                changed |= ensure_iam_roles(client, module, instance_id)
 
         if changed:
             instance = get_instance(client, module, instance_id)


Test patch:
diff --git a/tests/integration/targets/rds_instance/inventory b/tests/integration/targets/rds_instance/inventory
--- a/tests/integration/targets/rds_instance/inventory
+++ b/tests/integration/targets/rds_instance/inventory
@@ -15,6 +15,9 @@ tagging
 replica
 upgrade
 
+# TODO: uncomment after adding iam:CreatePolicy and iam:DeletePolicy
+# iam_roles
+
 # TODO: uncomment after adding rds_cluster module
 # aurora
 
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml b/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml
@@ -29,3 +29,7 @@ modified_processor_features:
 # For mariadb tests
 mariadb_engine_version: 10.3.31
 mariadb_engine_version_2: 10.4.21
+
+# For iam roles tests
+postgres_db_instance_class: db.m6g.large # smallest psql instance
+postgres_db_engine_version: 14.2
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/files/s3_integration_policy.json b/tests/integration/targets/rds_instance/roles/rds_instance/files/s3_integration_policy.json
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/files/s3_integration_policy.json
@@ -0,0 +1,16 @@
+{
+  "Version": "2012-10-17",
+  "Statement": [
+      {
+          "Sid": "",
+          "Effect": "Allow",
+          "Action": [
+              "s3:PutObject",
+              "s3:GetObject",
+              "s3:ListBucket",
+              "rds:*"
+          ],
+          "Resource": "*"
+      }
+  ]
+}
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/files/s3_integration_trust_policy.json b/tests/integration/targets/rds_instance/roles/rds_instance/files/s3_integration_trust_policy.json
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/files/s3_integration_trust_policy.json
@@ -0,0 +1,13 @@
+{
+    "Version": "2012-10-17",
+    "Statement": [
+        {
+            "Sid": "",
+            "Effect": "Allow",
+            "Principal": {
+                "Service": "rds.amazonaws.com"
+            },
+            "Action": "sts:AssumeRole"
+        }
+    ]
+}
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_complex.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_complex.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_complex.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_complex.yml
@@ -41,11 +41,59 @@
           - result.changed
           - "result.db_instance_identifier == '{{ instance_id }}'"
 
+    - name: Add IAM roles to mariab (should fail - iam roles not supported for mariadb)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: mariadb
+        engine_version: "{{ mariadb_engine_version }}"
+        allow_major_version_upgrade: true
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ db_instance_class }}"
+        allocated_storage: "{{ io1_allocated_storage }}"
+        storage_type: "{{ storage_type }}"
+        iops: "{{ iops }}"
+        iam_roles:
+          - role_arn: 'my_role'
+            feature_name: 'my_feature'
+      register: result
+      ignore_errors: True
+
+    - assert:
+        that:
+          - result.failed
+          - '"is not valid for adding IAM roles" in result.msg'
+
     # TODO: test modifying db_subnet_group_name, db_security_groups, db_parameter_group_name, option_group_name,
     # monitoring_role_arn, monitoring_interval, domain, domain_iam_role_name, cloudwatch_logs_export_configuration
 
     # Test multiple modifications including enabling enhanced monitoring
 
+    - name: Modify several attributes - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        allocated_storage: "{{ io1_modified_allocated_storage }}"
+        storage_type: "{{ storage_type }}"
+        db_instance_class: "{{ modified_db_instance_class }}"
+        backup_retention_period: 2
+        preferred_backup_window: "05:00-06:00"
+        preferred_maintenance_window: "{{ preferred_maintenance_window }}"
+        auto_minor_version_upgrade: false
+        monitoring_interval: "{{ monitoring_interval }}"
+        monitoring_role_arn: "{{ enhanced_monitoring_role.arn }}"
+        iops: "{{ iops }}"
+        port: 1150
+        max_allocated_storage: 150
+        apply_immediately: True
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
     - name: Modify several attributes
       rds_instance:
         id: "{{ instance_id }}"
@@ -74,6 +122,32 @@
           - '"db_instance_class" in result.pending_modified_values or result.db_instance_class == modified_db_instance_class'
           - '"monitoring_interval" in result.pending_modified_values or result.monitoring_interval == monitoring_interval'
 
+    - name: Idempotence modifying several pending attributes - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        allocated_storage: "{{ io1_modified_allocated_storage }}"
+        storage_type: "{{ storage_type }}"
+        db_instance_class: "{{ modified_db_instance_class }}"
+        backup_retention_period: 2
+        preferred_backup_window: "05:00-06:00"
+        preferred_maintenance_window: "{{ preferred_maintenance_window }}"
+        auto_minor_version_upgrade: false
+        monitoring_interval: "{{ monitoring_interval }}"
+        monitoring_role_arn: "{{ enhanced_monitoring_role.arn }}"
+        iops: "{{ iops }}"
+        port: 1150
+        max_allocated_storage: 150
+      register: result
+      retries: 30
+      delay: 10
+      until: result is not failed
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
     - name: Idempotence modifying several pending attributes
       rds_instance:
         id: "{{ instance_id }}"
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_iam_roles.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_iam_roles.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_iam_roles.yml
@@ -0,0 +1,400 @@
+---
+- block:
+    - name: Ensure the resource doesn't exist
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: absent
+        skip_final_snapshot: True
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+      ignore_errors: yes
+
+    - name: Create s3 integration policy
+      iam_managed_policy:
+        policy_name: "{{ instance_id }}-s3-policy"
+        policy: "{{ lookup('file','files/s3_integration_policy.json') }}"
+        state: present
+      register: s3_integration_policy
+
+    - name: Create an s3 integration role
+      iam_role:
+        assume_role_policy_document: "{{ lookup('file','files/s3_integration_trust_policy.json') }}"
+        name: "{{ instance_id }}-s3-role-1"
+        state: present
+        managed_policy: "{{ s3_integration_policy.policy.arn }}"
+      register: s3_integration_role_1
+
+    - name: Create an s3 integration role
+      iam_role:
+        assume_role_policy_document: "{{ lookup('file','files/s3_integration_trust_policy.json') }}"
+        name: "{{ instance_id }}-s3-role-2"
+        state: present
+        managed_policy: "{{ s3_integration_policy.policy.arn }}"
+      register: s3_integration_role_2
+
+    - name: Create an s3 integration role
+      iam_role:
+        assume_role_policy_document: "{{ lookup('file','files/s3_integration_trust_policy.json') }}"
+        name: "{{ instance_id }}-s3-role-3"
+        state: present
+        managed_policy: "{{ s3_integration_policy.policy.arn }}"
+      register: s3_integration_role_3
+
+    # ------------------------------------------------------------------------------------------
+
+    - name: Create DB instance with IAM roles - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: postgres
+        engine_version: "{{ postgres_db_engine_version }}"
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ postgres_db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        allow_major_version_upgrade: yes
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+          - role_arn: "{{ s3_integration_role_3.arn }}"
+            feature_name: 's3Import'
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
+    - name: Create DB instance with IAM roles
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: postgres
+        engine_version: "{{ postgres_db_engine_version }}"
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ postgres_db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        allow_major_version_upgrade: yes
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+          - role_arn: "{{ s3_integration_role_3.arn }}"
+            feature_name: 's3Import'
+      register: result
+
+    - assert:
+        that:
+          - result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 3
+          - "{{ 's3Export' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 'Lambda' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 's3Import' in result.associated_roles | map(attribute='feature_name') }}"
+
+    - name: Create DB instance with IAM roles (idempotence) - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: postgres
+        engine_version: "{{ postgres_db_engine_version }}"
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ postgres_db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+          - role_arn: "{{ s3_integration_role_3.arn }}"
+            feature_name: 's3Import'
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Create DB instance with IAM roles (idempotence)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: postgres
+        engine_version: "{{ postgres_db_engine_version }}"
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ postgres_db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+          - role_arn: "{{ s3_integration_role_3.arn }}"
+            feature_name: 's3Import'
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 3
+          - "{{ 's3Export' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 'Lambda' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 's3Import' in result.associated_roles | map(attribute='feature_name') }}"
+
+    - name: Create DB instance with IAM roles (idempotence) - purge roles
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: postgres
+        engine_version: "{{ postgres_db_engine_version }}"
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ postgres_db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+          - role_arn: "{{ s3_integration_role_3.arn }}"
+            feature_name: 's3Import'
+        purge_iam_roles: yes
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 3
+          - "{{ 's3Export' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 'Lambda' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 's3Import' in result.associated_roles | map(attribute='feature_name') }}"
+
+    # ------------------------------------------------------------------------------------------
+
+    - name: Remove s3Import IAM role from db instance - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+        purge_iam_roles: yes
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
+    - name: Remove s3Import IAM role from db instance
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+        purge_iam_roles: yes
+      register: result
+
+    - assert:
+        that:
+          - result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 2
+          - "{{ 's3Export' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 'Lambda' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 's3Import' not in result.associated_roles | map(attribute='feature_name') }}"
+
+    - name: Remove s3Import IAM role from db instance (idempotence) - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+        purge_iam_roles: yes
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Remove s3Import IAM role from db instance (idempotence)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+          - role_arn: "{{ s3_integration_role_2.arn }}"
+            feature_name: 'Lambda'
+        purge_iam_roles: yes
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 2
+          - "{{ 's3Export' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 'Lambda' in result.associated_roles | map(attribute='feature_name') }}"
+          - "{{ 's3Import' not in result.associated_roles | map(attribute='feature_name') }}"
+
+    # ------------------------------------------------------------------------------------------
+
+    - name: Remove IAM roles from db instance - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        purge_iam_roles: yes
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
+    - name: Remove IAM roles from db instance
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        purge_iam_roles: yes
+      register: result
+
+    - assert:
+        that:
+          - result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 0
+
+    - name: Remove IAM roles from db instance (idempotence) - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        purge_iam_roles: yes
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Remove IAM roles from db instance (idempotence)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        purge_iam_roles: yes
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 0
+
+    # ------------------------------------------------------------------------------------------
+
+    - name: Add IAM role to existing db instance - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
+    - name: Add IAM role to existing db instance
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+      register: result
+
+    - assert:
+        that:
+          - result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 1
+          - "{{ 's3Export' in result.associated_roles | map(attribute='feature_name') }}"
+
+    - name: Add IAM role to existing db instance (idempotence) - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Add IAM role to existing db instance (idempotence)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+
+        iam_roles:
+          - role_arn: "{{ s3_integration_role_1.arn }}"
+            feature_name: 's3Export'
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - result.associated_roles | length == 1
+          - "{{ 's3Export' in result.associated_roles | map(attribute='feature_name') }}"
+
+  always:
+      - name: Delete IAM policy
+        iam_managed_policy:
+          policy_name: "{{ instance_id }}-s3-policy"
+          state: absent
+        ignore_errors: yes
+
+      - name: Delete IAM roles
+        iam_role:
+          name: "{{ item.role_name }}"
+          assume_role_policy_document: "{{ lookup('file','files/s3_integration_trust_policy.json') }}"
+          state: absent
+        ignore_errors: yes
+        with_items:
+          - "{{ s3_integration_role_1 }}"
+          - "{{ s3_integration_role_2 }}"
+          - "{{ s3_integration_role_3 }}"
+
+      - name: Delete the instance
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: absent
+          skip_final_snapshot: True
+          wait: false
+        ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify.yml
@@ -39,6 +39,20 @@
           - result.changed
           - "result.db_instance_identifier == '{{ instance_id }}'"
 
+    - name: Modify the instance name without immediate application - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        new_id: "{{ modified_instance_id }}"
+        password: "{{ password }}"
+        apply_immediately: False
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
     - name: Modify the instance name without immediate application
       rds_instance:
         id: "{{ instance_id }}"
@@ -53,6 +67,19 @@
           - result.changed
           - 'result.db_instance_identifier == "{{ instance_id }}"'
 
+    - name: Immediately apply the pending update - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        new_id: "{{ modified_instance_id }}"
+        apply_immediately: True
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
     - name: Immediately apply the pending update
       rds_instance:
         id: "{{ instance_id }}"
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor.yml
@@ -30,7 +30,7 @@
           that:
             - result.changed
 
-      - name: Check mode - modify the processor features
+      - name: Modify the processor features - check_mode
         rds_instance:
           id: "{{ instance_id }}"
           state: present
@@ -69,6 +69,45 @@
             - 'result.pending_modified_values.processor_features.coreCount == "{{ modified_processor_features.coreCount }}"'
             - 'result.pending_modified_values.processor_features.threadsPerCore == "{{ modified_processor_features.threadsPerCore }}"'
 
+      - name: Modify the processor features (idempotence) - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          engine: oracle-ee
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ oracle_ee_db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          storage_encrypted: True
+          processor_features: "{{ modified_processor_features }}"
+          apply_immediately: true
+        register: result
+        check_mode: True
+
+      - assert:
+          that:
+            - not result.changed
+
+      - name: Modify the processor features (idempotence)
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          engine: oracle-ee
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ oracle_ee_db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          storage_encrypted: True
+          processor_features: "{{ modified_processor_features }}"
+          apply_immediately: true
+        register: result
+
+      - assert:
+          that:
+            - not result.changed
+            - 'result.pending_modified_values.processor_features.coreCount == "{{ modified_processor_features.coreCount }}"'
+            - 'result.pending_modified_values.processor_features.threadsPerCore == "{{ modified_processor_features.threadsPerCore }}"'
+
     always:
 
       - name: Delete the DB instance
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_replica.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_replica.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_replica.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_replica.yml
@@ -40,6 +40,31 @@
             - source_db.changed
             - "source_db.db_instance_identifier == '{{ instance_id }}'"
 
+    # ------------------------------------------------------------------------------------------
+
+      - name: Create a read replica in a different region - check_mode
+        rds_instance:
+          id: "{{ instance_id }}-replica"
+          state: present
+          source_db_instance_identifier: "{{ instance_id }}"
+          engine: mysql
+          username: "{{ username }}"
+          password: "{{ password }}"
+          read_replica: True
+          db_instance_class: "{{ db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          region: "{{ region_dest }}"
+          tags:
+            Name: "{{ instance_id }}"
+            Created_by: Ansible rds_instance tests
+          wait: yes
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - result.changed
+
       - name: Create a read replica in a different region
         rds_instance:
           id: "{{ instance_id }}-replica"
@@ -66,6 +91,27 @@
             - "result.tags.Name == '{{ instance_id }}'"
             - "result.tags.Created_by == 'Ansible rds_instance tests'"
 
+      - name: Test idempotence with a read replica - check_mode
+        rds_instance:
+          id: "{{ instance_id }}-replica"
+          state: present
+          source_db_instance_identifier: "{{ instance_id }}"
+          engine: mysql
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          region: "{{ region_dest }}"
+          tags:
+            Name: "{{ instance_id }}"
+            Created_by: Ansible rds_instance tests
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - not result.changed
+
       - name: Test idempotence with a read replica
         rds_instance:
           id: "{{ instance_id }}-replica"
@@ -82,10 +128,9 @@
             Created_by: Ansible rds_instance tests
         register: result
 
-      ## XXX Bug
-      # - assert:
-      #     that:
-      #       - not result.changed
+      - assert:
+          that:
+            - not result.changed
 
       - name: Test idempotence with read_replica=True
         rds_instance:
@@ -104,6 +149,25 @@
             Created_by: Ansible rds_instance tests
         register: result
 
+      - assert:
+          that:
+            - not result.changed
+
+    # ------------------------------------------------------------------------------------------
+
+      - name: Promote the read replica - check_mode
+        rds_instance:
+          id: "{{ instance_id }}-replica"
+          state: present
+          read_replica: False
+          region: "{{ region_dest }}"
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - result.changed
+
       - name: Promote the read replica
         rds_instance:
           id: "{{ instance_id }}-replica"
@@ -116,6 +180,19 @@
           that:
             - result.changed
 
+      - name: Test idempotence - check_mode
+        rds_instance:
+          id: "{{ instance_id }}-replica"
+          state: present
+          read_replica: False
+          region: "{{ region_dest }}"
+        register: result
+        check_mode: yes
+
+      - assert:
+         that:
+           - not result.changed
+
       - name: Test idempotence
         rds_instance:
           id: "{{ instance_id }}-replica"
@@ -124,10 +201,9 @@
           region: "{{ region_dest }}"
         register: result
 
-      ## XXX Bug
-      #- assert:
-      #    that:
-      #      - not result.changed
+      - assert:
+         that:
+           - not result.changed
 
     always:
 
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore.yml
@@ -31,6 +31,25 @@
             - source_db.changed
             - "source_db.db_instance_identifier == '{{ instance_id }}-s'"
 
+      - name: Create a point in time DB instance - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          source_db_instance_identifier: "{{ instance_id }}-s"
+          creation_source: instance
+          engine: mysql
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          use_latest_restorable_time: True
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            result.changed
+
       - name: Create a point in time DB instance
         rds_instance:
           id: "{{ instance_id }}"
@@ -45,7 +64,30 @@
           use_latest_restorable_time: True
         register: result
 
-      - name: Test idempotence with a point in time replica
+      - assert:
+          that:
+            result.changed
+
+      - name: Create a point in time DB instance (idempotence) - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          source_db_instance_identifier: "{{ instance_id }}-s"
+          creation_source: instance
+          engine: mysql
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          restore_time: "{{ result.latest_restorable_time }}"
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - not result.changed
+
+      - name: Create a point in time DB instance (idempotence)
         rds_instance:
           id: "{{ instance_id }}"
           state: present
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_sgroups.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_sgroups.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_sgroups.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_sgroups.yml
@@ -40,8 +40,6 @@
           - "{{ resource_prefix }}-sg-2"
           - "{{ resource_prefix }}-sg-3"
 
-      - debug: var=sgs_result
-
       - name: Ensure the resource doesn't exist
         rds_instance:
           id: "{{ instance_id }}"
@@ -54,6 +52,27 @@
             - not result.changed
         ignore_errors: yes
 
+    # ------------------------------------------------------------------------------------------
+
+      - name: Create a DB instance in the VPC with two security groups - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          engine: mariadb
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          vpc_security_group_ids:
+            - "{{ sgs_result.results.0.group_id }}"
+            - "{{ sgs_result.results.1.group_id }}"
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - result.changed
+
       - name: Create a DB instance in the VPC with two security groups
         rds_instance:
           id: "{{ instance_id }}"
@@ -74,7 +93,48 @@
             - "result.db_instance_identifier == '{{ instance_id }}'"
             - "result.vpc_security_groups | selectattr('status', 'in', ['active', 'adding']) | list | length == 2"
 
-      - name: Add a new security group without purge (check_mode)
+      - name: Create a DB instance in the VPC with two security groups (idempotence) - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          engine: mariadb
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          vpc_security_group_ids:
+            - "{{ sgs_result.results.0.group_id }}"
+            - "{{ sgs_result.results.1.group_id }}"
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - not result.changed
+
+      - name: Create a DB instance in the VPC with two security groups (idempotence)
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          engine: mariadb
+          username: "{{ username }}"
+          password: "{{ password }}"
+          db_instance_class: "{{ db_instance_class }}"
+          allocated_storage: "{{ allocated_storage }}"
+          vpc_security_group_ids:
+            - "{{ sgs_result.results.0.group_id }}"
+            - "{{ sgs_result.results.1.group_id }}"
+        register: result
+
+      - assert:
+          that:
+            - not result.changed
+            - "result.db_instance_identifier == '{{ instance_id }}'"
+            - "result.vpc_security_groups | selectattr('status', 'in', ['active', 'adding']) | list | length == 2"
+
+    # ------------------------------------------------------------------------------------------
+
+      - name: Add a new security group without purge - check_mode
         rds_instance:
           id: "{{ instance_id }}"
           state: present
@@ -106,7 +166,23 @@
             - "result.db_instance_identifier == '{{ instance_id }}'"
             - "result.vpc_security_groups | selectattr('status', 'in', ['active', 'adding']) | list | length == 3"
 
-      - name: Add a new security group without purge (test idempotence)
+      - name: Add a new security group without purge (idempotence) - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          vpc_security_group_ids:
+            - "{{ sgs_result.results.2.group_id }}"
+          apply_immediately: true
+          purge_security_groups: false
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - not result.changed
+            - "result.db_instance_identifier == '{{ instance_id }}'"
+
+      - name: Add a new security group without purge (idempotence)
         rds_instance:
           id: "{{ instance_id }}"
           state: present
@@ -120,6 +196,23 @@
           that:
             - not result.changed
             - "result.db_instance_identifier == '{{ instance_id }}'"
+            - "result.vpc_security_groups | selectattr('status', 'in', ['active', 'adding']) | list | length == 3"
+
+    # ------------------------------------------------------------------------------------------
+
+      - name: Add a security group with purge - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          vpc_security_group_ids:
+            - "{{ sgs_result.results.2.group_id }}"
+          apply_immediately: true
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - result.changed
 
       - name: Add a security group with purge
         rds_instance:
@@ -137,6 +230,35 @@
             - "result.vpc_security_groups | selectattr('status', 'in', ['active', 'adding']) | list | length == 1"
             - "result.vpc_security_groups | selectattr('status', 'equalto', 'removing') | list | length == 2"
 
+      - name: Add a security group with purge (idempotence) - check_mode
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          vpc_security_group_ids:
+            - "{{ sgs_result.results.2.group_id }}"
+          apply_immediately: true
+        register: result
+        check_mode: yes
+
+      - assert:
+          that:
+            - not result.changed
+
+      - name: Add a security group with purge (idempotence)
+        rds_instance:
+          id: "{{ instance_id }}"
+          state: present
+          vpc_security_group_ids:
+            - "{{ sgs_result.results.2.group_id }}"
+          apply_immediately: true
+        register: result
+
+      - assert:
+          that:
+            - not result.changed
+            - "result.db_instance_identifier == '{{ instance_id }}'"
+            - "result.vpc_security_groups | selectattr('status', 'in', ['active', 'adding']) | list | length == 1"
+
     always:
 
       - name: Ensure the resource doesn't exist
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml
@@ -12,6 +12,28 @@
           - not result.changed
       ignore_errors: yes
 
+
+    # ------------------------------------------------------------------------------------------
+
+    - name: Create a mariadb instance - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: mariadb
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        tags:
+          Name: "{{ instance_id }}"
+          Created_by: Ansible rds_instance tests
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
     - name: Create a mariadb instance
       rds_instance:
         id: "{{ instance_id }}"
@@ -34,8 +56,51 @@
           - "result.tags.Name == '{{ instance_id }}'"
           - "result.tags.Created_by == 'Ansible rds_instance tests'"
 
+    - name: Create a mariadb instance (idempotence) - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: mariadb
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        tags:
+          Name: "{{ instance_id }}"
+          Created_by: Ansible rds_instance tests
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Create a mariadb instance (idempotence)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: mariadb
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        tags:
+          Name: "{{ instance_id }}"
+          Created_by: Ansible rds_instance tests
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+          - "result.db_instance_identifier == '{{ instance_id }}'"
+          - "result.tags | length == 2"
+          - "result.tags.Name == '{{ instance_id }}'"
+          - "result.tags.Created_by == 'Ansible rds_instance tests'"
+
+    # ------------------------------------------------------------------------------------------
     # Test stopping / rebooting instances
-    - name: Check mode - reboot a stopped instance
+
+    - name: Reboot a stopped instance - check_mode
       rds_instance:
         id: "{{ instance_id }}"
         state: rebooted
@@ -56,7 +121,9 @@
         that:
           - result.changed
 
-    - name: Check Mode - stop the instance
+    # ------------------------------------------------------------------------------------------
+
+    - name: Stop the instance - check_mode
       rds_instance:
         id: "{{ instance_id }}"
         state: stopped
@@ -77,7 +144,7 @@
         that:
           - result.changed
 
-    - name: Check Mode - idempotence
+    - name: Stop the instance (idempotence) - check_mode
       rds_instance:
         id: "{{ instance_id }}"
         state: stopped
@@ -88,7 +155,7 @@
         that:
           - not result.changed
 
-    - name: Idempotence
+    - name: Stop the instance (idempotence)
       rds_instance:
         id: "{{ instance_id }}"
         state: stopped
@@ -98,7 +165,9 @@
         that:
           - not result.changed
 
-    - name: Check Mode - start the instance
+    # ------------------------------------------------------------------------------------------
+
+    - name: Start the instance - check_mode
       rds_instance:
         id: "{{ instance_id }}"
         state: started
@@ -119,6 +188,93 @@
         that:
           - result.changed
 
+    - name: Start the instance (idempotence) - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: started
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Start the instance (idempotence)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: started
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+
+    # ------------------------------------------------------------------------------------------
+
+    - name: Ensure instance exists prior to deleting
+      rds_instance_info:
+          db_instance_identifier: '{{ instance_id }}'
+      register: db_info
+
+    - assert:
+        that:
+          - db_info.instances | length == 1
+
+    - name: Delete the instance - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: absent
+        skip_final_snapshot: True
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
+    - name: Delete the instance
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: absent
+        skip_final_snapshot: True
+      register: result
+
+    - assert:
+        that:
+          - result.changed
+
+    - name: Ensure instance was deleted
+      rds_instance_info:
+          db_instance_identifier: '{{ instance_id }}'
+      register: db_info
+
+    - assert:
+        that:
+          - db_info.instances | length == 0
+
+    - name: Delete the instance (idempotence) - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: absent
+        skip_final_snapshot: True
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Delete the instance (idempotence)
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: absent
+        skip_final_snapshot: True
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+
   always:
     - name: Remove DB instance
       rds_instance:
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tagging.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tagging.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tagging.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tagging.yml
@@ -56,6 +56,22 @@
           - result.kms_key_id
           - result.storage_encrypted == true
 
+    - name: Test impotency omitting tags - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: mariadb
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
     - name: Test impotency omitting tags
       rds_instance:
         id: "{{ instance_id }}"
@@ -103,6 +119,21 @@
           - not result.changed
           - "result.tags | length == 2"
 
+    - name: Add a tag and remove a tag - check_mode
+      rds_instance:
+        db_instance_identifier: "{{ instance_id }}"
+        state: present
+        tags:
+          Name: "{{ instance_id }}-new"
+          Created_by: Ansible rds_instance tests
+        purge_tags: True
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
     - name: Add a tag and remove a tag
       rds_instance:
         db_instance_identifier: "{{ instance_id }}"
@@ -119,6 +150,37 @@
           - "result.tags | length == 2"
           - "result.tags.Name == '{{ instance_id }}-new'"
 
+    - name: Add a tag and remove a tag (idempotence) - check_mode
+      rds_instance:
+        db_instance_identifier: "{{ instance_id }}"
+        state: present
+        tags:
+          Name: "{{ instance_id }}-new"
+          Created_by: Ansible rds_instance tests
+        purge_tags: True
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - not result.changed
+
+    - name: Add a tag and remove a tag (idempotence)
+      rds_instance:
+        db_instance_identifier: "{{ instance_id }}"
+        state: present
+        tags:
+          Name: "{{ instance_id }}-new"
+          Created_by: Ansible rds_instance tests
+        purge_tags: True
+      register: result
+
+    - assert:
+        that:
+          - not result.changed
+          - "result.tags | length == 2"
+          - "result.tags.Name == '{{ instance_id }}-new'"
+
     # Test final snapshot on deletion
     - name: Delete the DB instance
       rds_instance:
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_upgrade.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_upgrade.yml
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_upgrade.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_upgrade.yml
@@ -32,7 +32,26 @@
 
     # Test upgrade of DB instance
 
-    - name: Uprade a mariadb instance
+    - name: Upgrade a mariadb instance - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: mariadb
+        engine_version: "{{ mariadb_engine_version_2 }}"
+        allow_major_version_upgrade: true
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+        apply_immediately: True
+      register: result
+      check_mode: yes
+
+    - assert:
+        that:
+          - result.changed
+
+    - name: Upgrade a mariadb instance
       rds_instance:
         id: "{{ instance_id }}"
         state: present
@@ -51,7 +70,30 @@
           - result.changed
           - '"engine_version" in result.pending_modified_values or result.engine_version == mariadb_engine_version_2'
 
-    - name: Idempotence uprading a mariadb instance
+    - name: Idempotence upgrading a mariadb instance - check_mode
+      rds_instance:
+        id: "{{ instance_id }}"
+        state: present
+        engine: mariadb
+        engine_version: "{{ mariadb_engine_version_2 }}"
+        allow_major_version_upgrade: true
+        username: "{{ username }}"
+        password: "{{ password }}"
+        db_instance_class: "{{ db_instance_class }}"
+        allocated_storage: "{{ allocated_storage }}"
+      register: result
+      retries: 30
+      delay: 10
+      until: result is not failed
+      check_mode: yes
+
+    ### Specifying allow_major_version_upgrade with check_mode will always result in changed=True
+    ### since it's not returned in describe_db_instances api call
+    # - assert:
+    #     that:
+    #       - not result.changed
+
+    - name: Idempotence upgrading a mariadb instance
       rds_instance:
         id: "{{ instance_id }}"
         state: present