diff options
Diffstat (limited to 'ansible_collections/community/general/tests')
19 files changed, 1110 insertions, 29 deletions
diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml index ec446d241..7ff30bcd5 100644 --- a/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml +++ b/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml @@ -15,6 +15,7 @@ tested_filesystems: # - 1.7.0 requires at least 30Mo # - 1.10.0 requires at least 38Mo # - resizefs asserts when initial fs is smaller than 60Mo and seems to require 1.10.0 + bcachefs: {fssize: 20, grow: true, new_uuid: null} ext4: {fssize: 10, grow: true, new_uuid: 'random'} ext4dev: {fssize: 10, grow: true, new_uuid: 'random'} ext3: {fssize: 10, grow: true, new_uuid: 'random'} diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml index 0c15c2155..51361079c 100644 --- a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml +++ b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml @@ -36,7 +36,7 @@ # Not available: btrfs, lvm, f2fs, ocfs2 # All BSD systems use swap fs, but only Linux needs mkswap # Supported: ext2/3/4 (e2fsprogs), xfs (xfsprogs), reiserfs (progsreiserfs), vfat - - 'not (ansible_system == "FreeBSD" and item.0.key in ["btrfs", "f2fs", "swap", "lvm", "ocfs2"])' + - 'not (ansible_system == "FreeBSD" and item.0.key in ["bcachefs", "btrfs", "f2fs", "swap", "lvm", "ocfs2"])' # Available on FreeBSD but not on testbed (util-linux conflicts with e2fsprogs): wipefs, mkfs.minix - 'not (ansible_system == "FreeBSD" and item.1 in ["overwrite_another_fs", "remove_fs"])' @@ -46,6 +46,10 @@ # Other limitations and corner cases + # bcachefs only on Alpine > 3.18 and Arch Linux for now + # other distributions have too old versions of bcachefs-tools and/or util-linux (blkid for UUID tests) + - 'ansible_distribution == "Alpine" and ansible_distribution_version is version("3.18", ">") and item.0.key == "bcachefs"' + - 'ansible_distribution == "Archlinux" and item.0.key == "bcachefs"' # f2fs-tools and reiserfs-utils packages not available with RHEL/CentOS on CI - 'not (ansible_distribution in ["CentOS", "RedHat"] and item.0.key in ["f2fs", "reiserfs"])' - 'not (ansible_os_family == "RedHat" and ansible_distribution_major_version is version("8", ">=") and diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/setup.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/setup.yml index 97dafaeee..77c028aca 100644 --- a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/setup.yml +++ b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/setup.yml @@ -16,6 +16,16 @@ - e2fsprogs - xfsprogs +- name: "Install bcachefs tools" + ansible.builtin.package: + name: bcachefs-tools + state: present + when: + # bcachefs only on Alpine > 3.18 and Arch Linux for now + # other distributions have too old versions of bcachefs-tools and/or util-linux (blkid for UUID tests) + - ansible_distribution == "Alpine" and ansible_distribution_version is version("3.18", ">") + - ansible_distribution == "Archlinux" + - name: "Install btrfs progs" ansible.builtin.package: name: btrfs-progs diff --git a/ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml index a2eca36a6..abb92dfc5 100644 --- a/ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml +++ b/ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml @@ -12,15 +12,21 @@ another_section: connection: 'ssh' + interpolate_test: + interpolate_test_key: '%' + - name: 'Write INI file that reflects ini_test_dict to {{ ini_test_file }}' ansible.builtin.copy: dest: '{{ ini_test_file }}' content: | [section_name] - key_name=key value + key_name = key value [another_section] - connection=ssh + connection = ssh + + [interpolate_test] + interpolate_test_key = % - name: 'Slurp the test file: {{ ini_test_file }}' ansible.builtin.slurp: diff --git a/ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml index 877d4471d..e16aa98a5 100644 --- a/ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml +++ b/ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml @@ -16,6 +16,9 @@ another_section: connection: 'ssh' + interpolate_test: + interpolate_test_key: '%' + - name: 'Write INI file manually to {{ ini_test_file }}' ansible.builtin.copy: dest: '{{ ini_test_file }}' @@ -26,6 +29,9 @@ [another_section] connection = ssh + [interpolate_test] + interpolate_test_key = % + - name: 'Slurp the manually created test file: {{ ini_test_file }}' ansible.builtin.slurp: src: '{{ ini_test_file }}' diff --git a/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/check_mode.yml b/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/check_mode.yml index 9f52dc122..b4538200f 100644 --- a/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/check_mode.yml +++ b/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/check_mode.yml @@ -52,6 +52,38 @@ - removal_result is not changed msg: "Removing an absent flatpak shall mark module execution as not changed" +# state=latest on absent flatpak + +- name: Test state=latest of absent flatpak (check mode) + flatpak: + name: com.dummy.App1 + remote: dummy-remote + state: latest + register: latest_result + check_mode: true + +- name: Verify state=latest of absent flatpak test result (check mode) + assert: + that: + - latest_result is changed + msg: "state=latest an absent flatpak shall mark module execution as changed" + +- name: Test non-existent idempotency of state=latest of absent flatpak (check mode) + flatpak: + name: com.dummy.App1 + remote: dummy-remote + state: latest + register: double_latest_result + check_mode: true + +- name: Verify non-existent idempotency of state=latest of absent flatpak test result (check mode) + assert: + that: + - double_latest_result is changed + msg: | + state=latest an absent flatpak a second time shall still mark module execution + as changed in check mode + # state=present with url on absent flatpak - name: Test addition of absent flatpak with url (check mode) @@ -101,6 +133,40 @@ - url_removal_result is not changed msg: "Removing an absent flatpak shall mark module execution as not changed" +# state=latest with url on absent flatpak + +- name: Test state=latest of absent flatpak with url (check mode) + flatpak: + name: http://127.0.0.1:8000/repo/com.dummy.App1.flatpakref + remote: dummy-remote + state: latest + register: url_latest_result + check_mode: true + +- name: Verify state=latest of absent flatpak with url test result (check mode) + assert: + that: + - url_latest_result is changed + msg: "state=latest an absent flatpak from URL shall mark module execution as changed" + +- name: Test non-existent idempotency of state=latest of absent flatpak with url (check mode) + flatpak: + name: http://127.0.0.1:8000/repo/com.dummy.App1.flatpakref + remote: dummy-remote + state: latest + register: double_url_latest_result + check_mode: true + +- name: > + Verify non-existent idempotency of additionof state=latest flatpak with url test + result (check mode) + assert: + that: + - double_url_latest_result is changed + msg: | + state=latest an absent flatpak from URL a second time shall still mark module execution + as changed in check mode + # - Tests with present flatpak ------------------------------------------------- # state=present on present flatpak @@ -149,6 +215,22 @@ Removing a present flatpak a second time shall still mark module execution as changed in check mode +# state=latest on present flatpak + +- name: Test state=latest of present flatpak (check mode) + flatpak: + name: com.dummy.App2 + remote: dummy-remote + state: latest + register: latest_present_result + check_mode: true + +- name: Verify latest test result of present flatpak (check mode) + assert: + that: + - latest_present_result is changed + msg: "state=latest an present flatpak shall mark module execution as changed" + # state=present with url on present flatpak - name: Test addition with url of present flatpak (check mode) @@ -195,3 +277,19 @@ that: - double_url_removal_present_result is changed msg: Removing an absent flatpak a second time shall still mark module execution as changed + +# state=latest with url on present flatpak + +- name: Test state=latest with url of present flatpak (check mode) + flatpak: + name: http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + remote: dummy-remote + state: latest + register: url_latest_present_result + check_mode: true + +- name: Verify state=latest with url of present flatpak test result (check mode) + assert: + that: + - url_latest_present_result is changed + msg: "state=latest a present flatpak from URL shall mark module execution as changed" diff --git a/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/test.yml b/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/test.yml index 29c4efbe9..658f7b116 100644 --- a/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/test.yml +++ b/ansible_collections/community/general/tests/integration/targets/flatpak/tasks/test.yml @@ -65,6 +65,45 @@ - double_removal_result is not changed msg: "state=absent shall not do anything when flatpak is not present" +# state=latest + +- name: Test state=latest - {{ method }} + flatpak: + name: com.dummy.App1 + remote: dummy-remote + state: present + method: "{{ method }}" + no_dependencies: true + register: latest_result + +- name: Verify state=latest test result - {{ method }} + assert: + that: + - latest_result is changed + msg: "state=latest shall add flatpak when absent" + +- name: Test idempotency of state=latest - {{ method }} + flatpak: + name: com.dummy.App1 + remote: dummy-remote + state: present + method: "{{ method }}" + no_dependencies: true + register: double_latest_result + +- name: Verify idempotency of state=latest test result - {{ method }} + assert: + that: + - double_latest_result is not changed + msg: "state=latest shall not do anything when flatpak is already present" + +- name: Cleanup after state=present test - {{ method }} + flatpak: + name: com.dummy.App1 + state: absent + method: "{{ method }}" + no_dependencies: true + # state=present with url as name - name: Test addition with url - {{ method }} @@ -152,6 +191,45 @@ method: "{{ method }}" no_dependencies: true +# state=latest with url as name + +- name: Test state=latest with url - {{ method }} + flatpak: + name: http://127.0.0.1:8000/repo/com.dummy.App1.flatpakref + remote: dummy-remote + state: latest + method: "{{ method }}" + no_dependencies: true + register: url_latest_result + +- name: Verify state=latest test result - {{ method }} + assert: + that: + - url_latest_result is changed + msg: "state=present with url as name shall add flatpak when absent" + +- name: Test idempotency of state=latest with url - {{ method }} + flatpak: + name: http://127.0.0.1:8000/repo/com.dummy.App1.flatpakref + remote: dummy-remote + state: latest + method: "{{ method }}" + no_dependencies: true + register: double_url_latest_result + +- name: Verify idempotency of state=latest with url test result - {{ method }} + assert: + that: + - double_url_latest_result is not changed + msg: "state=present with url as name shall not do anything when flatpak is already present" + +- name: Cleanup after state=present with url test - {{ method }} + flatpak: + name: com.dummy.App1 + state: absent + method: "{{ method }}" + no_dependencies: true + # state=present with list of packages - name: Test addition with list - {{ method }} @@ -287,3 +365,84 @@ that: - double_removal_result is not changed msg: "state=absent shall not do anything when flatpak is not present" + +# state=latest with list of packages + +- name: Test state=latest with list - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + remote: dummy-remote + state: latest + method: "{{ method }}" + no_dependencies: true + register: latest_result + +- name: Verify state=latest with list test result - {{ method }} + assert: + that: + - latest_result is changed + msg: "state=present shall add flatpak when absent" + +- name: Test idempotency of state=latest with list - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + remote: dummy-remote + state: latest + method: "{{ method }}" + no_dependencies: true + register: double_latest_result + +- name: Verify idempotency of state=latest with list test result - {{ method }} + assert: + that: + - double_latest_result is not changed + msg: "state=present shall not do anything when flatpak is already present" + +- name: Test state=latest with list partially installed - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + - com.dummy.App3 + remote: dummy-remote + state: latest + method: "{{ method }}" + no_dependencies: true + register: latest_result + +- name: Verify state=latest with list partially installed test result - {{ method }} + assert: + that: + - latest_result is changed + msg: "state=present shall add flatpak when absent" + +- name: Test idempotency of state=latest with list partially installed - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + - com.dummy.App3 + remote: dummy-remote + state: latest + method: "{{ method }}" + no_dependencies: true + register: double_latest_result + +- name: Verify idempotency of state=latest with list partially installed test result - {{ method }} + assert: + that: + - double_latest_result is not changed + msg: "state=present shall not do anything when flatpak is already present" + +- name: Cleanup after state=present with list test - {{ method }} + flatpak: + name: + - com.dummy.App1 + - com.dummy.App2 + - com.dummy.App3 + state: absent + method: "{{ method }}" diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml index 0ed3c2817..8fd88074b 100644 --- a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml +++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml @@ -16,7 +16,6 @@ - name: include tasks block: - - name: include tasks to perform basic tests include_tasks: tests/00-basic.yml @@ -50,3 +49,6 @@ - name: include tasks to test optional spaces in section headings include_tasks: tests/07-section_name_spaces.yml + + - name: include tasks to test section_has_values + include_tasks: tests/08-section.yml diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/08-section.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/08-section.yml new file mode 100644 index 000000000..4f3a135e1 --- /dev/null +++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/08-section.yml @@ -0,0 +1,341 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +## testing section selection + +- name: test-section 1 - Create starting ini file + copy: + content: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + fav = lemonade + beverage = pineapple juice + + dest: "{{ output_file }}" + +- name: test-section 1 - Modify starting ini file + ini_file: + dest: "{{ output_file }}" + section: drinks + option: car + value: volvo + state: present + register: result1 + +- name: test-section 1 - Read modified file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-section 1 - Create expected result + set_fact: + expected1: | + [drinks] + fav = lemonade + beverage = orange juice + car = volvo + + [drinks] + fav = lemonade + beverage = pineapple juice + output1: "{{ output_content.content | b64decode }}" + +- name: test-section 1 - Option was added to first section + assert: + that: + - result1 is changed + - result1.msg == 'option added' + - output1 == expected1 + +# ---------------- + +- name: test-section 2 - Create starting ini file + copy: + content: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + fav = lemonade + beverage = pineapple juice + + dest: "{{ output_file }}" + +- name: test-section 2 - Modify starting ini file + ini_file: + dest: "{{ output_file }}" + section: drinks + section_has_values: + - option: beverage + value: pineapple juice + option: car + value: volvo + state: present + register: result1 + +- name: test-section 2 - Read modified file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-section 2 - Create expected result + set_fact: + expected1: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + fav = lemonade + beverage = pineapple juice + car = volvo + output1: "{{ output_content.content | b64decode }}" + +- name: test-section 2 - Option added to second section specified with section_has_values + assert: + that: + - result1 is changed + - result1.msg == 'option added' + - output1 == expected1 + +# ---------------- + +- name: test-section 3 - Create starting ini file + copy: + content: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + fav = lemonade + beverage = pineapple juice + + dest: "{{ output_file }}" + +- name: test-section 3 - Modify starting ini file + ini_file: + dest: "{{ output_file }}" + section: drinks + section_has_values: + - option: beverage + value: pineapple juice + option: fav + value: lemonade + state: absent + register: result1 + +- name: test-section 3 - Read modified file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-section 3 - Create expected result + set_fact: + expected1: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + beverage = pineapple juice + output1: "{{ output_content.content | b64decode }}" + +- name: test-section 3 - Option was removed from specified section + assert: + that: + - result1 is changed + - result1.msg == 'option changed' + - output1 == expected1 + +# ---------------- + +- name: test-section 4 - Create starting ini file + copy: + content: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + fav = lemonade + beverage = pineapple juice + + dest: "{{ output_file }}" + +- name: test-section 4 - Modify starting ini file + ini_file: + dest: "{{ output_file }}" + section: drinks + section_has_values: + - option: beverage + value: alligator slime + option: fav + value: tea + state: present + register: result1 + +- name: test-section 4 - Read modified file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-section 4 - Create expected result + set_fact: + expected1: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + fav = lemonade + beverage = pineapple juice + [drinks] + beverage = alligator slime + fav = tea + output1: "{{ output_content.content | b64decode }}" + +- name: test-section 4 - New section created, including required values + assert: + that: + - result1 is changed + - result1.msg == 'section and option added' + - output1 == expected1 + +# ---------------- + +- name: test-section 5 - Modify test-section 4 result file + ini_file: + dest: "{{ output_file }}" + section: drinks + section_has_values: + - option: fav + value: lemonade + - option: beverage + value: pineapple juice + state: absent + register: result1 + +- name: test-section 5 - Read modified file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-section 5 - Create expected result + set_fact: + expected1: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + beverage = alligator slime + fav = tea + output1: "{{ output_content.content | b64decode }}" + +- name: test-section 5 - Section removed as specified + assert: + that: + - result1 is changed + - result1.msg == 'section removed' + - output1 == expected1 + +# ---------------- + +- name: test-section 6 - Modify test-section 5 result file with multiple values + ini_file: + dest: "{{ output_file }}" + section: drinks + section_has_values: + - option: fav + values: + - cherry + - lemon + - vanilla + - option: beverage + value: pineapple juice + state: present + option: fav + values: + - vanilla + - grape + exclusive: false + register: result1 + +- name: test-section 6 - Read modified file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-section 6 - Create expected result + set_fact: + expected1: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + beverage = alligator slime + fav = tea + [drinks] + beverage = pineapple juice + fav = vanilla + fav = grape + fav = cherry + fav = lemon + output1: "{{ output_content.content | b64decode }}" + +- name: test-section 6 - New section added + assert: + that: + - result1 is changed + - result1.msg == 'section and option added' + - output1 == expected1 + +# ---------------- + +- name: test-section 7 - Modify test-section 6 result file with exclusive value + ini_file: + dest: "{{ output_file }}" + section: drinks + section_has_values: + - option: fav + value: vanilla + state: present + option: fav + value: cherry + exclusive: true + register: result1 + +- name: test-section 7 - Read modified file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-section 7 - Create expected result + set_fact: + expected1: | + [drinks] + fav = lemonade + beverage = orange juice + + [drinks] + beverage = alligator slime + fav = tea + [drinks] + beverage = pineapple juice + fav = cherry + output1: "{{ output_content.content | b64decode }}" + +- name: test-section 7 - Option changed + assert: + that: + - result1 is changed + - result1.msg == 'option changed' + - output1 == expected1 diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/README.md b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/README.md new file mode 100644 index 000000000..cd1152dad --- /dev/null +++ b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/README.md @@ -0,0 +1,20 @@ +<!-- +Copyright (c) Ansible Project +GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +SPDX-License-Identifier: GPL-3.0-or-later +--> +# Running keycloak_client_rolescope module integration test + +To run Keycloak component info module's integration test, start a keycloak server using Docker: + + docker run -d --rm --name mykeycloak -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:latest start-dev --http-relative-path /auth + +Run integration tests: + + ansible-test integration -v keycloak_client_rolescope --allow-unsupported --docker fedora35 --docker-network host + +Cleanup: + + docker stop mykeycloak + + diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/aliases b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/aliases new file mode 100644 index 000000000..bd1f02444 --- /dev/null +++ b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/aliases @@ -0,0 +1,5 @@ +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +unsupported diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/tasks/main.yml new file mode 100644 index 000000000..8675c9548 --- /dev/null +++ b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/tasks/main.yml @@ -0,0 +1,317 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later +- name: Wait for Keycloak + uri: + url: "{{ url }}/admin/" + status_code: 200 + validate_certs: no + register: result + until: result.status == 200 + retries: 10 + delay: 10 + +- name: Delete realm if exists + community.general.keycloak_realm: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + state: absent + +- name: Create realm + community.general.keycloak_realm: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + id: "{{ realm }}" + realm: "{{ realm }}" + state: present + +- name: Create a Keycloak realm role + community.general.keycloak_role: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + name: "{{ item }}" + realm: "{{ realm }}" + with_items: + - "{{ realm_role_admin }}" + - "{{ realm_role_user }}" + +- name: Client private + community.general.keycloak_client: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_private }}" + state: present + redirect_uris: + - "https://my-backend-api.c.org/" + fullScopeAllowed: True + attributes: '{{client_attributes1}}' + public_client: False + +- name: Create a Keycloak client role + community.general.keycloak_role: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + name: "{{ item }}" + realm: "{{ realm }}" + client_id: "{{ client_name_private }}" + with_items: + - "{{ client_role_admin }}" + - "{{ client_role_user }}" + +- name: Client public + community.general.keycloak_client: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + redirect_uris: + - "https://my-onepage-app-frontend.c.org/" + attributes: '{{client_attributes1}}' + full_scope_allowed: False + public_client: True + + +- name: Map roles to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + client_scope_id: "{{ client_name_private }}" + role_names: + - "{{ client_role_admin }}" + - "{{ client_role_user }}" + register: result + +- name: Assert mapping created + assert: + that: + - result is changed + - result.end_state | length == 2 + +- name: remap role user to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + client_scope_id: "{{ client_name_private }}" + role_names: + - "{{ client_role_user }}" + register: result + +- name: Assert mapping created + assert: + that: + - result is not changed + - result.end_state | length == 2 + +- name: Remove Map role admin to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + client_scope_id: "{{ client_name_private }}" + role_names: + - "{{ client_role_admin }}" + state: absent + register: result + +- name: Assert mapping deleted + assert: + that: + - result is changed + - result.end_state | length == 1 + - result.end_state[0].name == client_role_user + +- name: Map missing roles to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + client_scope_id: "{{ client_name_private }}" + role_names: + - "{{ client_role_admin }}" + - "{{ client_role_not_exists }}" + ignore_errors: true + register: result + +- name: Assert failed mapping missing role + assert: + that: + - result is failed + +- name: Map roles duplicate + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + client_scope_id: "{{ client_name_private }}" + role_names: + - "{{ client_role_admin }}" + - "{{ client_role_admin }}" + register: result + +- name: Assert result + assert: + that: + - result is changed + - result.end_state | length == 2 + +- name: Map roles to private client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_private }}" + role_names: + - "{{ realm_role_admin }}" + ignore_errors: true + register: result + +- name: Assert failed mapping role to full scope client + assert: + that: + - result is failed + +- name: Map realm role to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + role_names: + - "{{ realm_role_admin }}" + register: result + +- name: Assert result + assert: + that: + - result is changed + - result.end_state | length == 1 + +- name: Map two realm roles to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + role_names: + - "{{ realm_role_admin }}" + - "{{ realm_role_user }}" + register: result + +- name: Assert result + assert: + that: + - result is changed + - result.end_state | length == 2 + +- name: Unmap all realm roles to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + role_names: + - "{{ realm_role_admin }}" + - "{{ realm_role_user }}" + state: absent + register: result + +- name: Assert result + assert: + that: + - result is changed + - result.end_state | length == 0 + +- name: Map missing realm role to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + role_names: + - "{{ realm_role_not_exists }}" + ignore_errors: true + register: result + +- name: Assert failed mapping missing realm role + assert: + that: + - result is failed + +- name: Check-mode try to Map realm roles to public client + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + role_names: + - "{{ realm_role_admin }}" + - "{{ realm_role_user }}" + check_mode: true + register: result + +- name: Assert result + assert: + that: + - result is changed + - result.end_state | length == 2 + +- name: Check-mode step two, check if change where applied + community.general.keycloak_client_rolescope: + auth_keycloak_url: "{{ url }}" + auth_realm: "{{ admin_realm }}" + auth_username: "{{ admin_user }}" + auth_password: "{{ admin_password }}" + realm: "{{ realm }}" + client_id: "{{ client_name_public }}" + role_names: [] + register: result + +- name: Assert result + assert: + that: + - result is not changed + - result.end_state | length == 0
\ No newline at end of file diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/vars/main.yml new file mode 100644 index 000000000..8bd59398b --- /dev/null +++ b/ansible_collections/community/general/tests/integration/targets/keycloak_client_rolescope/vars/main.yml @@ -0,0 +1,26 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +url: http://localhost:8080/auth +admin_realm: master +admin_user: admin +admin_password: password +realm: myrealm + + +client_name_private: backend-client-private +client_role_admin: client-role-admin +client_role_user: client-role-user +client_role_not_exists: client-role-missing + +client_name_public: frontend-client-public + + +realm_role_admin: realm-role-admin +realm_role_user: realm-role-user +realm_role_not_exists: client-role-missing + + +client_attributes1: {"backchannel.logout.session.required": true, "backchannel.logout.revoke.offline.tokens": false, "client.secret.creation.time": 0} diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/test.yml b/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/test.yml index 217c020ca..8a88bca45 100644 --- a/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/test.yml +++ b/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/test.yml @@ -19,13 +19,13 @@ - item.0 == 'nl' - item.1 == 'Netherlands' vars: - - lmdb_kv_db: jp.mdb + lmdb_kv_db: jp.mdb with_community.general.lmdb_kv: - n* - assert: that: - item == 'Belgium' vars: - - lmdb_kv_db: jp.mdb + lmdb_kv_db: jp.mdb with_community.general.lmdb_kv: - be diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.18.txt b/ansible_collections/community/general/tests/sanity/ignore-2.18.txt new file mode 100644 index 000000000..d75aaeac2 --- /dev/null +++ b/ansible_collections/community/general/tests/sanity/ignore-2.18.txt @@ -0,0 +1,17 @@ +plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice +plugins/modules/homectl.py import-3.11 # Uses deprecated stdlib library 'crypt' +plugins/modules/homectl.py import-3.12 # Uses deprecated stdlib library 'crypt' +plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin +plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen +plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice +plugins/modules/parted.py validate-modules:parameter-state-invalid-choice +plugins/modules/rax_files_objects.py use-argspec-type-path # module deprecated - removed in 9.0.0 +plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice # module deprecated - removed in 9.0.0 +plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0 +plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice +plugins/modules/udm_user.py import-3.11 # Uses deprecated stdlib library 'crypt' +plugins/modules/udm_user.py import-3.12 # Uses deprecated stdlib library 'crypt' +plugins/modules/xfconf.py validate-modules:return-syntax-error +plugins/module_utils/univention_umc.py pylint:use-yield-from # suggested construct does not work with Python 2 +tests/unit/compat/mock.py pylint:use-yield-from # suggested construct does not work with Python 2 +tests/unit/plugins/modules/test_gio_mime.yaml no-smart-quotes diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.18.txt.license b/ansible_collections/community/general/tests/sanity/ignore-2.18.txt.license new file mode 100644 index 000000000..edff8c768 --- /dev/null +++ b/ansible_collections/community/general/tests/sanity/ignore-2.18.txt.license @@ -0,0 +1,3 @@ +GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +SPDX-License-Identifier: GPL-3.0-or-later +SPDX-FileCopyrightText: Ansible Project diff --git a/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py b/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py index 17932ed5f..4d7c2c9db 100644 --- a/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py +++ b/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py @@ -9,8 +9,8 @@ from ansible.executor.task_result import TaskResult from ansible_collections.community.general.tests.unit.compat import unittest from ansible_collections.community.general.tests.unit.compat.mock import patch, Mock from ansible_collections.community.general.plugins.callback.loganalytics import AzureLogAnalyticsSource -from datetime import datetime +from datetime import datetime import json import sys @@ -32,10 +32,10 @@ class TestAzureLogAnalytics(unittest.TestCase): if sys.version_info < (3, 2): self.assertRegex = self.assertRegexpMatches - @patch('ansible_collections.community.general.plugins.callback.loganalytics.datetime') + @patch('ansible_collections.community.general.plugins.callback.loganalytics.now') @patch('ansible_collections.community.general.plugins.callback.loganalytics.open_url') - def test_overall(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_overall(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.loganalytics.send_event(workspace_id='01234567-0123-0123-0123-01234567890a', @@ -52,10 +52,10 @@ class TestAzureLogAnalytics(unittest.TestCase): self.assertEqual(sent_data['event']['uuid'], 'myuuid') self.assertEqual(args[0], 'https://01234567-0123-0123-0123-01234567890a.ods.opinsights.azure.com/api/logs?api-version=2016-04-01') - @patch('ansible_collections.community.general.plugins.callback.loganalytics.datetime') + @patch('ansible_collections.community.general.plugins.callback.loganalytics.now') @patch('ansible_collections.community.general.plugins.callback.loganalytics.open_url') - def test_auth_headers(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_auth_headers(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.loganalytics.send_event(workspace_id='01234567-0123-0123-0123-01234567890a', diff --git a/ansible_collections/community/general/tests/unit/plugins/callback/test_splunk.py b/ansible_collections/community/general/tests/unit/plugins/callback/test_splunk.py index ddcdae24c..c09540fc0 100644 --- a/ansible_collections/community/general/tests/unit/plugins/callback/test_splunk.py +++ b/ansible_collections/community/general/tests/unit/plugins/callback/test_splunk.py @@ -27,10 +27,10 @@ class TestSplunkClient(unittest.TestCase): self.mock_host = Mock('MockHost') self.mock_host.name = 'myhost' - @patch('ansible_collections.community.general.plugins.callback.splunk.datetime') + @patch('ansible_collections.community.general.plugins.callback.splunk.now') @patch('ansible_collections.community.general.plugins.callback.splunk.open_url') - def test_timestamp_with_milliseconds(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_timestamp_with_milliseconds(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.splunk.send_event( @@ -45,10 +45,10 @@ class TestSplunkClient(unittest.TestCase): self.assertEqual(sent_data['event']['host'], 'my-host') self.assertEqual(sent_data['event']['ip_address'], '1.2.3.4') - @patch('ansible_collections.community.general.plugins.callback.splunk.datetime') + @patch('ansible_collections.community.general.plugins.callback.splunk.now') @patch('ansible_collections.community.general.plugins.callback.splunk.open_url') - def test_timestamp_without_milliseconds(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_timestamp_without_milliseconds(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.splunk.send_event( diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py b/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py index 9270dd44e..04cad8d6c 100644 --- a/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py +++ b/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py @@ -6,6 +6,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +import re from ansible_collections.community.general.tests.unit.compat import unittest from ansible_collections.community.general.tests.unit.compat.mock import patch @@ -13,8 +14,10 @@ from ansible.errors import AnsibleError from ansible.module_utils import six from ansible.plugins.loader import lookup_loader from ansible_collections.community.general.plugins.lookup.bitwarden import Bitwarden +from ansible.parsing.ajson import AnsibleJSONEncoder MOCK_COLLECTION_ID = "3b12a9da-7c49-40b8-ad33-aede017a7ead" +MOCK_ORGANIZATION_ID = "292ba0c6-f289-11ee-9301-ef7b639ccd2a" MOCK_RECORDS = [ { @@ -48,7 +51,7 @@ MOCK_RECORDS = [ "name": "a_test", "notes": None, "object": "item", - "organizationId": None, + "organizationId": MOCK_ORGANIZATION_ID, "passwordHistory": [ { "lastUsedDate": "2022-07-26T23:03:23.405Z", @@ -68,9 +71,7 @@ MOCK_RECORDS = [ "type": 1 }, { - "collectionIds": [ - MOCK_COLLECTION_ID - ], + "collectionIds": [], "deletedDate": None, "favorite": False, "folderId": None, @@ -106,10 +107,30 @@ MOCK_RECORDS = [ "name": "dupe_name", "notes": None, "object": "item", - "organizationId": None, + "organizationId": MOCK_ORGANIZATION_ID, "reprompt": 0, "revisionDate": "2022-07-27T03:42:46.673Z", "type": 1 + }, + { + "collectionIds": [], + "deletedDate": None, + "favorite": False, + "folderId": None, + "id": "2bf517be-fb13-11ee-be89-a345aa369a94", + "login": { + "password": "e", + "passwordRevisionDate": None, + "totp": None, + "username": "f" + }, + "name": "non_collection_org_record", + "notes": None, + "object": "item", + "organizationId": MOCK_ORGANIZATION_ID, + "reprompt": 0, + "revisionDate": "2024-14-15T11:30:00.000Z", + "type": 1 } ] @@ -118,11 +139,41 @@ class MockBitwarden(Bitwarden): unlocked = True - def _get_matches(self, search_value=None, search_field="name", collection_id=None): - if not search_value and collection_id: - return list(filter(lambda record: collection_id in record['collectionIds'], MOCK_RECORDS)) + def _run(self, args, stdin=None, expected_rc=0): + if args[0] == 'get': + if args[1] == 'item': + for item in MOCK_RECORDS: + if item.get('id') == args[2]: + return AnsibleJSONEncoder().encode(item), '' + if args[0] == 'list': + if args[1] == 'items': + try: + search_value = args[args.index('--search') + 1] + except ValueError: + search_value = None + + try: + collection_to_filter = args[args.index('--collectionid') + 1] + except ValueError: + collection_to_filter = None + + try: + organization_to_filter = args[args.index('--organizationid') + 1] + except ValueError: + organization_to_filter = None + + items = [] + for item in MOCK_RECORDS: + if search_value and not re.search(search_value, item.get('name')): + continue + if collection_to_filter and collection_to_filter not in item.get('collectionIds', []): + continue + if organization_to_filter and item.get('organizationId') != organization_to_filter: + continue + items.append(item) + return AnsibleJSONEncoder().encode(items), '' - return list(filter(lambda record: record[search_field] == search_value, MOCK_RECORDS)) + return '[]', '' class LoggedOutMockBitwarden(MockBitwarden): @@ -194,4 +245,19 @@ class TestLookupModule(unittest.TestCase): @patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden()) def test_bitwarden_plugin_full_collection(self): # Try to retrieve the full records of the given collection. - self.assertEqual(MOCK_RECORDS, self.lookup.run(None, collection_id=MOCK_COLLECTION_ID)[0]) + self.assertEqual([MOCK_RECORDS[0], MOCK_RECORDS[2]], self.lookup.run(None, collection_id=MOCK_COLLECTION_ID)[0]) + + @patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden()) + def test_bitwarden_plugin_full_organization(self): + self.assertEqual([MOCK_RECORDS[0], MOCK_RECORDS[2], MOCK_RECORDS[3]], + self.lookup.run(None, organization_id=MOCK_ORGANIZATION_ID)[0]) + + @patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden()) + def test_bitwarden_plugin_filter_organization(self): + self.assertEqual([MOCK_RECORDS[2]], + self.lookup.run(['dupe_name'], organization_id=MOCK_ORGANIZATION_ID)[0]) + + @patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden()) + def test_bitwarden_plugin_full_collection_organization(self): + self.assertEqual([MOCK_RECORDS[0], MOCK_RECORDS[2]], self.lookup.run(None, + collection_id=MOCK_COLLECTION_ID, organization_id=MOCK_ORGANIZATION_ID)[0]) |