Skip to content

Commit

Permalink
Add a real python api for running commands
Browse files Browse the repository at this point in the history
This commit adds a real api for running the stestr commands. Instead of
just having a magic run() function that takes in an tuple of a argparse
Namespace and a list of undefined arguments this migrates all the real
work into a function that has properly defined kwargs. The run() command
is then relegated to just convert the Namespace into a dict and pass the
arguments into that real function. This enables external programs to
just call the new functions with defined args and run commands exactly
like on the cli, but with a defined python interface. It makes
everything a lot easier for python consumption. The tradeoff here though
is that everything is bit more verbose, but that's the cost of being
explicit with a defined interface.

As a side effect of this change instead of passing that Namespace object
around between all the lower layers real interfaces have to be defined
for all the functions. This means a ton of new kwargs, but again this
is better in the long run because it means we have defined interfaces
for all the functions.

Closes Issue #8
  • Loading branch information
mtreinish committed Jul 24, 2017
1 parent e571f84 commit 8a75797
Show file tree
Hide file tree
Showing 11 changed files with 398 additions and 136 deletions.
30 changes: 26 additions & 4 deletions stestr/commands/failing.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,35 @@ def _get_id():

def run(arguments):
args = arguments[0]
repo = util.get_repo_open(args.repo_type, args.repo_url)
return failing(repo_type=args.repo_type, repo_url=args.repo_url,
list_tests=args.list, subunit=args.subunit)


def failing(repo_type='file', repo_url=None, list_tests=False, subunit=False):
"""Return the failing tests from the most recent run in the repository
Note this function depends on the cwd for the repository if `repo_type` is
set to file and `repo_url` is not specified it will use the repository
located at CWD/.stestr
:param str repo_type: This is the type of repository to use. Valid choices
are 'file' and 'sql'.
:param str repo_url: The url of the repository to use.
:param bool list_test: Show only a list of failing tests.
:param bool subunit: Show output as a subunit stream.
"""
if repo_type not in ['file', 'sql']:
print('Repository type %s is not a type' % repo_type)
return 1

repo = util.get_repo_open(repo_type, repo_url)
run = repo.get_failing()
if args.subunit:
if subunit:
return _show_subunit(run)
case = run.get_test()
failed = False
result, summary = _make_result(repo, list_tests=args.list)
result, summary = _make_result(repo, list_tests=list_tests)
result.startTestRun()
try:
case.run(result)
Expand All @@ -76,7 +98,7 @@ def run(arguments):
result = 1
else:
result = 0
if args.list:
if list_tests:
failing_tests = [
test for test, _ in summary.errors + summary.failures]
output.output_tests(failing_tests)
Expand Down
20 changes: 18 additions & 2 deletions stestr/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,24 @@
from stestr.repository import util


def run(args):
util.get_repo_initialise(args[0].repo_type, args[0].repo_url)
def run(arguments):
args = arguments[0]
return init(args.repo_type, args.repo_url)


def init(repo_type='file', repo_url=None):
"""Initialize a new repository
Note this function depends on the cwd for the repository if `repo_type` is
set to file and `repo_url` is not specified it will use the repository
located at CWD/.stestr
:param str repo_type: This is the type of repository to use. Valid choices
are 'file' and 'sql'.
:param str repo_url: The url of the repository to use.
"""

return util.get_repo_initialise(repo_type, repo_url)


def set_cli_opts(parser):
Expand Down
22 changes: 19 additions & 3 deletions stestr/commands/last.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,32 @@ def set_cli_opts(parser):

def run(arguments):
args = arguments[0]
repo = util.get_repo_open(args.repo_type, args.repo_url)
return last(repo_type=args.repo_type, repo_url=args.repo_url,
subunit=args.subunit)


def last(repo_type='file', repo_url=None, subunit=False):
"""Show the last run loaded into a a repository
Note this function depends on the cwd for the repository if `repo_type` is
set to file and `repo_url` is not specified it will use the repository
located at CWD/.stestr
:param str repo_type: This is the type of repository to use. Valid choices
are 'file' and 'sql'.
:param str repo_url: The url of the repository to use.
:param bool subunit: Show output as a subunit stream.
"""
repo = util.get_repo_open(repo_type, repo_url)
latest_run = repo.get_latest_run()
if args.subunit:
if subunit:
stream = latest_run.get_subunit_stream()
output.output_stream(stream)
# Exits 0 if we successfully wrote the stream.
return 0
case = latest_run.get_test()
try:
if args.repo_type == 'file':
if repo_type == 'file':
previous_run = repo.get_test_run(repo.latest_id() - 1)
# TODO(mtreinish): add a repository api to get the previous_run to
# unify this logic
Expand Down
61 changes: 52 additions & 9 deletions stestr/commands/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,59 @@ def set_cli_opts(parser):
' white selection, which by default is everything.')


