Merge lp:~allenap/launchpad/more-retest into lp:launchpad

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~allenap/launchpad/more-retest
Merge into: lp:launchpad
Diff against target: 134 lines
1 file modified
buildout-templates/bin/retest.in (+57/-40)
To merge this branch: bzr merge lp:~allenap/launchpad/more-retest
Reviewer Review Type Date Requested Status
Michael Nelson (community) code Approve
Review via email: mp+12709@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

This branch adjusts retest.py to allow pasting of a test report (by
using fileinput), changes the parsing code to work with multiple
chunks (so test output can be appended to a log), makes it *not* run
the whole test suite if it doesn't find any tests in the log, improves
the usage docs, and MOST IMPORTANTLY makes it possible to kill the
test process with Ctrl-C, which was especially important in the days
when it could decide to try and run the whole test suite.

It also moves the script to be a buildout template, which ends up
creating bin/retest (currently it's not a template, and lives in
utilities/retest.py).

Revision history for this message
Michael Nelson (michael.nelson) wrote :

> This branch adjusts retest.py to allow pasting of a test report (by
> using fileinput), changes the parsing code to work with multiple
> chunks (so test output can be appended to a log), makes it *not* run
> the whole test suite if it doesn't find any tests in the log, improves
> the usage docs, and MOST IMPORTANTLY makes it possible to kill the
> test process with Ctrl-C, which was especially important in the days
> when it could decide to try and run the whole test suite.
>
> It also moves the script to be a buildout template, which ends up
> creating bin/retest (currently it's not a template, and lives in
> utilities/retest.py).

That's great! Thanks Gavin.

launchpad/more-retest/+merge/12709
<noodles775> allenap: sure thing!
<allenap> noodles775: Thanks :)
<thumper> deryck: https://code.edge.launchpad.net/~thumper/launchpad/inline-lifecycle-status-edit/+merge/12707
* sinzui (n=sinzui@91.189.88.12) has joined #launchpad-reviews
<noodles775> allenap: nice - I hadn't seen takewhile before...
<noodles775> allenap: on line 97, why are you converting to a set rather than a list?
<noodles775> I mean, test output will not have duplicates...?
* noodles775 has changed the topic to: on call: noodles775 || reviewing: allenap || queue: [] || This channel is logged: http://irclogs.ubuntu.com
<allenap> noodles775: If multiple test logs are passed in (one of the new features), this removes duplicates.
<noodles775> allenap: then why not convert it back to a sorted list then and there?
<noodles775> ie., so extract_tests returns a sorted list of unique tests?
<noodles775> That's great that multiple logs can be used - and that it's now using a buildout template!
<allenap> noodles775: I only want them sorted to display them prettily, otherwise a set is what I want. Not much in it really.
<allenap> noodles775: As in, could be either a set or a list, but it happens to be a set because of de-duplication.
<noodles775> oh, I didn't see the set features being used anywhere... looking again.
<noodles775> Ah, gotcha. ok.
* sinzui has quit (Read error: 104 (Connection reset by peer))
* sinzui1 (n=sinzui@91.189.88.12) has joined #launchpad-reviews
<noodles775> allenap: great, r=me... just note, there's one reference to the old utilities/retest in the usage instructions.
<noodles775> er, actually, two :)
<allenap> noodles775: Ah, good spot, thanks :)

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'utilities/retest.py' => 'buildout-templates/bin/retest.in'
2--- utilities/retest.py 2009-09-25 20:28:53 +0000
3+++ buildout-templates/bin/retest.in 2009-10-01 10:38:14 +0000
4@@ -1,4 +1,4 @@
5-#!/usr/bin/env python
6+#!${buildout:executable}
7 #
8 # Copyright 2009 Canonical Ltd. This software is licensed under the
9 # GNU Affero General Public License version 3 (see the file LICENSE).
10@@ -7,23 +7,39 @@
11 Given an error report, run all of the failed tests again.
12
13 For instance, it can be used in the following scenario:
14-% bin/test -vvm lp.registry | tee test.out
15-% # Oh nos! Failures!
16-% # Fix tests.
17-% utilities/retest.py test.out
18+
19+ % bin/test -vvm lp.registry | tee test.out
20+ % # Oh nos! Failures!
21+ % # Fix tests.
22+ % bin/retest test.out
23+
24+Or, when run without arguments (or if any argument is "-"), a test
25+report (or a part of) can be piped in, for example by pasting it:
26+
27+ % bin/retest
28+ Tests with failures:
29+ lib/lp/registry/browser/tests/sourcepackage-views.txt
30+ lib/lp/registry/tests/../stories/product/xx-product-package-pages.txt
31+ Total: ... tests, 2 failures, 0 errors in ...
32+
33 """
34
35-import subprocess
36+import fileinput
37+import os
38+import re
39 import sys
40-import re
41+from itertools import takewhile
42 from pprint import pprint
43
44
45+# The test script for this branch.
46+TEST = '${buildout:directory}/bin/test'
47+
48 # Regular expression to match numbered stories.
49 STORY_RE = re.compile("(.*)/\d{2}-.*")
50
51
52-def getTestName(test):
53+def get_test_name(test):
54 """Get the test name of a failed test.
55
56 If the test is part of a numbered story,
57@@ -36,44 +52,45 @@
58 return test
59
60
61-def extractTests(input_file):
62- """Get the set of tests to be run.
63-
64- Given a file object for a test summary report, find all of the tests to be
65- run.
66- """
67- failed_tests = set()
68- reading_tests = False
69- for line in input_file:
70- if line.startswith('Tests with failures:'):
71- reading_tests = True
72- continue
73- if reading_tests:
74- if line.startswith('Total:'):
75- break
76- test = getTestName(line.strip())
77- failed_tests.add(test)
78- return failed_tests
79+def gen_test_lines(lines):
80+ def p_start(line):
81+ return line.startswith('Tests with failures:')
82+ def p_take(line):
83+ return not line.startswith('Total:')
84+ lines = iter(lines)
85+ for line in lines:
86+ if p_start(line):
87+ for line in takewhile(p_take, lines):
88+ yield line
89+
90+
91+def gen_tests(test_lines):
92+ for test_line in test_lines:
93+ yield get_test_name(test_line.strip())
94+
95+
96+def extract_tests(lines):
97+ return set(gen_tests(gen_test_lines(lines)))
98
99
100 def run_tests(tests):
101 """Given a set of tests, run them as one group."""
102- cmd = ['bin/test', '-vv']
103 print "Running tests:"
104- pprint(sorted(list(tests)))
105+ pprint(sorted(tests))
106+ args = ['-vv']
107 for test in tests:
108- cmd.append('-t')
109- cmd.append(test)
110- p = subprocess.Popen(cmd)
111- p.wait()
112+ args.append('-t')
113+ args.append(test)
114+ os.execl(TEST, TEST, *args)
115
116
117 if __name__ == '__main__':
118- try:
119- log_file = sys.argv[1]
120- except IndexError:
121- print "Usage: %s test_output_file" % (sys.argv[0])
122- sys.exit(-1)
123- fd = open(log_file, 'r')
124- failed_tests = extractTests(fd)
125- run_tests(failed_tests)
126+ tests = extract_tests(fileinput.input())
127+ if len(tests) >= 1:
128+ run_tests(tests)
129+ else:
130+ sys.stdout.write(
131+ "Error: no tests found\n"
132+ "Usage: %s [test_output_file|-] ...\n\n%s\n\n" % (
133+ sys.argv[0], __doc__.strip()))
134+ sys.exit(1)