1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#!${buildout:executable}
#
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""
Given an error report, run all of the failed tests again.
For instance, it can be used in the following scenario:
% bin/test -vvm lp.registry | tee test.out
% # Oh nos! Failures!
% # Fix tests.
% bin/retest test.out
Or, when run without arguments (or if any argument is "-"), a test
report (or a part of) can be piped in, for example by pasting it:
% bin/retest
Tests with failures:
lib/lp/registry/browser/tests/sourcepackage-views.txt
lib/lp/registry/tests/../stories/product/xx-product-package-pages.txt
Total: ... tests, 2 failures, 0 errors in ...
"""
import fileinput
import os
import re
import sys
from itertools import takewhile, imap
${python-relative-path-setup}
# The test script for this branch.
TEST = "${buildout:directory/bin/test}"
# Regular expression to match numbered stories.
STORY_RE = re.compile("(.*)/\d{2}-.*")
# Regular expression to remove terminal color escapes.
COLOR_RE = re.compile("\x1b[[][0-9;]+m")
def decolorize(text):
"""Remove all ANSI terminal color escapes from `text`."""
return COLOR_RE.sub("", text)
def get_test_name(test):
"""Get the test name of a failed test.
If the test is part of a numbered story,
e.g. 'stories/gpg-coc/01-claimgpgp.txt', then return the directory name
since all of the stories must be run together.
"""
match = STORY_RE.match(test)
if match:
return match.group(1)
else:
return test
def gen_test_lines(lines):
def p_start(line):
return (
line.startswith('Tests with failures:') or
line.startswith('Tests with errors:'))
def p_take(line):
return not (
line.isspace() or
line.startswith('Total:'))
lines = iter(lines)
for line in lines:
if p_start(line):
for line in takewhile(p_take, lines):
yield line
def gen_tests(test_lines):
for test_line in test_lines:
yield get_test_name(test_line.strip())
def extract_tests(lines):
return set(gen_tests(gen_test_lines(lines)))
def run_tests(tests):
"""Given a set of tests, run them as one group."""
print "Running tests:"
for test in tests:
print " %s" % test
args = ['-vvc'] if sys.stdout.isatty() else ['-vv']
for test in tests:
args.append('-t')
args.append(re.escape(test))
os.execl(TEST, TEST, *args)
if __name__ == '__main__':
lines = imap(decolorize, fileinput.input())
tests = extract_tests(lines)
if len(tests) >= 1:
run_tests(tests)
else:
sys.stdout.write(
"Error: no tests found\n"
"Usage: %s [test_output_file|-] ...\n\n%s\n\n" % (
sys.argv[0], __doc__.strip()))
sys.exit(1)
|