From 77c2139f7ebc2ceb76c76f69a883cb85d725c674 Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Wed, 11 Sep 2019 14:40:59 -0700 Subject: [PATCH] [stable-2.9] Fix ansible-test pytest plugin loading. (#62119) (#62120) * [stable-2.9] Fix ansible-test pytest plugin loading. (#62119) * Avoid assertion rewriting in pytest plugins. Adding PYTEST_DONT_REWRITE to the ansible-test pytest plugin docstrings disables assertion rewriting in pytest for those plugins. This avoids warnings during test execution if the plugins are loaded multiple times (such as being imported within tests). * Run ansible-test pytest plugins early. The ansible-test pytest plugins need to load and run earlier than conftest modules. To facilitate this, the pytest_configure function is run during loading, which works since they are loaded (but not always run) before conftest modules are loaded. A check has also been added to the pytest_configure functions to prevent them from running multiple times in the same process. * Load pytest plugins using an env var. The -p command line option loads plugins before conftest, but only during collection. The PYTEST_PLUGINS environment variable loads plugins before confest, both during collection and test execution. (cherry picked from commit aaa6d2e) Co-authored-by: Matt Clay * Add missing changelog entry for ansible-test fix. PR https://github.com/ansible/ansible/pull/62119 was missing a changelog entry. (cherry picked from commit 6c78f02121b1742e63d2b2d66a98a4c760f706ad) --- .../fragments/ansible-test-pytest-plugin-loading.yml | 2 ++ .../pytest/plugins/ansible_pytest_collections.py | 11 ++++++++++- .../_data/pytest/plugins/ansible_pytest_coverage.py | 11 ++++++++++- test/lib/ansible_test/_internal/units/__init__.py | 4 +--- 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/ansible-test-pytest-plugin-loading.yml diff --git a/changelogs/fragments/ansible-test-pytest-plugin-loading.yml b/changelogs/fragments/ansible-test-pytest-plugin-loading.yml new file mode 100644 index 00000000000..2a052a7ff16 --- /dev/null +++ b/changelogs/fragments/ansible-test-pytest-plugin-loading.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible-test now loads the collection loader plugin early enough for ansible_collections imports to work in unit test conftest.py modules diff --git a/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_collections.py b/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_collections.py index ae87187b835..91e20478786 100644 --- a/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_collections.py +++ b/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_collections.py @@ -1,4 +1,4 @@ -"""Enable unit testing of Ansible collections.""" +"""Enable unit testing of Ansible collections. PYTEST_DONT_REWRITE""" from __future__ import (absolute_import, division, print_function) __metaclass__ = type @@ -20,6 +20,12 @@ def collection_pypkgpath(self): def pytest_configure(): """Configure this pytest plugin.""" + try: + if pytest_configure.executed: + return + except AttributeError: + pytest_configure.executed = True + from ansible.utils.collection_loader import AnsibleCollectionLoader # allow unit tests to import code from collections @@ -32,3 +38,6 @@ def pytest_configure(): # original idea from https://stackoverflow.com/questions/50174130/how-do-i-pytest-a-project-using-pep-420-namespace-packages/50175552#50175552 # noinspection PyProtectedMember py._path.local.LocalPath.pypkgpath = collection_pypkgpath # pylint: disable=protected-access + + +pytest_configure() diff --git a/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_coverage.py b/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_coverage.py index 344a091e1c5..b05298ab0b3 100644 --- a/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_coverage.py +++ b/test/lib/ansible_test/_data/pytest/plugins/ansible_pytest_coverage.py @@ -1,10 +1,16 @@ -"""Monkey patch os._exit when running under coverage so we don't lose coverage data in forks, such as with `pytest --boxed`.""" +"""Monkey patch os._exit when running under coverage so we don't lose coverage data in forks, such as with `pytest --boxed`. PYTEST_DONT_REWRITE""" from __future__ import (absolute_import, division, print_function) __metaclass__ = type def pytest_configure(): """Configure this pytest plugin.""" + try: + if pytest_configure.executed: + return + except AttributeError: + pytest_configure.executed = True + try: import coverage except ImportError: @@ -57,3 +63,6 @@ def pytest_configure(): if cov: cov.start() + + +pytest_configure() diff --git a/test/lib/ansible_test/_internal/units/__init__.py b/test/lib/ansible_test/_internal/units/__init__.py index 15655c4c1d3..22145431117 100644 --- a/test/lib/ansible_test/_internal/units/__init__.py +++ b/test/lib/ansible_test/_internal/units/__init__.py @@ -122,9 +122,7 @@ def command_units(args): if plugins: env['PYTHONPATH'] += ':%s' % os.path.join(ANSIBLE_TEST_DATA_ROOT, 'pytest/plugins') - - for plugin in plugins: - cmd.extend(['-p', plugin]) + env['PYTEST_PLUGINS'] = ','.join(plugins) if args.collect_only: cmd.append('--collect-only')