Skip to content

Commit

Permalink
Merge branch 'ansible-collections:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
ff05 authored Feb 5, 2025
2 parents 739193e + 0b4337c commit 06071fb
Show file tree
Hide file tree
Showing 23 changed files with 1,823 additions and 1,776 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- keycloak_client - fix and improve existing tests. The module showed a diff without actual changes, solved by improving the ``normalise_cr()`` function (https://github.com/ansible-collections/community.general/pull/9644).
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- cloudflare_dns - fix crash when deleting a DNS record or when updating a record with ``solo=true`` (https://github.com/ansible-collections/community.general/issues/9652, https://github.com/ansible-collections/community.general/pull/9649).
5 changes: 3 additions & 2 deletions plugins/modules/cloudflare_dns.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,18 +685,19 @@ def delete_dns_records(self, **kwargs):
else:
search_value = content

zone_id = self._get_zone_id(params['zone'])
records = self.get_dns_records(params['zone'], params['type'], search_record, search_value)

for rr in records:
if params['solo']:
if not ((rr['type'] == params['type']) and (rr['name'] == search_record) and (rr['content'] == content)):
self.changed = True
if not self.module.check_mode:
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(rr['zone_id'], rr['id']), 'DELETE')
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(zone_id, rr['id']), 'DELETE')
else:
self.changed = True
if not self.module.check_mode:
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(rr['zone_id'], rr['id']), 'DELETE')
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(zone_id, rr['id']), 'DELETE')
return self.changed

def ensure_dns_record(self, **kwargs):
Expand Down
10 changes: 10 additions & 0 deletions plugins/modules/keycloak_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,9 +758,19 @@ def normalise_cr(clientrep, remove_ids=False):
if remove_ids:
mapper.pop('id', None)

# Convert bool to string
if 'config' in mapper:
for key, value in mapper['config'].items():
if isinstance(value, bool):
mapper['config'][key] = str(value).lower()

# Set to a default value.
mapper['consentRequired'] = mapper.get('consentRequired', False)

if 'attributes' in clientrep:
for key, value in clientrep['attributes'].items():
if isinstance(value, bool):
clientrep['attributes'][key] = str(value).lower()
return clientrep


Expand Down
2 changes: 1 addition & 1 deletion plugins/modules/lvol.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
default: true
force:
description:
- Shrink or remove operations of volumes requires this switch. Ensures that that filesystems get never corrupted/destroyed
- Shrink or remove operations of volumes requires this switch. Ensures that filesystems never get corrupted/destroyed
by mistake.
type: bool
default: false
Expand Down
12 changes: 6 additions & 6 deletions tests/integration/targets/keycloak_client/vars/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ protocol_mappers1:
"claim.name": "email"
"user.attribute": "email"
"jsonType.label": "String"
"id.token.claim": "true"
"access.token.claim": "true"
"userinfo.token.claim": "true"
"id.token.claim": true
"access.token.claim": true
"userinfo.token.claim": true

- name: 'email_verified'
protocol: 'openid-connect'
Expand All @@ -45,9 +45,9 @@ protocol_mappers1:
"claim.name": "email_verified"
"user.attribute": "emailVerified"
"jsonType.label": "boolean"
"id.token.claim": "true"
"access.token.claim": "true"
"userinfo.token.claim": "true"
"id.token.claim": true
"access.token.claim": true
"userinfo.token.claim": true

- name: 'family_name'
protocol: 'openid-connect'
Expand Down
1 change: 1 addition & 0 deletions tests/integration/targets/snap/aliases
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ skip/freebsd
skip/osx
skip/macos
skip/docker
skip/rhel8.8 # TODO: fix
1 change: 1 addition & 0 deletions tests/integration/targets/snap_alias/aliases
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ skip/freebsd
skip/osx
skip/macos
skip/docker
skip/rhel8.8 # TODO: fix
84 changes: 39 additions & 45 deletions tests/unit/plugins/modules/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,57 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os
import sys
import json

import yaml
import pytest


from ansible.module_utils.common._collections_compat import Sequence


class Helper(object):
TEST_SPEC_VALID_SECTIONS = ["anchors", "test_cases"]

@staticmethod
def from_spec(test_module, ansible_module, test_spec, mocks=None):
helper = Helper(test_module, ansible_module, test_spec=test_spec, mocks=mocks)
def from_spec(ansible_module, test_module, test_spec, mocks=None):
helper = Helper(ansible_module, test_module, test_spec=test_spec, mocks=mocks)
return helper

@staticmethod
def from_file(test_module, ansible_module, filename, mocks=None):
with open(filename, "r") as test_cases:
test_spec = yaml.safe_load(test_cases)
return Helper.from_spec(test_module, ansible_module, test_spec, mocks)
def from_file(ansible_module, test_module, test_spec_filehandle, mocks=None):
test_spec = yaml.safe_load(test_spec_filehandle)
return Helper.from_spec(ansible_module, test_module, test_spec, mocks)

