~launchpad-pqm/launchpad/devel

9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
1
#!${buildout:executable}
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
2
#
3
# Copyright 2009 Canonical Ltd.  This software is licensed under the
4
# GNU Affero General Public License version 3 (see the file LICENSE).
5
6
"""
7
Given an error report, run all of the failed tests again.
8
9
For instance, it can be used in the following scenario:
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
10
11
  % bin/test -vvm lp.registry | tee test.out
12
  % # Oh nos!  Failures!
13
  % # Fix tests.
9609.1.2 by Gavin Panella
Correct docstring to refer to new location of retest script.
14
  % bin/retest test.out
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
15
16
Or, when run without arguments (or if any argument is "-"), a test
17
report (or a part of) can be piped in, for example by pasting it:
18
9609.1.2 by Gavin Panella
Correct docstring to refer to new location of retest script.
19
  % bin/retest
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
20
  Tests with failures:
21
     lib/lp/registry/browser/tests/sourcepackage-views.txt
22
     lib/lp/registry/tests/../stories/product/xx-product-package-pages.txt
23
  Total: ... tests, 2 failures, 0 errors in ...
24
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
25
"""
26
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
27
import fileinput
28
import os
29
import re
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
30
import sys
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
31
from itertools import takewhile
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
32
from pprint import pprint
33
10713.1.1 by Gary Poster
use new version of z3c.recipe.filetemplate and zc.buildout fork to use relative paths.
34
${python-relative-path-setup}
9570.5.2 by Brad Crittenden
Minor changes from review.
35
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
36
# The test script for this branch.
11090.3.14 by Brad Crittenden
Fix retest to handle windmill tests.
37
TEST = "${buildout:directory/bin/test}"
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
38
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
39
# Regular expression to match numbered stories.
40
STORY_RE = re.compile("(.*)/\d{2}-.*")
41
42
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
43
def get_test_name(test):
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
44
    """Get the test name of a failed test.
45
46
    If the test is part of a numbered story,
47
    e.g. 'stories/gpg-coc/01-claimgpgp.txt', then return the directory name
48
    since all of the stories must be run together.
49
    """
50
    match = STORY_RE.match(test)
51
    if match:
52
        return match.group(1)
11090.3.14 by Brad Crittenden
Fix retest to handle windmill tests.
53
    # Otherwise split the test and return the first portion.  The split will
54
    # chop off windmill descriptions.
55
    return test.split()[0]
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
56
57
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
58
def gen_test_lines(lines):
59
    def p_start(line):
12060.2.1 by Gavin Panella
Make bin/retest work on errors too.
60
        return (
61
            line.startswith('Tests with failures:') or
62
            line.startswith('Tests with errors:'))
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
63
    def p_take(line):
12060.2.2 by Gavin Panella
Make bin/retest work when there are both errors and failures.
64
        return not (
65
            line.isspace() or
66
            line.startswith('Total:'))
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
67
    lines = iter(lines)
68
    for line in lines:
69
        if p_start(line):
70
            for line in takewhile(p_take, lines):
71
                yield line
72
73
74
def gen_tests(test_lines):
75
    for test_line in test_lines:
76
        yield get_test_name(test_line.strip())
77
78
79
def extract_tests(lines):
80
    return set(gen_tests(gen_test_lines(lines)))
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
81
82
83
def run_tests(tests):
84
    """Given a set of tests, run them as one group."""
85
    print "Running tests:"
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
86
    pprint(sorted(tests))
87
    args = ['-vv']
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
88
    for test in tests:
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
89
        args.append('-t')
90
        args.append(test)
91
    os.execl(TEST, TEST, *args)
9570.5.1 by Brad Crittenden
Added retest.py, a tool for re-running a failed set of tests based as listed in the output from a previous test run.
92
93
94
if __name__ == '__main__':
9609.1.1 by Gavin Panella
Merge retest improvements from mucked-up branch.
95
    tests = extract_tests(fileinput.input())
96
    if len(tests) >= 1:
97
        run_tests(tests)
98
    else:
99
        sys.stdout.write(
100
            "Error: no tests found\n"
101
            "Usage: %s [test_output_file|-] ...\n\n%s\n\n" % (
102
                sys.argv[0], __doc__.strip()))
103
        sys.exit(1)