---
# Tests for iam_role and iam_role_info
#
# Tests:
# - Minimal Role creation
# - Role deletion
# - Fetching a specific role
# - Creating roles w/ and w/o instance profiles
# - Creating roles w/ a path
# - Updating Max Session Duration
# - Updating Description
# - Managing list of managed policies
# - Managing list of inline policies (for testing _info)
# - Managing boundary policy
#
# Notes:
# - Only tests *documented* return values ( RESULT.iam_role )
# - There are some known timing issues with boto3 returning before actions
#   complete in the case of problems with "changed" status it's worth enabling
#   the standard_pauses and paranoid_pauses options as a first step in debugging
#
# Possible Bugs:
# - Fails to delete role if inline policies not removed first

- name: 'Setup AWS connection info'
  module_defaults:
    group/aws:
      aws_access_key: '{{ aws_access_key }}'
      aws_secret_key: '{{ aws_secret_key }}'
      security_token: '{{ security_token | default(omit) }}'
      region: '{{ aws_region }}'
    iam_role:
      assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
  collections:
    - amazon.aws
  block:
  # ===================================================================
  # Parameter Checks
  - name: 'Friendly message when creating an instance profile and adding a boundary profile'
    iam_role:
      name: '{{ test_role }}'
      boundary: '{{ boundary_policy }}'
    register: iam_role
    ignore_errors: yes
  - assert:
      that:
      - iam_role is failed
      - '"boundary policy" in iam_role.msg'
      - '"create_instance_profile" in iam_role.msg'
      - '"false" in iam_role.msg'

  - name: 'Friendly message when boundary profile is not an ARN'
    iam_role:
      name: '{{ test_role }}'
      boundary: 'AWSDenyAll'
      create_instance_profile: no
    register: iam_role
    ignore_errors: yes
  - assert:
      that:
      - iam_role is failed
      - '"Boundary policy" in iam_role.msg'
      - '"ARN" in iam_role.msg'

  - name: 'Friendly message when "present" without assume_role_policy_document'
    module_defaults: { iam_role: {} }
    iam_role:
      name: '{{ test_role }}'
    register: iam_role
    ignore_errors: yes
  - assert:
      that:
      - iam_role is failed
      - 'iam_role.msg.startswith("state is present but all of the following are missing")'
      - '"assume_role_policy_document" in iam_role.msg'

  - name: 'Maximum Session Duration needs to be between 1 and 12 hours'
    iam_role:
      name: '{{ test_role }}'
      max_session_duration: 3599
    register: iam_role
    ignore_errors: yes
  - assert:
      that:
      - iam_role is failed
      - '"max_session_duration must be between" in iam_role.msg'

  - name: 'Maximum Session Duration needs to be between 1 and 12 hours'
    iam_role:
      name: '{{ test_role }}'
      max_session_duration: 43201
    register: iam_role
    ignore_errors: yes
  - assert:
      that:
      - iam_role is failed
      - '"max_session_duration must be between" in iam_role.msg'

  - name: 'Role Paths must start with /'
    iam_role:
      name: '{{ test_role }}'
      path: 'test/'
    register: iam_role
    ignore_errors: yes
  - assert:
      that:
      - iam_role is failed
      - '"path must begin and end with /" in iam_role.msg'

  - name: 'Role Paths must end with /'
    iam_role:
      name: '{{ test_role }}'
      path: '/test'
    register: iam_role
    ignore_errors: yes
  - assert:
      that:
      - iam_role is failed
      - '"path must begin and end with /" in iam_role.msg'

  # ===================================================================
  # Supplemental resource pre-creation
  - name: 'Create Safe IAM Managed Policy'
    iam_managed_policy:
      state: present
      policy_name: '{{ custom_policy_name }}'
      policy_description: "A safe (deny-all) managed policy"
      policy: "{{ lookup('file', 'deny-all.json') }}"
    register: create_managed_policy
  - assert:
      that:
       - create_managed_policy is succeeded

  # ===================================================================
  # Rapid Role Creation and deletion
  - name: Try running some rapid fire create/delete tests
    # We've previously seen issues with iam_role returning before creation's
    # actually complete, if we think the issue's gone, let's try creating and
    # deleting things in quick succession
    when: not (standard_pauses | bool)
    block:
    - name: 'Minimal IAM Role without instance profile (rapid)'
      iam_role:
        name: '{{ test_role }}'
        create_instance_profile: no
      register: iam_role
    - name: 'Minimal IAM Role without instance profile (rapid)'
      iam_role:
        name: '{{ test_role }}'
        create_instance_profile: no
      register: iam_role_again
    - assert:
        that:
        - iam_role is changed
        - iam_role_again is not changed
    - name: 'Remove IAM Role (rapid)'
      iam_role:
        state: absent
        name: '{{ test_role }}'
      register: iam_role
    - name: 'Remove IAM Role (rapid)'
      iam_role:
        state: absent
        name: '{{ test_role }}'
      register: iam_role_again
    - assert:
        that:
        - iam_role is changed
        - iam_role_again is not changed

    - name: 'Minimal IAM Role without instance profile (rapid)'
      iam_role:
        name: '{{ test_role }}'
        create_instance_profile: no
      register: iam_role
    - name: 'Remove IAM Role (rapid)'
      iam_role:
        state: absent
        name: '{{ test_role }}'
      register: iam_role_again
    - assert:
        that:
        - iam_role is changed
        - iam_role_again is changed

  # ===================================================================
  # Role Creation
  # (without Instance profile)
  - name: 'iam_role_info before Role creation (no args)'
    iam_role_info:
    register: role_info
  - assert:
      that:
      - role_info is succeeded

  - name: 'iam_role_info before Role creation (search for test role)'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 0

  - name: 'Minimal IAM Role (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: no
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
  # Pause this first time, just in case we actually created something...
  - name: Short pause for role creation to finish
    pause:
      seconds: 10
    when: standard_pauses | bool

  - name: 'iam_role_info after Role creation in check_mode'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 0

  - name: 'Minimal IAM Role without instance profile'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: no
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - 'iam_role.iam_role.arn.startswith("arn")'
      - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
      # Would be nice to test the contents...
      - '"assume_role_policy_document" in iam_role.iam_role'
      - iam_role.iam_role.attached_policies | length == 0
      - iam_role.iam_role.max_session_duration == 3600
      - iam_role.iam_role.path == '/'
      - iam_role.iam_role.role_name == test_role
      - '"create_date" in iam_role.iam_role'
      - '"role_id" in iam_role.iam_role'
  - name: Short pause for role creation to finish
    pause:
      seconds: 10
    when: standard_pauses | bool

  - name: 'Minimal IAM Role without instance profile (no change)'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: no
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after Role creation'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - '"description" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 0
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 3600
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 0

  - name: 'Remove IAM Role'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      delete_instance_profile: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
  - name: Short pause for role removal to finish
    pause:
      seconds: 10
    when: paranoid_pauses | bool

  - name: 'iam_role_info after Role deletion'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 0

  # (with path)
  - name: 'Minimal IAM Role with path (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      path: '{{ test_path }}'
    register: iam_role
    check_mode: yes
  - assert:
      that:
      - iam_role is changed

  - name: 'Minimal IAM Role with path'
    iam_role:
      name: '{{ test_role }}'
      path: '{{ test_path }}'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - 'iam_role.iam_role.arn.startswith("arn")'
      - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
      # Would be nice to test the contents...
      - '"assume_role_policy_document" in iam_role.iam_role'
      - iam_role.iam_role.attached_policies | length == 0
      - iam_role.iam_role.max_session_duration == 3600
      - iam_role.iam_role.path == '{{ test_path }}'
      - iam_role.iam_role.role_name == test_role
      - '"create_date" in iam_role.iam_role'
      - '"role_id" in iam_role.iam_role'
  - name: Short pause for role creation to finish
    pause:
      seconds: 10
    when: standard_pauses | bool

  - name: 'Minimal IAM Role with path (no change)'
    iam_role:
      name: '{{ test_role }}'
      path: '{{ test_path }}'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after Role creation'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - '"description" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 3600
      - role_info.iam_roles[0].path == '{{ test_path }}'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 0

  - name: 'iam_role_info after Role creation (searching a path)'
    iam_role_info:
      path_prefix: '{{ test_path }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - '"description" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 3600
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].path == '{{ test_path }}'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 0

  - name: 'Remove IAM Role'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      path: '{{ test_path }}'
      # If we don't delete the existing profile it'll be reused (with the path)
      # by the test below.
      delete_instance_profile: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
  - name: Short pause for role removal to finish
    pause:
      seconds: 10
    when: paranoid_pauses | bool

  - name: 'iam_role_info after Role deletion'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 0

  # (with Instance profile)
  - name: 'Minimal IAM Role with instance profile'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - 'iam_role.iam_role.arn.startswith("arn")'
      - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
      # Would be nice to test the contents...
      - '"assume_role_policy_document" in iam_role.iam_role'
      - iam_role.iam_role.attached_policies | length == 0
      - iam_role.iam_role.max_session_duration == 3600
      - iam_role.iam_role.path == '/'
      - iam_role.iam_role.role_name == test_role
      - '"create_date" in iam_role.iam_role'
      - '"role_id" in iam_role.iam_role'
  - name: Short pause for role creation to finish
    pause:
      seconds: 10
    when: standard_pauses | bool

  - name: 'Minimal IAM Role wth instance profile (no change)'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: yes
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after Role creation'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - '"description" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 3600
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 0

  # ===================================================================
  # Max Session Duration Manipulation

  - name: 'Update Max Session Duration (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      max_session_duration: 43200
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Update Max Session Duration'
    iam_role:
      name: '{{ test_role }}'
      max_session_duration: 43200
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - iam_role.iam_role.max_session_duration == 43200

  - name: 'Update Max Session Duration (no change)'
    iam_role:
      name: '{{ test_role }}'
      max_session_duration: 43200
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after updating Max Session Duration'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - '"description" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 0

  # ===================================================================
  # Description Manipulation

  - name: 'Add Description (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      description: 'Ansible Test Role {{ resource_prefix }}'
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Add Description'
    iam_role:
      name: '{{ test_role }}'
      description: 'Ansible Test Role {{ resource_prefix }}'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'

  - name: 'Add Description (no change)'
    iam_role:
      name: '{{ test_role }}'
      description: 'Ansible Test Role {{ resource_prefix }}'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role
      - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'

  - name: 'iam_role_info after adding Description'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 0

  - name: 'Update Description (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      description: 'Ansible Test Role (updated) {{ resource_prefix }}'
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Update Description'
    iam_role:
      name: '{{ test_role }}'
      description: 'Ansible Test Role (updated) {{ resource_prefix }}'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'

  - name: 'Update Description (no change)'
    iam_role:
      name: '{{ test_role }}'
      description: 'Ansible Test Role (updated) {{ resource_prefix }}'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role
      - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'

  - name: 'iam_role_info after updating Description'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 0


  # ===================================================================
  # Tag Manipulation

  - name: 'Add Tag (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      tags:
        TagA: ValueA
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Add Tag'
    iam_role:
      name: '{{ test_role }}'
      tags:
        TagA: ValueA
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - iam_role.iam_role.tags | length == 1
      - '"TagA" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagA == "ValueA"

  - name: 'Add Tag (no change)'
    iam_role:
      name: '{{ test_role }}'
      tags:
        TagA: ValueA
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role
      - '"TagA" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagA == "ValueA"

  - name: 'iam_role_info after adding Tags'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 1
      - '"TagA" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagA == "ValueA"

  - name: 'Update Tag (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      tags:
        TagA: AValue
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Update Tag'
    iam_role:
      name: '{{ test_role }}'
      tags:
        TagA: AValue
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - '"TagA" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagA == "AValue"

  - name: 'Update Tag (no change)'
    iam_role:
      name: '{{ test_role }}'
      tags:
        TagA: AValue
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role
      - '"TagA" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagA == "AValue"

  - name: 'iam_role_info after updating Tag'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 1
      - '"TagA" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagA == "AValue"

  - name: 'Add second Tag without purge (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      purge_tags: no
      tags:
        TagB: ValueB
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Add second Tag without purge'
    iam_role:
      name: '{{ test_role }}'
      purge_tags: no
      tags:
        TagB: ValueB
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - '"TagB" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagB == "ValueB"

  - name: 'Add second Tag without purge (no change)'
    iam_role:
      name: '{{ test_role }}'
      purge_tags: no
      tags:
        TagB: ValueB
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role
      - '"TagB" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagB == "ValueB"

  - name: 'iam_role_info after adding second Tag without purge'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 2
      - '"TagA" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagA == "AValue"
      - '"TagB" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagB == "ValueB"

  - name: 'Purge first tag (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      purge_tags: yes
      tags:
        TagB: ValueB
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Purge first tag'
    iam_role:
      name: '{{ test_role }}'
      purge_tags: yes
      tags:
        TagB: ValueB
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - '"TagB" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagB == "ValueB"

  - name: 'Purge first tag (no change)'
    iam_role:
      name: '{{ test_role }}'
      purge_tags: yes
      tags:
        TagB: ValueB
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role
      - '"TagB" in iam_role.iam_role.tags'
      - iam_role.iam_role.tags.TagB == "ValueB"

  - name: 'iam_role_info after purging first Tag'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 1
      - '"TagA" not in role_info.iam_roles[0].tags'
      - '"TagB" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagB == "ValueB"


  # ===================================================================
  # Policy Manipulation

  - name: 'Add Managed Policy (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      purge_policies: no
      managed_policy:
      - '{{ safe_managed_policy }}'
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Add Managed Policy'
    iam_role:
      name: '{{ test_role }}'
      purge_policies: no
      managed_policy:
      - '{{ safe_managed_policy }}'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role

  - name: 'Add Managed Policy (no change)'
    iam_role:
      name: '{{ test_role }}'
      purge_policies: no
      managed_policy:
      - '{{ safe_managed_policy }}'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after adding Managed Policy'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 1
      - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - custom_policy_name not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 1
      - '"TagB" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagB == "ValueB"

  - name: 'Update Managed Policy without purge (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      purge_policies: no
      managed_policy:
      - '{{ custom_policy_name }}'
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Update Managed Policy without purge'
    iam_role:
      name: '{{ test_role }}'
      purge_policies: no
      managed_policy:
      - '{{ custom_policy_name }}'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role

  - name: 'Update Managed Policy without purge (no change)'
    iam_role:
      name: '{{ test_role }}'
      purge_policies: no
      managed_policy:
      - '{{ custom_policy_name }}'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after updating Managed Policy without purge'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 2
      - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 1
      - '"TagB" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagB == "ValueB"

  # Managed Policies are purged by default
  - name: 'Update Managed Policy with purge (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      managed_policy:
      - '{{ custom_policy_name }}'
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Update Managed Policy with purge'
    iam_role:
      name: '{{ test_role }}'
      managed_policy:
      - '{{ custom_policy_name }}'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role

  - name: 'Update Managed Policy with purge (no change)'
    iam_role:
      name: '{{ test_role }}'
      managed_policy:
      - '{{ custom_policy_name }}'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after updating Managed Policy with purge'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 1
      - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 1
      - '"TagB" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagB == "ValueB"

  # ===================================================================
  # Inline Policy (test _info behaviour)

  # XXX Not sure if it's a bug in Ansible or a "quirk" of AWS, but these two
  # policies need to have at least different Sids or the second doesn't show
  # up...

  - name: 'Attach inline policy a'
    iam_policy:
      state: present
      iam_type: 'role'
      iam_name: '{{ test_role }}'
      policy_name: 'inline-policy-a'
      policy_json: '{{ lookup("file", "deny-all-a.json") }}'

  - name: 'Attach inline policy b'
    iam_policy:
      state: present
      iam_type: 'role'
      iam_name: '{{ test_role }}'
      policy_name: 'inline-policy-b'
      policy_json: '{{ lookup("file", "deny-all-b.json") }}'

  - name: 'iam_role_info after attaching inline policies (using iam_policy)'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 2
      - '"inline-policy-a" in role_info.iam_roles[0].inline_policies'
      - '"inline-policy-b" in role_info.iam_roles[0].inline_policies'
      - role_info.iam_roles[0].instance_profiles | length == 1
      - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
      - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
      - role_info.iam_roles[0].managed_policies | length == 1
      - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == '/'
      - '"permissions_boundary" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - role_info.iam_roles[0].tags | length == 1
      - '"TagB" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagB == "ValueB"

  # XXX iam_role fails to remove inline policies before deleting the role
  - name: 'Detach inline policy a'
    iam_policy:
      state: absent
      iam_type: 'role'
      iam_name: '{{ test_role }}'
      policy_name: 'inline-policy-a'

  - name: 'Detach inline policy b'
    iam_policy:
      state: absent
      iam_type: 'role'
      iam_name: '{{ test_role }}'
      policy_name: 'inline-policy-b'

  # ===================================================================
  # Role Removal
  - name: 'Remove IAM Role (CHECK MODE)'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      delete_instance_profile: yes
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
  - name: 'Short pause for role removal to finish'
    pause:
      seconds: 10
    when: paranoid_pauses | bool

  - name: 'iam_role_info after deleting role in check mode'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1

  - name: 'Remove IAM Role'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      delete_instance_profile: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
  - name: 'Short pause for role removal to finish'
    pause:
      seconds: 10
    when: paranoid_pauses | bool

  - name: 'iam_role_info after deleting role'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 0

  - name: 'Remove IAM Role (should be gone already)'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      delete_instance_profile: yes
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
  - name: 'Short pause for role removal to finish'
    pause:
      seconds: 10
    when: paranoid_pauses | bool

  # ===================================================================
  # Boundary Policy (requires create_instance_profile: no)
  - name: 'Create minimal role with no boundary policy'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: no
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role

  - name: 'Configure Boundary Policy (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: no
      boundary: '{{ boundary_policy }}'
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed

  - name: 'Configure Boundary Policy'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: no
      boundary: '{{ boundary_policy }}'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role

  - name: 'Configure Boundary Policy (no change)'
    iam_role:
      name: '{{ test_role }}'
      create_instance_profile: no
      boundary: '{{ boundary_policy }}'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after adding boundary policy'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - '"description" not in role_info.iam_roles[0]'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 0
      - role_info.iam_roles[0].managed_policies | length == 0
      - role_info.iam_roles[0].max_session_duration == 3600
      - role_info.iam_roles[0].path == '/'
      - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
      - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role

  - name: 'Remove IAM Role'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      delete_instance_profile: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
  - name: Short pause for role removal to finish
    pause:
      seconds: 10
    when: paranoid_pauses | bool

  # ===================================================================
  # Complex role Creation
  - name: 'Complex IAM Role (CHECK MODE)'
    iam_role:
      name: '{{ test_role }}'
      assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
      boundary: '{{ boundary_policy }}'
      create_instance_profile: no
      description: 'Ansible Test Role {{ resource_prefix }}'
      managed_policy:
      - '{{ safe_managed_policy }}'
      - '{{ custom_policy_name }}'
      max_session_duration: 43200
      path: '{{ test_path }}'
      tags:
        TagA: 'ValueA'
    check_mode: yes
    register: iam_role
  - assert:
      that:
      - iam_role is changed
  - name: Short pause for role creation to finish
    pause:
      seconds: 10
    when: standard_pauses | bool

  - name: 'iam_role_info after Complex Role creation in check_mode'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 0

  - name: 'Complex IAM Role'
    iam_role:
      name: '{{ test_role }}'
      assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
      boundary: '{{ boundary_policy }}'
      create_instance_profile: no
      description: 'Ansible Test Role {{ resource_prefix }}'
      managed_policy:
      - '{{ safe_managed_policy }}'
      - '{{ custom_policy_name }}'
      max_session_duration: 43200
      path: '{{ test_path }}'
      tags:
        TagA: 'ValueA'
    register: iam_role
  - assert:
      that:
      - iam_role is changed
      - iam_role.iam_role.role_name == test_role
      - 'iam_role.iam_role.arn.startswith("arn")'
      - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
      # Would be nice to test the contents...
      - '"assume_role_policy_document" in iam_role.iam_role'
      - iam_role.iam_role.attached_policies | length == 2
      - iam_role.iam_role.max_session_duration == 43200
      - iam_role.iam_role.path == test_path
      - iam_role.iam_role.role_name == test_role
      - '"create_date" in iam_role.iam_role'
      - '"role_id" in iam_role.iam_role'
  - name: Short pause for role creation to finish
    pause:
      seconds: 10
    when: standard_pauses | bool

  - name: 'Complex IAM role (no change)'
    iam_role:
      name: '{{ test_role }}'
      assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
      boundary: '{{ boundary_policy }}'
      create_instance_profile: no
      description: 'Ansible Test Role {{ resource_prefix }}'
      managed_policy:
      - '{{ safe_managed_policy }}'
      - '{{ custom_policy_name }}'
      max_session_duration: 43200
      path: '{{ test_path }}'
      tags:
        TagA: 'ValueA'
    register: iam_role
  - assert:
      that:
      - iam_role is not changed
      - iam_role.iam_role.role_name == test_role

  - name: 'iam_role_info after Role creation'
    iam_role_info:
      name: '{{ test_role }}'
    register: role_info
  - assert:
      that:
      - role_info is succeeded
      - role_info.iam_roles | length == 1
      - 'role_info.iam_roles[0].arn.startswith("arn")'
      - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
      - '"assume_role_policy_document" in role_info.iam_roles[0]'
      - '"create_date" in role_info.iam_roles[0]'
      - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
      - role_info.iam_roles[0].inline_policies | length == 0
      - role_info.iam_roles[0].instance_profiles | length == 0
      - role_info.iam_roles[0].managed_policies | length == 2
      - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
      - role_info.iam_roles[0].max_session_duration == 43200
      - role_info.iam_roles[0].path == test_path
      - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
      - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
      - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
      - role_info.iam_roles[0].role_name == test_role
      - '"TagA" in role_info.iam_roles[0].tags'
      - role_info.iam_roles[0].tags.TagA == "ValueA"

  always:
  # ===================================================================
  # Cleanup

  # XXX iam_role fails to remove inline policies before deleting the role
  - name: 'Detach inline policy a'
    iam_policy:
      state: absent
      iam_type: 'role'
      iam_name: '{{ test_role }}'
      policy_name: 'inline-policy-a'
    ignore_errors: true

  - name: 'Detach inline policy b'
    iam_policy:
      state: absent
      iam_type: 'role'
      iam_name: '{{ test_role }}'
      policy_name: 'inline-policy-b'
    ignore_errors: true

  - name: 'Remove IAM Role'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      delete_instance_profile: yes
    ignore_errors: true

  - name: 'Remove IAM Role (with path)'
    iam_role:
      state: absent
      name: '{{ test_role }}'
      path: '{{ test_path }}'
      delete_instance_profile: yes
    ignore_errors: true

  - name: 'iam_role_info after Role deletion'
    iam_role_info:
      name: '{{ test_role }}'
    ignore_errors: true

  - name: 'Remove test managed policy'
    iam_managed_policy:
      state: absent
      policy_name: '{{ custom_policy_name }}'
