tests: change conftest.py to support dynamic markers and test selection

This applies correct markers to tests depending on their file path.
Tests that live at the root of tests/functional/tests will be given a
marker of 'all' and apply to any type of ceph node.

Tests that live in tests/functional/tests/mon will get the
'mons' marker and will only run for nodes in the 'mons' group.

Tests that live in tests/functional/tests/osd will get the 'osds'
marker and will only run for nodes in the 'osds' group.

All tests must use the CephNode fixture for this to work and be
parameterized by testinfra.

Signed-off-by: Andrew Schoen <aschoen@redhat.com>
pull/1150/head
Andrew Schoen 2016-12-03 08:07:09 -06:00
parent 870a4358f0
commit c02ffdb0e0
1 changed files with 19 additions and 96 deletions

View File

@ -1,101 +1,24 @@
import os
import pytest import pytest
import imp
def pytest_addoption(parser): @pytest.fixture()
default = 'scenario.py' def CephNode(Ansible, request):
parser.addoption( vars = Ansible.get_variables()
"--scenario", node_type = vars["group_names"][0]
action="store", if not request.node.get_marker(node_type):
default=default, pytest.skip("Not a valid test for node type")
help="YAML file defining scenarios to test. Currently defaults to: %s" % default
)
def load_scenario_config(filepath, **kw): def pytest_collection_modifyitems(session, config, items):
''' for item in items:
Creates a configuration dictionary from a file. test_path = item.location[0]
if "mon" in test_path:
:param filepath: The path to the file. item.add_marker(pytest.mark.mons)
''' elif "osd" in test_path:
item.add_marker(pytest.mark.osds)
abspath = os.path.abspath(os.path.expanduser(filepath)) elif "mds" in test_path:
conf_dict = {} item.add_marker(pytest.mark.mdss)
if not os.path.isfile(abspath): elif "rgw" in test_path:
raise RuntimeError('`%s` is not a file.' % abspath) item.add_marker(pytest.mark.rgws)
# First, make sure the code will actually compile (and has no SyntaxErrors)
with open(abspath, 'rb') as f:
compiled = compile(f.read(), abspath, 'exec')
# Next, attempt to actually import the file as a module.
# This provides more verbose import-related error reporting than exec()
absname, _ = os.path.splitext(abspath)
basepath, module_name = absname.rsplit(os.sep, 1)
imp.load_module(
module_name,
*imp.find_module(module_name, [basepath])
)
# If we were able to import as a module, actually exec the compiled code
exec(compiled, globals(), conf_dict)
conf_dict['__file__'] = abspath
return conf_dict
def pytest_configure_node(node):
node_id = node.slaveinput['slaveid']
scenario_path = os.path.abspath(node.config.getoption('--scenario'))
scenario = load_scenario_config(scenario_path)
node.slaveinput['node_config'] = scenario['nodes'][node_id]
node.slaveinput['scenario_config'] = scenario
@pytest.fixture(scope='session')
def node_config(request):
return request.config.slaveinput['node_config']
@pytest.fixture(scope="session")
def scenario_config(request):
return request.config.slaveinput['scenario_config']
def pytest_report_header(config):
"""
Hook to add extra information about the execution environment and to be
able to debug what did the magical args got expanded to
"""
lines = []
scenario_path = str(config.rootdir.join(config.getoption('--scenario')))
if not config.remote_execution:
lines.append('execution environment: local')
else: else:
lines.append('execution environment: remote') item.add_marker(pytest.mark.all)
lines.append('loaded scenario: %s' % scenario_path)
lines.append('expanded args: %s' % config.extended_args)
return lines
def pytest_cmdline_preparse(args, config):
# Note: we can only do our magical args expansion if we aren't already in
# a remote node via xdist/execnet so return quickly if we can't do magic.
# TODO: allow setting an environment variable that helps to skip this kind
# of magical argument expansion
if os.getcwd().endswith('pyexecnetcache'):
return
scenario_path = os.path.abspath(config.getoption('--scenario'))
scenarios = load_scenario_config(scenario_path, args=args)
rsync_dir = os.path.dirname(str(config.rootdir.join('functional')))
test_path = str(config.rootdir.join('functional/tests'))
nodes = []
config.remote_execution = True
for node in scenarios.get('nodes', []):
nodes.append('--tx')
nodes.append('vagrant_ssh={node_name}//id={node_name}'.format(node_name=node))
args[:] = args + ['--max-slave-restart', '0', '--dist=each'] + nodes + ['--rsyncdir', rsync_dir, test_path]
config.extended_args = ' '.join(args)