Switch to stestr under the covers
This commit switches the ostestr command to use stestr under the covers. This simplifies the majority of the logic, eventually ostestr will be deprecated as a result of this migration. (since almost all the logic here is contained in stestr already) Depends-On: I2c7618a742439fd2ed26879f3114f0f66fd6337f Change-Id: Id7cb2a39a8308f1413608dcf19273a1d7f33592e
This commit is contained in:
parent
8ca44080d7
commit
7dd678e372
1
.gitignore
vendored
1
.gitignore
vendored
@ -27,6 +27,7 @@ cover/
|
||||
.tox
|
||||
nosetests.xml
|
||||
.testrepository
|
||||
.stestr
|
||||
.venv
|
||||
|
||||
# Translations
|
||||
|
3
.stestr.conf
Normal file
3
.stestr.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[DEFAULT]
|
||||
test_path=os_testr/tests
|
||||
top_dir=./
|
@ -1,7 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
||||
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
|
||||
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
@ -14,21 +14,21 @@
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import atexit
|
||||
import copy
|
||||
import io
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import warnings
|
||||
|
||||
import pbr.version
|
||||
import six.moves
|
||||
|
||||
from stestr import commands
|
||||
from subunit import run as subunit_run
|
||||
from testtools import run as testtools_run
|
||||
|
||||
from os_testr import regex_builder as rb
|
||||
from os_testr import testlist_builder as tlb
|
||||
|
||||
|
||||
__version__ = pbr.version.VersionInfo('os_testr').version_string()
|
||||
@ -107,92 +107,68 @@ def get_parser(args):
|
||||
|
||||
|
||||
def call_testr(regex, subunit, pretty, list_tests, slowest, parallel, concur,
|
||||
until_failure, color, list_of_tests=None, others=None):
|
||||
others = others or []
|
||||
if parallel:
|
||||
cmd = ['testr', 'run', '--parallel']
|
||||
if concur:
|
||||
cmd.append('--concurrency=%s' % concur)
|
||||
else:
|
||||
cmd = ['testr', 'run']
|
||||
until_failure, color, others=None, blacklist_file=None,
|
||||
whitelist_file=None, black_regex=None, load_list=None):
|
||||
# Handle missing .stestr.conf from users from before stestr migration
|
||||
test_dir = None
|
||||
top_dir = None
|
||||
group_regex = None
|
||||
if not os.path.isfile('.stestr.conf') and os.path.isfile('.testr.conf'):
|
||||
msg = ('No .stestr.conf file found in the CWD. Please create one to '
|
||||
'to replace the .testr.conf. You can find a script to do this '
|
||||
'in the stestr git repository.')
|
||||
warnings.warn(msg)
|
||||
|
||||
with open('.testr.conf', 'r') as testr_conf_file:
|
||||
config = six.moves.configparser.ConfigParser()
|
||||
config.readfp(testr_conf_file)
|
||||
test_command = config.get('DEFAULT', 'test_command')
|
||||
group_regex = None
|
||||
if config.has_option('DEFAULT', 'group_regex'):
|
||||
group_regex = config.get('DEFAULT', 'group_regex')
|
||||
|
||||
for line in test_command.split('\n'):
|
||||
if 'subunit.run discover' in line:
|
||||
command_parts = line.split(' ')
|
||||
top_dir_present = '-t' in line
|
||||
for idx, val in enumerate(command_parts):
|
||||
if top_dir_present:
|
||||
if val == '-t':
|
||||
top_dir = command_parts[idx + 1]
|
||||
test_dir = command_parts[idx + 2]
|
||||
else:
|
||||
if val == 'discover':
|
||||
test_dir = command_parts[idx + 2]
|
||||
elif not os.path.isfile(
|
||||
'.testr.conf') and not os.path.isfile('.stestr.conf'):
|
||||
msg = ('No .stestr.conf found, please create one.')
|
||||
print(msg)
|
||||
sys.exit(1)
|
||||
|
||||
regexes = None
|
||||
if regex:
|
||||
regexes = regex.split()
|
||||
serial = not parallel
|
||||
if list_tests:
|
||||
cmd = ['testr', 'list-tests']
|
||||
elif (subunit or pretty) and not until_failure:
|
||||
cmd.append('--subunit')
|
||||
elif not (subunit or pretty) and until_failure:
|
||||
cmd.append('--until-failure')
|
||||
if list_of_tests:
|
||||
test_fd, test_file_name = tempfile.mkstemp()
|
||||
atexit.register(os.remove, test_file_name)
|
||||
test_file = os.fdopen(test_fd, 'w')
|
||||
test_file.write('\n'.join(list_of_tests) + '\n')
|
||||
test_file.close()
|
||||
cmd.extend(('--load-list', test_file_name))
|
||||
elif regex:
|
||||
cmd.append(regex)
|
||||
# TODO(mtreinish): remove init call after list command detects and
|
||||
# autocreates the repository
|
||||
if not os.path.isdir('.stestr'):
|
||||
commands.init_command()
|
||||
return commands.list_command(filters=regexes)
|
||||
return_code = commands.run_command(filters=regexes, subunit_out=subunit,
|
||||
concurrency=concur, test_path=test_dir,
|
||||
top_dir=top_dir,
|
||||
group_regex=group_regex,
|
||||
until_failure=until_failure,
|
||||
serial=serial, pretty_out=pretty,
|
||||
load_list=load_list,
|
||||
blacklist_file=blacklist_file,
|
||||
whitelist_file=whitelist_file,
|
||||
black_regex=black_regex)
|
||||
|
||||
env = copy.deepcopy(os.environ)
|
||||
|
||||
if pretty:
|
||||
subunit_trace_cmd = ['subunit-trace', '--no-failure-debug', '-f']
|
||||
if color:
|
||||
subunit_trace_cmd.append('--color')
|
||||
|
||||
# This workaround is necessary because of lp bug 1411804 it's super hacky
|
||||
# and makes tons of unfounded assumptions, but it works for the most part
|
||||
if (subunit or pretty) and until_failure:
|
||||
test_list = rb._get_test_list(regex, env)
|
||||
count = 0
|
||||
failed = False
|
||||
if not test_list:
|
||||
print("No tests to run")
|
||||
return 1
|
||||
# If pretty or subunit output is desired manually loop forever over
|
||||
# test individually and generate the desired output in a linear series
|
||||
# this avoids 1411804 while retaining most of the desired behavior
|
||||
while True:
|
||||
for test in test_list:
|
||||
if pretty:
|
||||
cmd = ['python', '-m', 'subunit.run', test]
|
||||
ps = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE)
|
||||
subunit_trace_cmd.append('--no-summary')
|
||||
proc = subprocess.Popen(subunit_trace_cmd,
|
||||
env=env,
|
||||
stdin=ps.stdout)
|
||||
ps.stdout.close()
|
||||
proc.communicate()
|
||||
if proc.returncode > 0:
|
||||
failed = True
|
||||
break
|
||||
else:
|
||||
try:
|
||||
subunit_run.main([sys.argv[0], test], sys.stdout)
|
||||
except SystemExit as e:
|
||||
if e > 0:
|
||||
print("Ran %s tests without failure" % count)
|
||||
return 1
|
||||
else:
|
||||
raise
|
||||
count = count + 1
|
||||
if failed:
|
||||
print("Ran %s tests without failure" % count)
|
||||
return 0
|
||||
# If not until-failure special case call testr like normal
|
||||
elif pretty and not list_tests:
|
||||
cmd.extend(others)
|
||||
ps = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE)
|
||||
proc = subprocess.Popen(subunit_trace_cmd,
|
||||
env=env, stdin=ps.stdout)
|
||||
ps.stdout.close()
|
||||
else:
|
||||
cmd.extend(others)
|
||||
proc = subprocess.Popen(cmd, env=env)
|
||||
proc.communicate()
|
||||
return_code = proc.returncode
|
||||
if slowest and not list_tests:
|
||||
print("\nSlowest Tests:\n")
|
||||
slow_proc = subprocess.Popen(['testr', 'slowest'], env=env)
|
||||
slow_proc.communicate()
|
||||
if slowest:
|
||||
sys.stdout.write("\nSlowest Tests:\n")
|
||||
commands.slowest_command()
|
||||
return return_code
|
||||
|
||||
|
||||
@ -224,19 +200,16 @@ def call_subunit_run(test_id, pretty, subunit):
|
||||
testtools_run.main([sys.argv[0], test_id], sys.stdout)
|
||||
|
||||
|
||||
def _ensure_testr():
|
||||
if not os.path.isdir('.testrepository'):
|
||||
subprocess.call(['testr', 'init'])
|
||||
|
||||
|
||||
def _select_and_call_runner(opts, exclude_regex, others):
|
||||
ec = 1
|
||||
_ensure_testr()
|
||||
|
||||
if not opts.no_discover and not opts.pdb:
|
||||
ec = call_testr(exclude_regex, opts.subunit, opts.pretty, opts.list,
|
||||
opts.slowest, opts.parallel, opts.concurrency,
|
||||
opts.until_failure, opts.color, None, others)
|
||||
opts.until_failure, opts.color, others,
|
||||
blacklist_file=opts.blacklist_file,
|
||||
whitelist_file=opts.whitelist_file,
|
||||
black_regex=opts.black_regex)
|
||||
else:
|
||||
if others:
|
||||
print('Unexpected arguments: ' + ' '.join(others))
|
||||
@ -248,24 +221,6 @@ def _select_and_call_runner(opts, exclude_regex, others):
|
||||
return ec
|
||||
|
||||
|
||||
def _call_testr_with_list(opts, test_list, others):
|
||||
ec = 1
|
||||
_ensure_testr()
|
||||
|
||||
if opts.list:
|
||||
print("\n".join(test_list))
|
||||
return 0
|
||||
|
||||
if not test_list:
|
||||
print("No testcase selected to run")
|
||||
return 8
|
||||
|
||||
ec = call_testr(None, opts.subunit, opts.pretty, opts.list,
|
||||
opts.slowest, opts.parallel, opts.concurrency,
|
||||
opts.until_failure, opts.color, test_list, others)
|
||||
return ec
|
||||
|
||||
|
||||
def ostestr(args):
|
||||
opts, others = get_parser(args)
|
||||
if opts.pretty and opts.subunit:
|
||||
@ -301,15 +256,7 @@ def ostestr(args):
|
||||
else:
|
||||
regex = opts.regex
|
||||
|
||||
if opts.blacklist_file or opts.whitelist_file or opts.black_regex:
|
||||
list_of_tests = tlb.construct_list(opts.blacklist_file,
|
||||
opts.whitelist_file,
|
||||
regex,
|
||||
opts.black_regex,
|
||||
opts.print_exclude)
|
||||
return (_call_testr_with_list(opts, list_of_tests, others))
|
||||
else:
|
||||
return (_select_and_call_runner(opts, regex, others))
|
||||
return _select_and_call_runner(opts, regex, others)
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -19,7 +19,7 @@ import subprocess
|
||||
|
||||
def _get_test_list(regex, env=None):
|
||||
env = env or copy.deepcopy(os.environ)
|
||||
testr_args = ['testr', 'list-tests']
|
||||
testr_args = ['stestr', 'list']
|
||||
if regex:
|
||||
testr_args.append(regex)
|
||||
proc = subprocess.Popen(testr_args, env=env,
|
||||
|
3
os_testr/tests/files/stestr-conf
Normal file
3
os_testr/tests/files/stestr-conf
Normal file
@ -0,0 +1,3 @@
|
||||
[DEFAULT]
|
||||
test_path=./tests
|
||||
group_regex=([^\.]*\.)*
|
@ -1,5 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_command=${PYTHON:-python} -m subunit.run discover -t ./ ./tests $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
||||
group_regex=([^\.]*\.)*
|
@ -34,13 +34,13 @@ class TestReturnCodes(base.TestCase):
|
||||
self.test_dir = os.path.join(self.directory, 'tests')
|
||||
os.mkdir(self.test_dir)
|
||||
# Setup Test files
|
||||
self.testr_conf_file = os.path.join(self.directory, '.testr.conf')
|
||||
self.testr_conf_file = os.path.join(self.directory, '.stestr.conf')
|
||||
self.setup_cfg_file = os.path.join(self.directory, 'setup.cfg')
|
||||
self.passing_file = os.path.join(self.test_dir, 'test_passing.py')
|
||||
self.failing_file = os.path.join(self.test_dir, 'test_failing.py')
|
||||
self.init_file = os.path.join(self.test_dir, '__init__.py')
|
||||
self.setup_py = os.path.join(self.directory, 'setup.py')
|
||||
shutil.copy('os_testr/tests/files/testr-conf', self.testr_conf_file)
|
||||
shutil.copy('os_testr/tests/files/stestr-conf', self.testr_conf_file)
|
||||
shutil.copy('os_testr/tests/files/passing-tests', self.passing_file)
|
||||
shutil.copy('os_testr/tests/files/failing-tests', self.failing_file)
|
||||
shutil.copy('setup.py', self.setup_py)
|
||||
@ -104,4 +104,4 @@ class TestReturnCodes(base.TestCase):
|
||||
self.assertRunExit('ostestr --list', 0)
|
||||
|
||||
def test_no_test(self):
|
||||
self.assertRunExit('ostestr --regex a --black-regex a', 8)
|
||||
self.assertRunExit('ostestr --regex a --black-regex a', 1)
|
||||
|
@ -3,6 +3,6 @@
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
stestr>=1.0.0 # Apache-2.0
|
||||
python-subunit>=0.0.18 # Apache-2.0/BSD
|
||||
testtools>=1.4.0 # MIT
|
||||
|
12
tox.ini
12
tox.ini
@ -10,6 +10,9 @@ setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
BRANCH_NAME=master
|
||||
CLIENT_NAME=os-testr
|
||||
OS_STDOUT_CAPTURE=1
|
||||
OS_STDERR_CAPTURE=1
|
||||
OS_TEST_TIMEOUT=500
|
||||
whitelist_externals = find
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
@ -24,7 +27,14 @@ commands = flake8
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
commands = python setup.py test --coverage --coverage-package-name='os_testr' --testr-args='{posargs}'
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
PYTHON=coverage run --source os_testr --parallel-mode
|
||||
commands =
|
||||
ostestr {posargs}
|
||||
coverage combine
|
||||
coverage html -d cover
|
||||
coverage xml -o cover/coverage.xml
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
|
Loading…
Reference in New Issue
Block a user