# @TODO: calculate the test_module_name automatically, remove one more parameter
@staticmethod
def from_module(ansible_module, test_module_name, test_spec=None, mocks=None):
def from_module(ansible_module, test_module_name, mocks=None):
test_module = sys.modules[test_module_name]
if test_spec is None:
test_spec = test_module.__file__.replace('.py', '.yaml')
return Helper.from_file(test_module, ansible_module, test_spec)
extensions = ['.yaml', '.yml']
for ext in extensions:
test_spec_filename = test_module.__file__.replace('.py', ext)
if os.path.exists(test_spec_filename):
with open(test_spec_filename, "r") as test_spec_filehandle:
return Helper.from_file(ansible_module, test_module, test_spec_filehandle, mocks=mocks)

raise Exception("Cannot find test case file for {0} with one of the extensions: {1}".format(test_module.__file__, extensions))

def add_func_to_test_module(self, name, func):
setattr(self.test_module, name, func)

def __init__(self, test_module, ansible_module, test_spec, mocks=None):
self.test_module = test_module
def __init__(self, ansible_module, test_module, test_spec, mocks=None):
self.ansible_module = ansible_module
self.test_module = test_module
self.test_cases = []
self.fixtures = {}
if isinstance(test_spec, Sequence):
test_cases = test_spec
else: # it is a dict
test_cases = test_spec['test_cases']
spec_diff = set(test_spec.keys()) - set(self.TEST_SPEC_VALID_SECTIONS)
if spec_diff:
raise ValueError("Test specification contain unknown keys: {0}".format(", ".join(spec_diff)))

spec_diff = set(test_spec.keys()) - set(self.TEST_SPEC_VALID_SECTIONS)
if spec_diff:
raise ValueError("Test specification contain unknown keys: {0}".format(", ".join(spec_diff)))

self.mocks_map = {m.name: m for m in mocks} if mocks else {}

for test_case in test_cases:
tc = ModuleTestCase.make_test_case(test_case, test_module, self.mocks_map)
for spec_test_case in test_spec['test_cases']:
tc = ModuleTestCase.make_test_case(spec_test_case, test_module, self.mocks_map)
self.test_cases.append(tc)
self.fixtures.update(tc.fixtures)
self.set_test_func()
Expand All @@ -72,7 +73,13 @@ def _test_module(mocker, capfd, patch_ansible_module, test_case):
"""
Run unit tests for each test case in self.test_cases
"""
patch_ansible_module(test_case.input)
args = {}
args.update(test_case.input)
if test_case.flags.get("check"):
args["_ansible_check_mode"] = test_case.flags.get("check")
if test_case.flags.get("diff"):
args["_ansible_diff"] = test_case.flags.get("diff")
patch_ansible_module(args)
self.runner.run(mocker, capfd, test_case)

self.add_func_to_test_module("test_module", _test_module)
Expand Down Expand Up @@ -145,26 +152,19 @@ def make_test_case(test_case_spec, test_module, mocks_map):
mocks=test_case_spec.get("mocks", {}),
flags=test_case_spec.get("flags", {})
)
tc.build_mocks(test_module, mocks_map)
tc.build_mocks(mocks_map)
return tc

def build_mocks(self, test_module, mocks_map):
def build_mocks(self, mocks_map):
for mock_name, mock_spec in self.mock_specs.items():
mock_class = mocks_map.get(mock_name, self.get_mock_class(test_module, mock_name))
try:
mock_class = mocks_map[mock_name]
except KeyError:
raise Exception("Cannot find TestCaseMock class for: {0}".format(mock_name))
self.mocks[mock_name] = mock_class.build_mock(mock_spec)

self._fixtures.update(self.mocks[mock_name].fixtures())

@staticmethod
def get_mock_class(test_module, mock):
try:
class_name = "".join(x.capitalize() for x in mock.split("_")) + "Mock"
plugin_class = getattr(test_module, class_name)
assert issubclass(plugin_class, TestCaseMock), "Class {0} is not a subclass of TestCaseMock".format(class_name)
return plugin_class
except AttributeError:
raise ValueError("Cannot find class {0} for mock {1}".format(class_name, mock))

@property
def fixtures(self):
return dict(self._fixtures)
Expand Down Expand Up @@ -200,10 +200,6 @@ def check_mocks(self, test_case, results):


class TestCaseMock:
@property
def name(self):
raise NotImplementedError()

@classmethod
def build_mock(cls, mock_specs):
return cls(mock_specs)
Expand All @@ -222,9 +218,7 @@ def check(self, test_case, results):


class RunCommandMock(TestCaseMock):
@property
def name(self):
return "run_command"
name = "run_command"

def __str__(self):
return "<RunCommandMock specs={specs}>".format(specs=self.mock_specs)
Expand Down
Loading

0 comments on commit 06071fb

Please sign in to comment.