Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use subunit-trace #72

Merged
merged 8 commits into from
Jul 28, 2017
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions doc/source/MANUAL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,24 @@ selection options to do this, for example::
This will list all the tests which will be run by stestr using that combination
of arguments.

Adjusting test run output
-------------------------

By default the ``stestr run`` command uses an output filter called
subunit-trace. (as does the ``stestr last`` command) This displays the tests
as they are finished executing, as well as their worker and status. It also
prints aggregate numbers about the run at the end. You can read more about
subunit-trace in the module doc: :ref:`subunit_trace`.

However, the test run output is configurable, you can disable this output
with the ``--no-subunit-trace`` flag which will be completely silent except for
any failures it encounters. There is also the ``--color`` flag which will enable
colorization with subunit-trace output. If you prefer to deal with the raw
subunit yourself and run your own output rendering or filtering you can use
the ``--subunit`` flag to output the result stream as raw subunit v2.



Combining Test Results
----------------------
There is sometimes a use case for running a single test suite split between
Expand Down
7 changes: 7 additions & 0 deletions doc/source/subunit_trace.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.. _subunit_trace:

Subunit Trace
=============

.. automodule:: stestr.subunit_trace
:members:
98 changes: 98 additions & 0 deletions stestr/colorizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Copyright 2015 NEC Corporation
# All Rights Reserved.
#
# 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.
#
# Colorizer Code is borrowed from Twisted:
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import sys


class AnsiColorizer(object):
"""A colorizer is an object that loosely wraps around a stream

allowing callers to write text to the stream in a particular color.

Colorizer classes must implement C{supported()} and C{write(text, color)}.
"""
_colors = dict(black=30, red=31, green=32, yellow=33,
blue=34, magenta=35, cyan=36, white=37)

def __init__(self, stream):
self.stream = stream

@classmethod
def supported(cls, stream=sys.stdout):
"""Check the current platform supports coloring terminal output

A class method that returns True if the current platform supports
coloring terminal output using this method. Returns False otherwise.
"""
if not stream.isatty():
return False # auto color only on TTYs
try:
import curses
except ImportError:
return False
else:
try:
try:
return curses.tigetnum("colors") > 2
except curses.error:
curses.setupterm()
return curses.tigetnum("colors") > 2
except Exception:
# guess false in case of error
return False

def write(self, text, color):
"""Write the given text to the stream in the given color.

@param text: Text to be written to the stream.

@param color: A string label for a color. e.g. 'red', 'white'.
"""
color = self._colors[color]
self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))


class NullColorizer(object):
"""See _AnsiColorizer docstring."""
def __init__(self, stream):
self.stream = stream

@classmethod
def supported(cls, stream=sys.stdout):
return True

def write(self, text, color):
self.stream.write(text)
48 changes: 34 additions & 14 deletions stestr/commands/last.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from stestr import output
from stestr.repository import util
from stestr import results
from stestr import subunit_trace


def get_cli_help():
Expand All @@ -35,16 +36,28 @@ def get_cli_help():
def set_cli_opts(parser):
parser.add_argument(
"--subunit", action="store_true",
default=False, help="Show output as a subunit stream."),
default=False, help="Show output as a subunit stream.")
parser.add_argument("--no-subunit-trace", action='store_true',
default=False,
help="Disable output with the subunit-trace output "
"filter")
parser.add_argument('--color', action='store_true', default=False,
help='Enable color output in the subunit-trace output,'
' if subunit-trace output is enabled. (this is '
'the default). If subunit-trace is disable this '
' does nothing.')


def run(arguments):
args = arguments[0]
pretty_out = not args.no_subunit_trace
return last(repo_type=args.repo_type, repo_url=args.repo_url,
subunit=args.subunit)
subunit_out=args.subunit, pretty_out=pretty_out,
color=args.color)