def run(args):
_args = args[0]
def run(arguments):
args = arguments[0]
filters = arguments[1]
return list_command(config=args.config, repo_type=args.repo_type,
repo_url=args.repo_url, group_regex=args.group_regex,
blacklist_file=args.blacklist_file,
whitelist_file=args.whitelist_file,
black_regex=args.black_regex,
filters=filters)


def list_command(config='.stestr.conf', repo_type='file', repo_url=None,
test_path=None, top_dir=None, group_regex=None,
blacklist_file=None, whitelist_file=None, black_regex=None,
filters=None):
"""Print a list of test_ids for a project
This function will print the test_ids for tests in a project. You can
filter the output just like with the run command to see exactly what
will be run.
:param str config: The path to the stestr config file. Must be a string.
:param str repo_type: This is the type of repository to use. Valid choices
are 'file' and 'sql'.
:param str repo_url: The url of the repository to use.
:param str test_path: Set the test path to use for unittest discovery.
If both this and the corresponding config file option are set, this
value will be used.
:param str top_dir: The top dir to use for unittest discovery. This takes
precedence over the value in the config file. (if one is present in
the config file)
:param str group_regex: Set a group regex to use for grouping tests
together in the stestr scheduler. If both this and the corresponding
config file option are set this value will be used.
:param str blacklist_file: Path to a blacklist file, this file contains a
separate regex exclude on each newline.
:param str whitelist_file: Path to a whitelist file, this file contains a
separate regex on each newline.
:param str black_regex: Test rejection regex. If a test cases name matches
on re.search() operation, it will be removed from the final test list.
:param list filters: A list of string regex filters to initially apply on
the test list. Tests that match any of the regexes will be used.
(assuming any other filtering specified also uses it)
"""
ids = None
filters = None
if args[1]:
filters = args[1]
conf = config_file.TestrConf(_args.config)
cmd = conf.get_run_command(_args, ids, filters)
not_filtered = filters is None and _args.blacklist_file is None\
and _args.whitelist_file is None and _args.black_regex is None
conf = config_file.TestrConf(config)
cmd = conf.get_run_command(
regexes=filters, repo_type=repo_type,
repo_url=repo_url, group_regex=group_regex,
blacklist_file=blacklist_file, whitelist_file=whitelist_file,
black_regex=black_regex)
not_filtered = filters is None and blacklist_file is None\
and whitelist_file is None and black_regex is None
try:
cmd.setUp()
# List tests if the fixture has not already needed to to filter.
Expand Down
56 changes: 28 additions & 28 deletions stestr/commands/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,34 @@ def get_cli_help():


def run(arguments):
load(arguments)


def load(arguments, in_streams=None, partial=False, subunit_out=False,
repo_type=None, repo_url=None, run_id=None):
args = arguments[0]
streams = arguments[1]
if args:
repo_type = args.repo_type
repo_url = args.repo_url
load(repo_type=args.repo_type, repo_url=args.repo_url,
partial=args.partial, subunit_out=args.subunit,
force_init=args.force_init, streams=arguments[1])


def load(force_init=False, in_streams=None,
partial=False, subunit_out=False, repo_type='file', repo_url=None,
run_id=None, streams=None):
"""Load subunit streams into a repository
:param bool force_init: Initialize the specifiedrepository if it hasn't
been created.
:param list in_streams: A list of file objects that will be saved into the
repository
:param bool partial: Specify the input is a partial stream
:param bool subunit_out: Output the subunit stream to stdout
:param str repo_type: This is the type of repository to use. Valid choices
are 'file' and 'sql'.
:param str repo_url: The url of the repository to use.
:param run_id: The optional run id to save the subunit stream to.
:param list streams: A list of file paths to read for the input streams.
"""

try:
repo = util.get_repo_open(repo_type, repo_url)
except repository.RepositoryNotFound:
if args.force_init:
if force_init:
repo = util.get_repo_initialise(repo_type, repo_url)
else:
raise
Expand Down Expand Up @@ -96,25 +110,11 @@ def make_tests():
yield (case, str(pos))

case = testtools.ConcurrentStreamTestSuite(make_tests)
# One unmodified copy of the stream to repository storage
_partial = False
if args:
_partial = getattr(args, 'partial')
# Set partial_stream if it comes in via the CLI or the kwarg
partial_stream = _partial or partial
_subunit = False
if args:
_subunit = getattr(args, 'subunit')
_subunit_out = _subunit or subunit_out
_run_id = None
if args:
_run_id = getattr(args, 'id')
_run_id = _run_id or run_id
if not _run_id:
inserter = repo.get_inserter(partial=partial_stream)
if not run_id:
inserter = repo.get_inserter(partial=partial)
else:
inserter = repo.get_inserter(partial=partial_stream, run_id=_run_id)
if _subunit_out:
inserter = repo.get_inserter(partial=partial, run_id=run_id)
if subunit_out:
output_result, summary_result = output.make_result(inserter.get_id)
else:
try:
Expand Down

0 comments on commit 8a75797

Please sign in to comment.