More prep for ansible-test relocation. (#60114)
* Update pytest plugins. * Fix update-bundled sanity test. * Remove old validate-modules comment. * Fix ansible-test plugin loading * Update code coverage comments. * Fix Makefile ansible-test reference. * Remove incorrect path from lint output. * Update ansible-test unit tests. * Make ansible-test's own unit tests singular.
This commit is contained in:
parent
ac5228390c
commit
fa2adf3b7b
11 changed files with 45 additions and 35 deletions
|
@ -1,9 +1,9 @@
|
||||||
.PHONY: all sanity units
|
all: sanity unit
|
||||||
|
|
||||||
all: sanity units
|
|
||||||
|
|
||||||
|
.PHONY: sanity
|
||||||
sanity:
|
sanity:
|
||||||
./ansible-test sanity test/runner/ ${TEST_FLAGS}
|
ansible-test sanity test/runner/ ${FLAGS}
|
||||||
|
|
||||||
units:
|
.PHONY: unit
|
||||||
PYTHONPATH=. pytest units ${TEST_FLAGS}
|
unit:
|
||||||
|
PYTHONPATH=.:.. pytest unit ${FLAGS}
|
||||||
|
|
|
@ -285,7 +285,7 @@ class TestFailure(TestResult):
|
||||||
if self.summary:
|
if self.summary:
|
||||||
command = self.format_command()
|
command = self.format_command()
|
||||||
message = 'The test `%s` failed. See stderr output for details.' % command
|
message = 'The test `%s` failed. See stderr output for details.' % command
|
||||||
path = 'test/runner/ansible-test'
|
path = ''
|
||||||
message = TestMessage(message, path)
|
message = TestMessage(message, path)
|
||||||
print(message)
|
print(message)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -812,10 +812,11 @@ def import_plugins(directory, root=None): # type: (str, t.Optional[str]) -> Non
|
||||||
root = os.path.dirname(__file__)
|
root = os.path.dirname(__file__)
|
||||||
|
|
||||||
path = os.path.join(root, directory)
|
path = os.path.join(root, directory)
|
||||||
prefix = 'lib.%s.' % directory.replace(os.sep, '.')
|
package = __name__.rsplit('.', 1)[0]
|
||||||
|
prefix = '%s.%s.' % (package, directory.replace(os.sep, '.'))
|
||||||
|
|
||||||
for (_module_loader, name, _ispkg) in pkgutil.iter_modules([path], prefix=prefix):
|
for (_module_loader, name, _ispkg) in pkgutil.iter_modules([path], prefix=prefix):
|
||||||
module_path = os.path.join(root, name[4:].replace('.', os.sep) + '.py')
|
module_path = os.path.join(root, name[len(package) + 1:].replace('.', os.sep) + '.py')
|
||||||
load_module(module_path, name)
|
load_module(module_path, name)
|
||||||
|
|
||||||
|
|
||||||
|
@ -824,7 +825,7 @@ def load_plugins(base_type, database): # type: (t.Type[C], t.Dict[str, t.Type[C
|
||||||
Load plugins of the specified type and track them in the specified database.
|
Load plugins of the specified type and track them in the specified database.
|
||||||
Only plugins which have already been imported will be loaded.
|
Only plugins which have already been imported will be loaded.
|
||||||
"""
|
"""
|
||||||
plugins = dict((sc.__module__.split('.')[2], sc) for sc in get_subclasses(base_type)) # type: t.Dict[str, t.Type[C]]
|
plugins = dict((sc.__module__.rsplit('.', 1)[1], sc) for sc in get_subclasses(base_type)) # type: t.Dict[str, t.Type[C]]
|
||||||
|
|
||||||
for plugin in plugins:
|
for plugin in plugins:
|
||||||
database[plugin] = plugins[plugin]
|
database[plugin] = plugins[plugin]
|
||||||
|
@ -832,6 +833,9 @@ def load_plugins(base_type, database): # type: (t.Type[C], t.Dict[str, t.Type[C
|
||||||
|
|
||||||
def load_module(path, name): # type: (str, str) -> None
|
def load_module(path, name): # type: (str, str) -> None
|
||||||
"""Load a Python module using the given name and path."""
|
"""Load a Python module using the given name and path."""
|
||||||
|
if name in sys.modules:
|
||||||
|
return
|
||||||
|
|
||||||
if sys.version_info >= (3, 4):
|
if sys.version_info >= (3, 4):
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|
|
@ -169,8 +169,8 @@ def get_coverage_environment(args, target_name, version, temp_path, module_cover
|
||||||
coverage_file = ''
|
coverage_file = ''
|
||||||
|
|
||||||
# Enable code coverage collection on local Python programs (this does not include Ansible modules).
|
# Enable code coverage collection on local Python programs (this does not include Ansible modules).
|
||||||
# Used by the injectors in test/runner/injector/ to support code coverage.
|
# Used by the injectors to support code coverage.
|
||||||
# Used by unit tests in test/units/conftest.py to support code coverage.
|
# Used by the pytest unit test plugin to support code coverage.
|
||||||
# The COVERAGE_FILE variable is also used directly by the 'coverage' module.
|
# The COVERAGE_FILE variable is also used directly by the 'coverage' module.
|
||||||
env = dict(
|
env = dict(
|
||||||
COVERAGE_CONF=config_file,
|
COVERAGE_CONF=config_file,
|
||||||
|
|
|
@ -6,6 +6,11 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from lib.util import (
|
||||||
|
to_text,
|
||||||
|
to_bytes,
|
||||||
|
)
|
||||||
|
|
||||||
from lib.diff import (
|
from lib.diff import (
|
||||||
parse_diff,
|
parse_diff,
|
||||||
FileDiff,
|
FileDiff,
|
||||||
|
@ -19,18 +24,18 @@ def get_diff(base, head=None):
|
||||||
:rtype: list[str]
|
:rtype: list[str]
|
||||||
"""
|
"""
|
||||||
if not head or head == 'HEAD':
|
if not head or head == 'HEAD':
|
||||||
head = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()
|
head = to_text(subprocess.check_output(['git', 'rev-parse', 'HEAD'])).strip()
|
||||||
|
|
||||||
cache = '/tmp/git-diff-cache-%s-%s.log' % (base, head)
|
cache = '/tmp/git-diff-cache-%s-%s.log' % (base, head)
|
||||||
|
|
||||||
if os.path.exists(cache):
|
if os.path.exists(cache):
|
||||||
with open(cache, 'r') as cache_fd:
|
with open(cache, 'rb') as cache_fd:
|
||||||
lines = cache_fd.read().splitlines()
|
lines = to_text(cache_fd.read()).splitlines()
|
||||||
else:
|
else:
|
||||||
lines = subprocess.check_output(['git', 'diff', base, head]).splitlines()
|
lines = to_text(subprocess.check_output(['git', 'diff', base, head]), errors='replace').splitlines()
|
||||||
|
|
||||||
with open(cache, 'w') as cache_fd:
|
with open(cache, 'wb') as cache_fd:
|
||||||
cache_fd.write('\n'.join(lines))
|
cache_fd.write(to_bytes('\n'.join(lines)))
|
||||||
|
|
||||||
assert lines
|
assert lines
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"all_targets": true,
|
"all_targets": true,
|
||||||
"extensions": [
|
"ignore_self": true,
|
||||||
".py"
|
"extensions": [
|
||||||
],
|
".py"
|
||||||
"output": "path-message"
|
],
|
||||||
|
"output": "path-message"
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,9 +70,6 @@ def get_files_with_bundled_metadata(paths):
|
||||||
|
|
||||||
with_metadata = set()
|
with_metadata = set()
|
||||||
for path in paths:
|
for path in paths:
|
||||||
if path == 'test/sanity/code-smell/update-bundled.py':
|
|
||||||
continue
|
|
||||||
|
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
body = f.read()
|
body = f.read()
|
||||||
|
|
||||||
|
|
|
@ -7914,8 +7914,6 @@ test/units/plugins/shell/test_cmd.py metaclass-boilerplate
|
||||||
test/units/plugins/shell/test_powershell.py future-import-boilerplate
|
test/units/plugins/shell/test_powershell.py future-import-boilerplate
|
||||||
test/units/plugins/shell/test_powershell.py metaclass-boilerplate
|
test/units/plugins/shell/test_powershell.py metaclass-boilerplate
|
||||||
test/units/plugins/test_plugins.py pylint:blacklisted-name
|
test/units/plugins/test_plugins.py pylint:blacklisted-name
|
||||||
test/units/pytest/plugins/ansible_pytest_collections.py metaclass-boilerplate
|
|
||||||
test/units/pytest/plugins/ansible_pytest_coverage.py metaclass-boilerplate
|
|
||||||
test/units/template/test_templar.py pylint:blacklisted-name
|
test/units/template/test_templar.py pylint:blacklisted-name
|
||||||
test/units/test_constants.py future-import-boilerplate
|
test/units/test_constants.py future-import-boilerplate
|
||||||
test/units/test_context.py future-import-boilerplate
|
test/units/test_context.py future-import-boilerplate
|
||||||
|
|
|
@ -38,8 +38,6 @@ class AnsibleTextIOWrapper(TextIOWrapper):
|
||||||
|
|
||||||
def find_executable(executable, cwd=None, path=None):
|
def find_executable(executable, cwd=None, path=None):
|
||||||
"""Finds the full path to the executable specified"""
|
"""Finds the full path to the executable specified"""
|
||||||
# This is mostly a copy from test/runner/lib/util.py. Should be removed once validate-modules has been integrated
|
|
||||||
# into ansible-test
|
|
||||||
match = None
|
match = None
|
||||||
real_cwd = os.getcwd()
|
real_cwd = os.getcwd()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Enable unit testing of Ansible collections."""
|
"""Enable unit testing of Ansible collections."""
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -10,6 +10,7 @@ ANSIBLE_COLLECTIONS_PATH = os.path.join(os.environ['ANSIBLE_COLLECTIONS_PATHS'],
|
||||||
|
|
||||||
|
|
||||||
def collection_pypkgpath(self):
|
def collection_pypkgpath(self):
|
||||||
|
"""Configure the Python package path so that pytest can find our collections."""
|
||||||
for parent in self.parts(reverse=True):
|
for parent in self.parts(reverse=True):
|
||||||
if str(parent) == ANSIBLE_COLLECTIONS_PATH:
|
if str(parent) == ANSIBLE_COLLECTIONS_PATH:
|
||||||
return parent
|
return parent
|
||||||
|
@ -18,13 +19,16 @@ def collection_pypkgpath(self):
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure():
|
def pytest_configure():
|
||||||
|
"""Configure this pytest plugin."""
|
||||||
from ansible.utils.collection_loader import AnsibleCollectionLoader
|
from ansible.utils.collection_loader import AnsibleCollectionLoader
|
||||||
|
|
||||||
# allow unit tests to import code from collections
|
# allow unit tests to import code from collections
|
||||||
sys.meta_path.insert(0, AnsibleCollectionLoader())
|
sys.meta_path.insert(0, AnsibleCollectionLoader())
|
||||||
|
|
||||||
|
# noinspection PyProtectedMember
|
||||||
import py._path.local
|
import py._path.local
|
||||||
|
|
||||||
# force collections unit tests to be loaded with the ansible_collections namespace
|
# force collections unit tests to be loaded with the ansible_collections namespace
|
||||||
# original idea from https://stackoverflow.com/questions/50174130/how-do-i-pytest-a-project-using-pep-420-namespace-packages/50175552#50175552
|
# original idea from https://stackoverflow.com/questions/50174130/how-do-i-pytest-a-project-using-pep-420-namespace-packages/50175552#50175552
|
||||||
py._path.local.LocalPath.pypkgpath = collection_pypkgpath
|
# noinspection PyProtectedMember
|
||||||
|
py._path.local.LocalPath.pypkgpath = collection_pypkgpath # pylint: disable=protected-access
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
"""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`."""
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure():
|
def pytest_configure():
|
||||||
|
"""Configure this pytest plugin."""
|
||||||
try:
|
try:
|
||||||
import coverage
|
import coverage
|
||||||
except ImportError:
|
except ImportError:
|
||||||
coverage = None
|
coverage = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
test = coverage.Coverage
|
coverage.Coverage
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
coverage = None
|
coverage = None
|
||||||
|
|
||||||
|
@ -41,7 +43,8 @@ def pytest_configure():
|
||||||
else:
|
else:
|
||||||
cov = None
|
cov = None
|
||||||
|
|
||||||
os_exit = os._exit
|
# noinspection PyProtectedMember
|
||||||
|
os_exit = os._exit # pylint: disable=protected-access
|
||||||
|
|
||||||
def coverage_exit(*args, **kwargs):
|
def coverage_exit(*args, **kwargs):
|
||||||
for instance in coverage_instances:
|
for instance in coverage_instances:
|
||||||
|
@ -50,7 +53,7 @@ def pytest_configure():
|
||||||
|
|
||||||
os_exit(*args, **kwargs)
|
os_exit(*args, **kwargs)
|
||||||
|
|
||||||
os._exit = coverage_exit
|
os._exit = coverage_exit # pylint: disable=protected-access
|
||||||
|
|
||||||
if cov:
|
if cov:
|
||||||
cov.start()
|
cov.start()
|
||||||
|
|
Loading…
Reference in a new issue