
This commit switches from using subprocess to call testtools.run and subunit.run with python -m to directly calling the methods being run. This should make the non-default cases when using subunit.run and testtools.run faster, and it simplifies the code. As part of this, the code around call_subunit is fixed to make sure the it works as expected given different argument combinations. ostestr will still call subprocess to run testr, because the interface is more complex, and when subunit.run is used with subunit-trace, because the stdin handling is tricky. The subunit.run with subunit-trace case will be handled in a later patch.
163 lines
6.5 KiB
Python
Executable File
163 lines
6.5 KiB
Python
Executable File
#!/usr/bin/env python2
|
|
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import argparse
|
|
import copy
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from subunit import run as subunit_run
|
|
from testtools import run as testtools_run
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(
|
|
description='Tool to run openstack tests')
|
|
parser.add_argument('--blacklist_file', '-b',
|
|
help='Path to a blacklist file, this file contains a'
|
|
' separate regex exclude on each newline')
|
|
parser.add_argument('--regex', '-r',
|
|
help='A normal testr selection regex. If a blacklist '
|
|
'file is specified, the regex will be appended '
|
|
'to the end of the generated regex from that '
|
|
'file')
|
|
parser.add_argument('--pretty', '-p', dest='pretty', action='store_true',
|
|
help='Print pretty output from subunit-trace. This is '
|
|
'mutually exclusive with --subunit')
|
|
parser.add_argument('--no-pretty', dest='pretty', action='store_false',
|
|
help='Disable the pretty output with subunit-trace')
|
|
parser.add_argument('--subunit', '-s', action='store_true',
|
|
help='output the raw subunit v2 from the test run '
|
|
'this is mutuall exclusive with --pretty')
|
|
parser.add_argument('--list', '-l', action='store_true',
|
|
help='List all the tests which will be run.')
|
|
parser.add_argument('--no-discover', '-n', metavar='TEST_ID',
|
|
help="Takes in a single test to bypasses test "
|
|
"discover and just excute the test specified")
|
|
parser.add_argument('--slowest', dest='slowest', action='store_true',
|
|
help="after the test run print the slowest tests")
|
|
parser.add_argument('--no-slowest', dest='slowest', action='store_false',
|
|
help="after the test run don't print the slowest "
|
|
"tests")
|
|
parser.add_argument('--pdb', metavar='TEST_ID',
|
|
help='Run a single test that has pdb traces added')
|
|
parser.add_argument('--parallel', dest='parallel', action='store_true',
|
|
help='Run tests in parallel (this is the default)')
|
|
parser.add_argument('--serial', dest='parallel', action='store_false',
|
|
help='Run tests serially')
|
|
parser.add_argument('--concurrency', '-c', type=int, metavar='WORKERS',
|
|
help='The number of workers to use when running in '
|
|
'parallel. By default this is the number of cpus')
|
|
parser.set_defaults(pretty=True, slowest=True, parallel=True)
|
|
opts = parser.parse_args()
|
|
return opts
|
|
|
|
|
|
def construct_regex(blacklist_file, regex):
|
|
if not blacklist_file:
|
|
exclude_regex = ''
|
|
else:
|
|
black_file = open(blacklist_file, 'r')
|
|
exclude_regex = ''
|
|
for line in black_file:
|
|
regex = line.strip()
|
|
exclude_regex = '|'.join([regex, exclude_regex])
|
|
if exclude_regex:
|
|
exclude_regex = "'(?!.*" + exclude_regex + ")"
|
|
if regex:
|
|
exclude_regex += regex
|
|
return exclude_regex
|
|
|
|
|
|
def call_testr(regex, subunit, pretty, list_tests, slowest, parallel, concur):
|
|
if parallel:
|
|
cmd = ['testr', 'run', '--parallel']
|
|
if concur:
|
|
cmd.append('--concurrency=%s' % concur)
|
|
else:
|
|
cmd = ['testr', 'run']
|
|
if list_tests:
|
|
cmd = ['testr', 'list-tests']
|
|
elif subunit or pretty:
|
|
cmd.append('--subunit')
|
|
cmd.append(regex)
|
|
env = copy.deepcopy(os.environ)
|
|
if pretty and not list_tests:
|
|
ps = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE)
|
|
proc = subprocess.Popen(['subunit-trace', '--no-failure-debug', '-f'],
|
|
env=env, stdin=ps.stdout)
|
|
ps.stdout.close()
|
|
else:
|
|
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()
|
|
return return_code
|
|
|
|
|
|
def call_subunit_run(test_id, pretty, subunit):
|
|
if pretty:
|
|
env = copy.deepcopy(os.environ)
|
|
cmd = ['python', '-m', 'subunit.run', test_id]
|
|
ps = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE)
|
|
proc = subprocess.Popen(['subunit-trace', '--no-failure-debug', '-f'],
|
|
env=env, stdin=ps.stdout)
|
|
ps.stdout.close()
|
|
proc.communicate()
|
|
return proc.returncode
|
|
elif subunit:
|
|
subunit_run.main([sys.argv[0], test_id], sys.stdout)
|
|
else:
|
|
testtools_run.main([sys.argv[0], test_id], sys.stdout)
|
|
|
|
|
|
def call_testtools_run(test_id):
|
|
testtools_run.main([sys.argv[0], test_id], sys.stdout)
|
|
|
|
|
|
def main():
|
|
opts = parse_args()
|
|
if opts.pretty and opts.subunit:
|
|
msg = ('Subunit output and pretty output cannot be specified at the '
|
|
'same time')
|
|
print(msg)
|
|
exit(2)
|
|
if opts.list and opts.no_discover:
|
|
msg = ('you can not list tests when you are bypassing discovery to '
|
|
'run a single test')
|
|
print(msg)
|
|
exit(3)
|
|
if not opts.parallel and opts.concurrency:
|
|
msg = "You can't specify a concurrency to use when running serially"
|
|
print(msg)
|
|
exit(4)
|
|
exclude_regex = construct_regex(opts.blacklist_file, opts.regex)
|
|
if not os.path.isdir('.testrepository'):
|
|
subprocess.call(['testr', 'init'])
|
|
if not opts.no_discover and not opts.pdb:
|
|
exit(call_testr(exclude_regex, opts.subunit, opts.pretty, opts.list,
|
|
opts.slowest, opts.parallel, opts.concurrency))
|
|
elif opts.pdb:
|
|
exit(call_testtools_run(opts.pdb))
|
|
else:
|
|
exit(call_subunit_run(opts.no_discover, opts.pretty, opts.subunit))
|
|
|
|
if __name__ == '__main__':
|
|
main()
|