Merge lp:~bac/testrepository/bug-949950-2 into lp:~testrepository/testrepository/trunk

Proposed by Brad Crittenden on 2012-04-17
Status: Merged
Merged at revision: 147
Proposed branch: lp:~bac/testrepository/bug-949950-2
Merge into: lp:~testrepository/testrepository/trunk
Diff against target: 298 lines (+85/-29)
5 files modified
testrepository/commands/load.py (+8/-7)
testrepository/commands/run.py (+9/-8)
testrepository/tests/test_ui.py (+36/-5)
testrepository/tests/ui/test_cli.py (+16/-6)
testrepository/ui/cli.py (+16/-3)
To merge this branch: bzr merge lp:~bac/testrepository/bug-949950-2
Reviewer Review Type Date Requested Status
Jonathan Lange 2012-04-17 Approve on 2012-04-18
Review via email: mp+102383@code.launchpad.net

Description of the Change

As requested, a '--subunit' option was added to the run command to get results in subunit format.

The change to test_cli.py was required or 'make_results' was unhappy due to not having an 'options' attribute, so the tests were made more robust.

In response to a previous review, moved the TestResultFilter into the UI 'make_results' method and added a '--full-results' option to not do any filtering. The default is to filter as before.

To post a comment you must log in.
Jonathan Lange (jml) wrote :

Hi Brad,

Thanks for the changes, it really makes a difference.

I've tweaked the tests to test behaviour rather than return type (http://paste.ubuntu.com/935581/). Other than that, is good to land as-is. Will do so now.

