Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split out module/module_utils unit test execution. #74337

Merged
merged 1 commit into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelogs/fragments/ansible-test-split-unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
breaking_changes:
- ansible-test - Unit tests for ``modules`` and ``module_utils`` are now limited to importing only ``ansible.module_utils`` from the ``ansible`` module.
minor_changes:
- ansible-test - Unit tests other than ``modules`` and ``module_utils`` are now run only on Python versions supported by the controller (Python 3.8+).
- ansible-test - Unit tests are now run in separate contexts (``controller``, ``modules``, ``module_utils``), each using separate invocations of ``pytest``.
23 changes: 23 additions & 0 deletions test/lib/ansible_test/_data/legacy_collection_loader/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# (c) 2019 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

# FIXME: decide what of this we want to actually be public/toplevel, put other stuff on a utility class?
from ._collection_config import AnsibleCollectionConfig
from ._collection_finder import AnsibleCollectionRef
from ansible.module_utils.common.text.converters import to_text


def resource_from_fqcr(ref):
"""
Return resource from a fully-qualified collection reference,
or from a simple resource name.
For fully-qualified collection references, this is equivalent to
``AnsibleCollectionRef.from_fqcr(ref).resource``.
:param ref: collection reference to parse
:return: the resource as a unicode string
"""
ref = to_text(ref, errors='strict')
return ref.split(u'.')[-1]
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# (c) 2019 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.six import with_metaclass


class _EventSource:
def __init__(self):
self._handlers = set()

def __iadd__(self, handler):
if not callable(handler):
raise ValueError('handler must be callable')
self._handlers.add(handler)
return self

def __isub__(self, handler):
try:
self._handlers.remove(handler)
except KeyError:
pass

return self

def _on_exception(self, handler, exc, *args, **kwargs):
# if we return True, we want the caller to re-raise
return True

def fire(self, *args, **kwargs):
for h in self._handlers:
try:
h(*args, **kwargs)
except Exception as ex:
if self._on_exception(h, ex, *args, **kwargs):
raise


class _AnsibleCollectionConfig(type):
def __init__(cls, meta, name, bases):
cls._collection_finder = None
cls._default_collection = None
cls._on_collection_load = _EventSource()

@property
def collection_finder(cls):
return cls._collection_finder

@collection_finder.setter
def collection_finder(cls, value):
if cls._collection_finder:
raise ValueError('an AnsibleCollectionFinder has already been configured')

cls._collection_finder = value

@property
def collection_paths(cls):
cls._require_finder()
return [to_text(p) for p in cls._collection_finder._n_collection_paths]

@property
def default_collection(cls):
return cls._default_collection

@default_collection.setter
def default_collection(cls, value):

cls._default_collection = value

@property
def on_collection_load(cls):
return cls._on_collection_load

@on_collection_load.setter
def on_collection_load(cls, value):
if value is not cls._on_collection_load:
raise ValueError('on_collection_load is not directly settable (use +=)')

@property
def playbook_paths(cls):
cls._require_finder()
return [to_text(p) for p in cls._collection_finder._n_playbook_paths]

@playbook_paths.setter
def playbook_paths(cls, value):
cls._require_finder()
cls._collection_finder.set_playbook_paths(value)

def _require_finder(cls):
if not cls._collection_finder:
raise NotImplementedError('an AnsibleCollectionFinder has not been installed in this process')


# concrete class of our metaclass type that defines the class properties we want
class AnsibleCollectionConfig(with_metaclass(_AnsibleCollectionConfig)):
pass