def last(repo_type='file', repo_url=None, subunit=False):
def last(repo_type='file', repo_url=None, subunit_out=False, pretty_out=True,
color=False):
"""Show the last run loaded into a a repository

Note this function depends on the cwd for the repository if `repo_type` is
Expand All @@ -54,11 +67,13 @@ def last(repo_type='file', repo_url=None, subunit=False):
: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.
:param bool subunit_out: Show output as a subunit stream.
:param pretty_out: Use the subunit-trace output filter.
:param color: Enable colorized output with the subunit-trace output filter.
"""
repo = util.get_repo_open(repo_type, repo_url)
latest_run = repo.get_latest_run()
if subunit:
if subunit_out:
stream = latest_run.get_subunit_stream()
output.output_stream(stream)
# Exits 0 if we successfully wrote the stream.
Expand All @@ -74,15 +89,20 @@ def last(repo_type='file', repo_url=None, subunit=False):
except KeyError:
previous_run = None
failed = False
output_result = results.CLITestResult(latest_run.get_id, sys.stdout,
previous_run)
summary = output_result.get_summary()
output_result.startTestRun()
try:
case.run(output_result)
finally:
output_result.stopTestRun()
failed = not summary.wasSuccessful()
if not pretty_out:
output_result = results.CLITestResult(latest_run.get_id, sys.stdout,
previous_run)
summary = output_result.get_summary()
output_result.startTestRun()
try:
case.run(output_result)
finally:
output_result.stopTestRun()
failed = not summary.wasSuccessful()
else:
stream = latest_run.get_subunit_stream()
failed = subunit_trace.trace(stream, sys.stdout, post_fails=True,
color=color)
if failed:
return 1
else:
Expand Down
32 changes: 30 additions & 2 deletions stestr/commands/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"""Load data into a repository."""


import datetime
import functools
import sys

Expand All @@ -23,6 +24,7 @@
from stestr.repository import abstract as repository
from stestr.repository import util
from stestr import results
from stestr import subunit_trace
from stestr import utils


Expand All @@ -40,6 +42,13 @@ def set_cli_opts(parser):
parser.add_argument("--id", "-i", default=None,
help="Append the stream into an existing entry in the "
"repository")
parser.add_argument("--subunit-trace", action='store_true', default=False,
help="Display the loaded stream through the "
"subunit-trace output filter")
parser.add_argument('--color', action='store_true', default=False,
help='Enable color output in the subunit-trace output,'
' if subunit-trace output is enabled. If '
'subunit-trace is disable this does nothing.')


def get_cli_help():
Expand All @@ -58,12 +67,13 @@ def run(arguments):
args = arguments[0]
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])
force_init=args.force_init, streams=arguments[1],
pretty_out=args.subunit_trace, color=args.color)


def load(force_init=False, in_streams=None,
partial=False, subunit_out=False, repo_type='file', repo_url=None,
run_id=None, streams=None):
run_id=None, streams=None, pretty_out=False, color=False):
"""Load subunit streams into a repository

:param bool force_init: Initialize the specifiedrepository if it hasn't
Expand All @@ -77,6 +87,9 @@ def load(force_init=False, in_streams=None,
: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.
:param bool pretty_out: Use the subunit-trace output filter for the loaded
stream.
:param bool color: Enabled colorized subunit-trace output
"""

try:
Expand Down Expand Up @@ -116,6 +129,15 @@ def make_tests():
inserter = repo.get_inserter(partial=partial, run_id=run_id)
if subunit_out:
output_result, summary_result = output.make_result(inserter.get_id)
if pretty_out:
outcomes = testtools.StreamToDict(
functools.partial(subunit_trace.show_outcome, sys.stdout,
enable_color=color))
summary_result = testtools.StreamSummary()
output_result = testtools.CopyStreamResult([outcomes, summary_result])
output_result = testtools.StreamResultRouter(output_result)
cat = subunit.test_results.CatFiles(sys.stdout)
output_result.add_rule(cat, 'test_id', test_id=None)
else:
try:
previous_run = repo.get_latest_run()
Expand All @@ -125,11 +147,17 @@ def make_tests():
inserter.get_id, sys.stdout, previous_run)
summary_result = output_result.get_summary()
result = testtools.CopyStreamResult([inserter, output_result])
start_time = datetime.datetime.utcnow()
result.startTestRun()
try:
case.run(result)
finally:
result.stopTestRun()
stop_time = datetime.datetime.utcnow()
elapsed_time = stop_time - start_time
if pretty_out:
subunit_trace.print_fails(sys.stdout)
subunit_trace.print_summary(sys.stdout, elapsed_time)
if not summary_result.wasSuccessful():
return 1
else:
Expand Down
Loading