Imported Upstream version 4.3.1
This commit is contained in:
0
ipatests/pytest_plugins/__init__.py
Normal file
0
ipatests/pytest_plugins/__init__.py
Normal file
57
ipatests/pytest_plugins/beakerlib.py
Normal file
57
ipatests/pytest_plugins/beakerlib.py
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/python2
|
||||
# Copyright (C) 2014 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""Test integration with BeakerLib
|
||||
|
||||
IPA-specific configuration for the BeakerLib plugin (from pytest-beakerlib).
|
||||
If the plugin is active, sets up IPA logging to also log to Beaker.
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from ipapython.ipa_log_manager import log_mgr
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
plugin = config.pluginmanager.getplugin('BeakerLibPlugin')
|
||||
if plugin:
|
||||
handler = BeakerLibLogHandler(plugin.run_beakerlib_command)
|
||||
log_mgr.configure(
|
||||
{
|
||||
'default_level': 'DEBUG',
|
||||
'handlers': [{'log_handler': handler,
|
||||
'format': '[%(name)s] %(message)s',
|
||||
'level': 'info'}]},
|
||||
configure_state='beakerlib_plugin')
|
||||
|
||||
|
||||
class BeakerLibLogHandler(logging.Handler):
|
||||
def __init__(self, beakerlib_command):
|
||||
super(BeakerLibLogHandler, self).__init__()
|
||||
self.beakerlib_command = beakerlib_command
|
||||
|
||||
def emit(self, record):
|
||||
command = {
|
||||
'DEBUG': 'rlLogDebug',
|
||||
'INFO': 'rlLogInfo',
|
||||
'WARNING': 'rlLogWarning',
|
||||
'ERROR': 'rlLogError',
|
||||
'CRITICAL': 'rlLogFatal',
|
||||
}.get(record.levelname, 'rlLog')
|
||||
self.beakerlib_command([command, self.format(record)])
|
||||
47
ipatests/pytest_plugins/declarative.py
Normal file
47
ipatests/pytest_plugins/declarative.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# Authors:
|
||||
# Petr Viktorin <pviktori@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Pytest plugin for Declarative tests"""
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
"""Generates Declarative tests"""
|
||||
if 'declarative_test_definition' in metafunc.fixturenames:
|
||||
name = metafunc.cls.__name__
|
||||
tests = []
|
||||
descriptions = []
|
||||
for i, test in enumerate(metafunc.cls.tests):
|
||||
if callable(test):
|
||||
description = '%s: %s' % (
|
||||
str(i).zfill(4),
|
||||
test.__name__, # test is not a dict. pylint: disable=E1103
|
||||
)
|
||||
else:
|
||||
description = '%s: %s: %s' % (str(i).zfill(4),
|
||||
test['command'][0],
|
||||
test.get('desc', ''))
|
||||
test = dict(test)
|
||||
test['nice'] = description
|
||||
tests.append(test)
|
||||
descriptions.append(description)
|
||||
metafunc.parametrize(
|
||||
['index', 'declarative_test_definition'],
|
||||
enumerate(tests),
|
||||
ids=descriptions,
|
||||
)
|
||||
237
ipatests/pytest_plugins/integration.py
Normal file
237
ipatests/pytest_plugins/integration.py
Normal file
@@ -0,0 +1,237 @@
|
||||
# Authors:
|
||||
# Petr Viktorin <pviktori@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2011 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Pytest plugin for IPA Integration tests"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
from pytest_multihost import make_multihost_fixture
|
||||
|
||||
from ipapython import ipautil
|
||||
from ipapython.ipa_log_manager import log_mgr
|
||||
from ipatests.test_integration import tasks
|
||||
from ipatests.test_integration.config import Config
|
||||
from ipatests.test_integration.env_config import get_global_config
|
||||
|
||||
|
||||
log = log_mgr.get_logger(__name__)
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup("IPA integration tests")
|
||||
|
||||
group.addoption(
|
||||
'--logfile-dir', dest="logfile_dir", default=None,
|
||||
help="Directory to store integration test logs in.")
|
||||
|
||||
|
||||
def collect_test_logs(node, logs_dict, test_config):
|
||||
"""Collect logs from a test
|
||||
|
||||
Calls collect_logs
|
||||
|
||||
:param node: The pytest collection node (request.node)
|
||||
:param logs_dict: Mapping of host to list of log filnames to collect
|
||||
:param test_config: Pytest configuration
|
||||
"""
|
||||
collect_logs(
|
||||
name=node.nodeid.replace('/', '-').replace('::', '-'),
|
||||
logs_dict=logs_dict,
|
||||
logfile_dir=test_config.getoption('logfile_dir'),
|
||||
beakerlib_plugin=test_config.pluginmanager.getplugin('BeakerLibPlugin'),
|
||||
)
|
||||
|
||||
|
||||
def collect_logs(name, logs_dict, logfile_dir=None, beakerlib_plugin=None):
|
||||
"""Collect logs from remote hosts
|
||||
|
||||
Calls collect_logs
|
||||
|
||||
:param name: Name under which logs arecollected, e.g. name of the test
|
||||
:param logs_dict: Mapping of host to list of log filnames to collect
|
||||
:param logfile_dir: Directory to log to
|
||||
:param beakerlib_plugin:
|
||||
BeakerLibProcess or BeakerLibPlugin used to collect tests for BeakerLib
|
||||
|
||||
If neither logfile_dir nor beakerlib_plugin is given, no tests are
|
||||
collected.
|
||||
"""
|
||||
if logs_dict and (logfile_dir or beakerlib_plugin):
|
||||
|
||||
if logfile_dir:
|
||||
remove_dir = False
|
||||
else:
|
||||
logfile_dir = tempfile.mkdtemp()
|
||||
remove_dir = True
|
||||
|
||||
topdirname = os.path.join(logfile_dir, name)
|
||||
|
||||
for host, logs in logs_dict.items():
|
||||
log.info('Collecting logs from: %s', host.hostname)
|
||||
|
||||
# Tar up the logs on the remote server
|
||||
cmd = host.run_command(['tar', 'cJv'] + logs, log_stdout=False,
|
||||
raiseonerr=False)
|
||||
if cmd.returncode:
|
||||
log.warn('Could not collect all requested logs')
|
||||
|
||||
# Unpack on the local side
|
||||
dirname = os.path.join(topdirname, host.hostname)
|
||||
try:
|
||||
os.makedirs(dirname)
|
||||
except OSError:
|
||||
pass
|
||||
tarname = os.path.join(dirname, 'logs.tar.xz')
|
||||
with open(tarname, 'w') as f:
|
||||
f.write(cmd.stdout_text)
|
||||
ipautil.run(['tar', 'xJvf', 'logs.tar.xz'], cwd=dirname,
|
||||
raiseonerr=False)
|
||||
os.unlink(tarname)
|
||||
|
||||
if beakerlib_plugin:
|
||||
# Use BeakerLib's rlFileSubmit on the indifidual files
|
||||
# The resulting submitted filename will be
|
||||
# $HOSTNAME-$FILENAME (with '/' replaced by '-')
|
||||
beakerlib_plugin.run_beakerlib_command(['pushd', topdirname])
|
||||
try:
|
||||
for dirpath, dirnames, filenames in os.walk(topdirname):
|
||||
for filename in filenames:
|
||||
fullname = os.path.relpath(
|
||||
os.path.join(dirpath, filename), topdirname)
|
||||
log.debug('Submitting file: %s', fullname)
|
||||
beakerlib_plugin.run_beakerlib_command(
|
||||
['rlFileSubmit', fullname])
|
||||
finally:
|
||||
beakerlib_plugin.run_beakerlib_command(['popd'])
|
||||
|
||||
if remove_dir:
|
||||
if beakerlib_plugin:
|
||||
# The BeakerLib process runs asynchronously, let it clean up
|
||||
# after it's done with the directory
|
||||
beakerlib_plugin.run_beakerlib_command(
|
||||
['rm', '-rvf', topdirname])
|
||||
else:
|
||||
shutil.rmtree(topdirname)
|
||||
|
||||
logs_dict.clear()
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def class_integration_logs():
|
||||
"""Internal fixture providing class-level logs_dict"""
|
||||
return {}
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
def integration_logs(class_integration_logs, request):
|
||||
"""Provides access to test integration logs, and collects after each test
|
||||
"""
|
||||
yield class_integration_logs
|
||||
collect_test_logs(request.node, class_integration_logs, request.config)
|
||||
|
||||
|
||||
@pytest.yield_fixture(scope='class')
|
||||
def mh(request, class_integration_logs):
|
||||
"""IPA's multihost fixture object
|
||||
"""
|
||||
cls = request.cls
|
||||
|
||||
domain_description = {
|
||||
'type': 'IPA',
|
||||
'hosts': {
|
||||
'master': 1,
|
||||
'replica': cls.num_replicas,
|
||||
'client': cls.num_clients,
|
||||
},
|
||||
}
|
||||
domain_description['hosts'].update(
|
||||
{role: 1 for role in cls.required_extra_roles})
|
||||
|
||||
domain_descriptions = [domain_description]
|
||||
for i in range(cls.num_ad_domains):
|
||||
domain_descriptions.append({
|
||||
'type': 'AD',
|
||||
'hosts': {'ad': 1, 'ad_subdomain': 1},
|
||||
})
|
||||
|
||||
mh = make_multihost_fixture(
|
||||
request,
|
||||
domain_descriptions,
|
||||
config_class=Config,
|
||||
_config=get_global_config(),
|
||||
)
|
||||
|
||||
mh.domain = mh.config.domains[0]
|
||||
[mh.master] = mh.domain.hosts_by_role('master')
|
||||
mh.replicas = mh.domain.hosts_by_role('replica')
|
||||
mh.clients = mh.domain.hosts_by_role('client')
|
||||
|
||||
cls.logs_to_collect = class_integration_logs
|
||||
|
||||
def collect_log(host, filename):
|
||||
log.info('Adding %s:%s to list of logs to collect' %
|
||||
(host.external_hostname, filename))
|
||||
class_integration_logs.setdefault(host, []).append(filename)
|
||||
|
||||
print(mh.config)
|
||||
for host in mh.config.get_all_hosts():
|
||||
host.add_log_collector(collect_log)
|
||||
cls.log.info('Preparing host %s', host.hostname)
|
||||
tasks.prepare_host(host)
|
||||
|
||||
setup_class(cls, mh)
|
||||
mh._pytestmh_request.addfinalizer(lambda: teardown_class(cls))
|
||||
|
||||
yield mh.install()
|
||||
|
||||
for host in cls.get_all_hosts():
|
||||
host.remove_log_collector(collect_log)
|
||||
|
||||
collect_test_logs(request.node, class_integration_logs, request.config)
|
||||
|
||||
|
||||
def setup_class(cls, mh):
|
||||
"""Add convenience attributes to the test class
|
||||
|
||||
This is deprecated in favor of the mh fixture.
|
||||
To be removed when no more tests using this.
|
||||
"""
|
||||
cls.domain = mh.domain
|
||||
cls.master = mh.master
|
||||
cls.replicas = mh.replicas
|
||||
cls.clients = mh.clients
|
||||
cls.ad_domains = mh.config.ad_domains
|
||||
|
||||
|
||||
def teardown_class(cls):
|
||||
"""Remove convenience attributes from the test class
|
||||
|
||||
This is deprecated in favor of the mh fixture.
|
||||
To be removed when no more tests using this.
|
||||
"""
|
||||
del cls.master
|
||||
del cls.replicas
|
||||
del cls.clients
|
||||
del cls.ad_domains
|
||||
del cls.domain
|
||||
73
ipatests/pytest_plugins/nose_compat.py
Normal file
73
ipatests/pytest_plugins/nose_compat.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# Authors:
|
||||
# Petr Viktorin <pviktori@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Provides command-line options for very limited Nose compatibility"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from ipapython.ipa_log_manager import log_mgr
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup("IPA nosetests compatibility shim")
|
||||
|
||||
group.addoption('--with-xunit', action="store_const",
|
||||
dest="xmlpath", metavar="path", default=None,
|
||||
const=os.environ.get('IPATEST_XUNIT_PATH', './nosetests.xml'),
|
||||
help="create junit-xml style report file at $IPATEST_XUNIT_PATH,"
|
||||
"or nosetests.xml by default")
|
||||
|
||||
group.addoption('--logging-level', action="store",
|
||||
dest="logging_level", metavar="level", default='CRITICAL',
|
||||
help="level for logging to stderr. "
|
||||
"Bypasses pytest logging redirection."
|
||||
"May be used to show progress of long-running tests.")
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
if config.getoption('logging_level'):
|
||||
# Forward IPA logging to a normal Python logger. Nose's logcapture plugin
|
||||
# can't work with IPA-managed loggers
|
||||
class LogHandler(logging.Handler):
|
||||
name = 'forwarding log handler'
|
||||
logger = logging.getLogger('IPA')
|
||||
|
||||
def emit(self, record):
|
||||
capture = config.pluginmanager.getplugin('capturemanager')
|
||||
orig_stdout, orig_stderr = sys.stdout, sys.stderr
|
||||
if capture:
|
||||
capture._capturing.suspend_capturing()
|
||||
sys.stderr.write(self.format(record))
|
||||
sys.stderr.write('\n')
|
||||
if capture:
|
||||
capture._capturing.resume_capturing()
|
||||
sys.stdout, sys.stderr = orig_stdout, orig_stderr
|
||||
|
||||
log_mgr.configure(
|
||||
{
|
||||
'default_level': config.getoption('logging_level'),
|
||||
'handlers': [{'log_handler': LogHandler(),
|
||||
'format': '[%(name)s] %(message)s',
|
||||
'level': 'debug'},
|
||||
{'level': 'debug',
|
||||
'name': 'real_stderr',
|
||||
'stream': sys.stderr}]},
|
||||
configure_state='tests')
|
||||
Reference in New Issue
Block a user