"""uses_*: Provides a set of fixtures used to mark tests for filtering on the command-line.
Tests using these fixtures directly or indirectly can be filtered using py.test's
``-k`` filter argument. For example, run tests that use the ssh client::
py.test -k uses_ssh
Additionally, tests using one of the fixtures listed in :py:attr:`appliance_marks` will be marked
with `is_appliance`, for easily filtering out appliance tests, e.g::
py.test -k 'not is_appliance'
All fixtures created by this module will have the ``uses_`` prefix.
Note:
``is_appliance`` is a mark that will be dynamically set based on fixtures used,
but is not a fixture itself.
"""
import pytest
# List of fixture marks to create and use for test marking
# these are exposed as globals and individually documented
_marks_to_make = [
'uses_db',
'uses_event_listener',
'uses_providers',
'uses_pxe',
'uses_ssh',
'uses_blockers',
]
#: List of fixtures that, when used, indicate an appliance is being tested
#: by applying the ``is_appliance`` mark.
appliance_marks = {
'uses_db',
'uses_ssh'
}
##
# Create the fixtures that will trigger test marking
##
markdoc = "Fixture which marks a test with the ``{}`` mark"
for mark in _marks_to_make:
def _markfunc():
return None
# Put on a nice docstring...
_markfunc.__doc__ = markdoc.format(mark)
globals()[mark] = pytest.fixture(scope="session")(_markfunc)
###
# Add fixtures with dependencies here
###
@pytest.fixture(scope="session")
[docs]def uses_cloud_providers(uses_providers):
"""Fixture which marks a test with the ``uses_cloud_providers`` and ``uses_providers`` marks"""
pass
@pytest.fixture(scope="session")
[docs]def uses_infra_providers(uses_providers):
"""Fixture which marks a test with the ``uses_infra_providers`` and ``uses_providers`` marks"""
pass
###
# Now hook the item collector to apply all the correct marks
###
[docs]def pytest_itemcollected(item):
"""pytest hook that actually does the marking
See: http://pytest.org/latest/plugins.html#_pytest.hookspec.pytest_collection_modifyitems
"""
try:
# Intersect 'uses_' fixture set with the fixtures being used by a test
mark_fixtures = _uses_fixturenames().intersection(set(item.fixturenames))
except AttributeError:
# Test doesn't have fixturenames, make no changes
return
for mark in mark_fixtures:
_add_mark(item, mark)
# Slap on the is_appliance mark if there's a match
if appliance_marks.intersection(mark_fixtures):
_add_mark(item, 'is_appliance')
###
# Helpers
###
# DRY
def _add_mark(item, mark):
# Add the mark directly to the item so test introspection is sane
item.add_marker(mark)
# Add the mark to extra_keyword_matches so the builtin item collector
# is able to filter based on this mark
item.extra_keyword_matches.add(mark)
def _uses_fixturenames():
# A set of all the names defined in this module named 'uses_*'
# These should all be fixtures.
return {mark for mark in globals().keys() if mark.startswith('uses_')}