jml

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'testrepository/commands/load.py'
2--- testrepository/commands/load.py 2011-11-03 15:09:02 +0000
3+++ testrepository/commands/load.py 2012-04-17 20:38:17 +0000
4@@ -21,7 +21,6 @@
5
6 from testrepository.commands import Command
7 from testrepository.repository import RepositoryNotFound
8-from testrepository.results import TestResultFilter
9
10
11 class load(Command):
12@@ -42,6 +41,10 @@
13 "--force-init", action="store_true",
14 default=False,
15 help="Initialise the repository if it does not exist already"),
16+ optparse.Option("--subunit", action="store_true",
17+ default=False, help="Display results in subunit format."),
18+ optparse.Option("--full-results", action="store_true",
19+ default=False, help="Show all test results."),
20 ]
21
22 def run(self):
23@@ -69,16 +72,14 @@
24 except KeyError:
25 previous_run = None
26 output_result = self.ui.make_result(lambda: run_id, previous_run)
27- # XXX: We want to *count* skips, but not show them.
28- filtered = TestResultFilter(output_result, filter_skip=False)
29- filtered.startTestRun()
30+ output_result.startTestRun()
31 inserter.startTestRun()
32 try:
33- case.run(MultiTestResult(inserter, filtered))
34+ case.run(MultiTestResult(inserter, output_result))
35 finally:
36 run_id = inserter.stopTestRun()
37- filtered.stopTestRun()
38- if not filtered.wasSuccessful():
39+ output_result.stopTestRun()
40+ if not output_result.wasSuccessful():
41 return 1
42 else:
43 return 0
44
45=== modified file 'testrepository/commands/run.py'
46--- testrepository/commands/run.py 2010-12-19 09:17:29 +0000
47+++ testrepository/commands/run.py 2012-04-17 20:38:17 +0000
48@@ -1,11 +1,11 @@
49 #
50-# Copyright (c) 2010 Testrepository Contributors
51-#
52+# Copyright (c) 2010-2012 Testrepository Contributors
53+#
54 # Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
55 # license at the users choice. A copy of both licenses are available in the
56 # project source as Apache-2.0 and BSD. You may not use this file except in
57 # compliance with one of these two licences.
58-#
59+#
60 # Unless required by applicable law or agreed to in writing, software
61 # distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
62 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
63@@ -14,11 +14,7 @@
64
65 """Run a projects tests and load them into testrepository."""
66
67-import ConfigParser
68-from cStringIO import StringIO
69 import optparse
70-import os.path
71-import string
72
73 from testtools import TestResult
74
75@@ -39,7 +35,12 @@
76 optparse.Option("--parallel", action="store_true",
77 default=False, help="Run tests in parallel processes."),
78 optparse.Option("--partial", action="store_true",
79- default=False, help="Only some tests will be run. Implied by --failing."),
80+ default=False,
81+ help="Only some tests will be run. Implied by --failing."),
82+ optparse.Option("--subunit", action="store_true",
83+ default=False, help="Display results in subunit format."),
84+ optparse.Option("--full-results", action="store_true",
85+ default=False, help="Show all test results."),
86 ]
87 args = [StringArgument('testargs', 0, None)]
88 # Can be assigned to to inject a custom command factory.
89
90=== modified file 'testrepository/tests/test_ui.py'
91--- testrepository/tests/test_ui.py 2011-11-02 19:27:08 +0000
92+++ testrepository/tests/test_ui.py 2012-04-17 20:38:17 +0000
93@@ -1,11 +1,11 @@
94 #
95 # Copyright (c) 2009, 2010 Testrepository Contributors
96-#
97+#
98 # Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
99 # license at the users choice. A copy of both licenses are available in the
100 # project source as Apache-2.0 and BSD. You may not use this file except in
101 # compliance with one of these two licences.
102-#
103+#
104 # Unless required by applicable law or agreed to in writing, software
105 # distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
106 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
107@@ -17,15 +17,18 @@
108 from cStringIO import StringIO
109 import optparse
110 import subprocess
111+import subunit
112 import sys
113
114 from testtools.matchers import raises
115
116 from testrepository import arguments, commands
117 from testrepository.commands import load
118+from testrepository.commands.run import run
119 from testrepository.repository import memory
120+from testrepository.results import TestResultFilter
121+from testrepository.tests import ResourcedTestCase
122 from testrepository.ui import cli, decorator, model
123-from testrepository.tests import ResourcedTestCase
124
125
126 def cli_ui_factory(input_streams=None, options=(), args=()):
127@@ -119,7 +122,7 @@
128 # output_table shows a table.
129 ui = self.get_test_ui()
130 ui.output_table([('col1', 'col2'), ('row1c1','row1c2')])
131-
132+
133 def test_output_tests(self):
134 # output_tests can be called, and takes a list of tests to output.
135 ui = self.get_test_ui()
136@@ -228,7 +231,35 @@
137 # make_result can take a previous run.
138 ui = self.ui_factory()
139 ui.set_command(commands.Command(ui))
140- result = ui.make_result(lambda: None, memory.Repository().get_failing())
141+ result = ui.make_result(
142+ lambda: None, memory.Repository().get_failing())
143 result.startTestRun()
144 result.stopTestRun()
145 self.assertEqual(0, result.testsRun)
146+
147+
148+class TestCLIUISpecific(ResourcedTestCase):
149+
150+ def test_run_subunit_option(self):
151+ ui = cli_ui_factory(options=[('subunit', True)])
152+ ui.set_command(run)
153+ self.assertEqual(True, ui.options.subunit)
154+
155+ def test_check_result_output_filtered(self):
156+ ui = cli_ui_factory(
157+ options=[
158+ ('subunit', True),
159+ ])
160+ ui.set_command(run)
161+ result = ui.make_result(lambda: None)
162+ self.assertTrue(isinstance(result, TestResultFilter))
163+
164+ def test_check_result_output_unfiltered(self):
165+ ui = cli_ui_factory(
166+ options=[
167+ ('subunit', True),
168+ ('full-results', True),
169+ ])
170+ ui.set_command(run)
171+ result = ui.make_result(lambda: None)
172+ self.assertTrue(isinstance(result, subunit.TestProtocolClient))
173
174=== modified file 'testrepository/tests/ui/test_cli.py'
175--- testrepository/tests/ui/test_cli.py 2012-04-02 12:14:26 +0000
176+++ testrepository/tests/ui/test_cli.py 2012-04-17 20:38:17 +0000
177@@ -17,6 +17,7 @@
178
179 import doctest
180 from cStringIO import StringIO
181+import optparse
182 import sys
183
184 from testtools import TestCase
185@@ -230,10 +231,19 @@
186 except ZeroDivisionError:
187 return sys.exc_info()
188
189- def make_result(self, stream=None):
190+ def make_result(self, stream=None, fullresults=False):
191 if stream is None:
192 stream = StringIO()
193- ui = cli.UI([], None, stream, None)
194+ argv = []
195+ if fullresults:
196+ argv.append('--full-results')
197+ ui = cli.UI(argv, None, stream, None)
198+ cmd = commands.Command(ui)
199+ if fullresults:
200+ cmd.options = [optparse.Option(
201+ "--full-results", action="store_true", default=False,
202+ help="Show full results.")]
203+ ui.set_command(cmd)
204 return ui.make_result(lambda: None)
205
206 def test_initial_stream(self):
207@@ -247,7 +257,7 @@
208 # CLITestResult formats errors by giving them a big fat line, a title
209 # made up of their 'label' and the name of the test, another different
210 # big fat line, and then the actual error itself.
211- result = self.make_result()
212+ result = self.make_result(fullresults=True)
213 error = result._format_error('label', self, 'error text')
214 expected = '%s%s: %s\n%s%s' % (
215 result.sep1, 'label', self.id(), result.sep2, 'error text')
216@@ -257,7 +267,7 @@
217 # CLITestResult.addError outputs the given error immediately to the
218 # stream.
219 stream = StringIO()
220- result = self.make_result(stream)
221+ result = self.make_result(stream, fullresults=True)
222 error = self.make_exc_info()
223 error_text = result._err_details_to_string(self, error)
224 result.addError(self, error)
225@@ -269,7 +279,7 @@
226 # CLITestResult.addFailure outputs the given error immediately to the
227 # stream.
228 stream = StringIO()
229- result = self.make_result(stream)
230+ result = self.make_result(stream, fullresults=True)
231 error = self.make_exc_info()
232 error_text = result._err_details_to_string(self, error)
233 result.addFailure(self, error)
234@@ -281,7 +291,7 @@
235 # CLITestResult.addFailure outputs the given error handling non-ascii
236 # characters.
237 stream = StringIO()
238- result = self.make_result(stream)
239+ result = self.make_result(stream, fullresults=True)
240 class MyError(ValueError):
241 def __unicode__(self):
242 return u'\u201c'
243
244=== modified file 'testrepository/ui/cli.py'
245--- testrepository/ui/cli.py 2012-03-29 10:58:30 +0000
246+++ testrepository/ui/cli.py 2012-04-17 20:38:17 +0000
247@@ -17,11 +17,13 @@
248 from optparse import OptionParser
249 import os
250 import signal
251+import subunit
252 import sys
253
254 from testtools.compat import unicode_output_stream
255
256 from testrepository import ui
257+from testrepository.results import TestResultFilter
258
259
260 class CLITestResult(ui.BaseUITestResult):
261@@ -71,7 +73,16 @@
262 yield self._stdin
263
264 def make_result(self, get_id, previous_run=None):
265- return CLITestResult(self, get_id, self._stdout, previous_run)
266+ if getattr(self.options, 'subunit', False):
267+ results = subunit.TestProtocolClient(self._stdout)
268+ else:
269+ results = CLITestResult(self, get_id, self._stdout, previous_run)
270+
271+ if not getattr(self.options, 'full_results', False):
272+ # XXX: We want to *count* skips, but not show them.
273+ filtered = TestResultFilter(results, filter_skip=False)
274+ return filtered
275+ return results
276
277 def output_error(self, error_tuple):
278 self._stderr.write(str(error_tuple[1]) + '\n')
279@@ -136,7 +147,8 @@
280 outputs.append('%s=%s' % (label, value))
281 self._stdout.write('%s\n' % ', '.join(outputs))
282
283- def _format_summary(self, successful, tests, tests_delta, time, time_delta, values):
284+ def _format_summary(self, successful, tests, tests_delta,
285+ time, time_delta, values):
286 # We build the string by appending to a list of strings and then
287 # joining trivially at the end. Avoids expensive string concatenation.
288 summary = []
289@@ -170,7 +182,8 @@
290 a(')')
291 return ''.join(summary)
292
293- def output_summary(self, successful, tests, tests_delta, time, time_delta, values):
294+ def output_summary(self, successful, tests, tests_delta,
295+ time, time_delta, values):
296 self._stdout.write(
297 self._format_summary(
298 successful, tests, tests_delta, time, time_delta, values))

Subscribers

People subscribed via source and target branches