Merge lp:~dobey/ubuntuone-dev-tools/trial-args into lp:ubuntuone-dev-tools
- trial-args
- Merge into trunk
Proposed by
dobey
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Roberto Alsina | ||||
Approved revision: | 51 | ||||
Merged at revision: | 48 | ||||
Proposed branch: | lp:~dobey/ubuntuone-dev-tools/trial-args | ||||
Merge into: | lp:ubuntuone-dev-tools | ||||
Diff against target: |
399 lines (+149/-90) 6 files modified
bin/u1lint (+2/-2) bin/u1trial (+140/-84) run-tests (+3/-2) ubuntuone/devtools/reactors/glib.py (+1/-1) ubuntuone/devtools/reactors/qt4.py (+1/-1) ubuntuone/devtools/services/tests/test_dbus.py (+2/-0) |
||||
To merge this branch: | bzr merge lp:~dobey/ubuntuone-dev-tools/trial-args | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roberto Alsina (community) | Approve | ||
Sidnei da Silva (community) | Approve | ||
Review via email: mp+82758@code.launchpad.net |
Commit message
Use the Options handling API of trial so unhandled options get passed through
Fix some style issues
Make test_dbus work with --loop argument
Description of the change
To post a comment you must log in.
Revision history for this message
dobey (dobey) wrote : | # |
On Mon, 2011-11-21 at 19:37 +0000, Sidnei da Silva wrote:
> 2. Does help-reactors need to be overriden? Seems like trial already implements it.
Typo fixed. And yes, we need to override it, as we support some reactors
which are not installed in the twisted directory, as well as needing to
do some additional work on top of just importing them, for running some
tests that poke at the UI. I would be very happy to not have to
implement the reactor bits here, but for now we have to. :)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/u1lint' |
2 | --- bin/u1lint 2011-11-10 20:32:35 +0000 |
3 | +++ bin/u1lint 2011-11-21 20:08:24 +0000 |
4 | @@ -4,7 +4,7 @@ |
5 | # |
6 | # Author: Rodney Dawes <rodney.dawes@canonical.com> |
7 | # |
8 | -# Copyright 2009-2010 Canonical Ltd. |
9 | +# Copyright 2009-2011 Canonical Ltd. |
10 | # |
11 | # This program is free software: you can redistribute it and/or modify it |
12 | # under the terms of the GNU General Public License version 3, as published |
13 | @@ -209,7 +209,7 @@ |
14 | else: |
15 | pylint_args = get_subprocess_start_info('pylint') |
16 | # append the extra args to the start info |
17 | - pylint_args.extend(['--output-format=parseable', |
18 | + pylint_args.extend(['--output-format=parseable', |
19 | '--include-ids=yes']) |
20 | if PYLINTRC: |
21 | pylint_args.append("--rcfile=" + PYLINTRC) |
22 | |
23 | === modified file 'bin/u1trial' |
24 | --- bin/u1trial 2011-10-24 15:55:17 +0000 |
25 | +++ bin/u1trial 2011-11-21 20:08:24 +0000 |
26 | @@ -4,7 +4,7 @@ |
27 | # |
28 | # Author: Rodney Dawes <rodney.dawes@canonical.com> |
29 | # |
30 | -# Copyright 2009-2010 Canonical Ltd. |
31 | +# Copyright 2009-2011 Canonical Ltd. |
32 | # |
33 | # This program is free software: you can redistribute it and/or modify it |
34 | # under the terms of the GNU General Public License version 3, as published |
35 | @@ -28,12 +28,15 @@ |
36 | import sys |
37 | import unittest |
38 | |
39 | +from twisted.python.usage import UsageError |
40 | +from twisted.scripts import trial |
41 | from twisted.trial.runner import TrialRunner |
42 | |
43 | sys.path.insert(0, os.path.abspath(".")) |
44 | |
45 | from ubuntuone.devtools.testing.txcheck import TXCheckSuite |
46 | |
47 | + |
48 | def _is_in_ignored_path(testcase, paths): |
49 | """Return if the testcase is in one of the ignored paths.""" |
50 | for ignored_path in paths: |
51 | @@ -45,12 +48,10 @@ |
52 | class TestRunner(TrialRunner): |
53 | """The test runner implementation.""" |
54 | |
55 | - def __init__(self, force_gc=False): |
56 | - from twisted.trial.reporter import TreeReporter |
57 | - |
58 | + def __init__(self, config=None): |
59 | # set $HOME to the _trial_temp dir, to avoid breaking user files |
60 | trial_temp_dir = os.environ.get('TRIAL_TEMP_DIR', os.getcwd()) |
61 | - homedir = os.path.join(trial_temp_dir, '_trial_temp') |
62 | + homedir = os.path.join(trial_temp_dir, config['temp-directory']) |
63 | os.environ['HOME'] = homedir |
64 | |
65 | # setup $XDG_*_HOME variables and create the directories |
66 | @@ -71,12 +72,29 @@ |
67 | # setup the ROOTDIR env var |
68 | os.environ['ROOTDIR'] = os.getcwd() |
69 | |
70 | + # Need an attribute for tempdir so we can use it later |
71 | self.tempdir = homedir |
72 | - working_dir = os.path.join(self.tempdir, 'tmp') |
73 | - super(TestRunner, self).__init__(reporterFactory=TreeReporter, |
74 | - realTimeErrors=True, |
75 | - workingDirectory=working_dir, |
76 | - forceGarbageCollection=force_gc) |
77 | + working_dir = os.path.join(self.tempdir, 'trial') |
78 | + |
79 | + # Handle running trial in debug or dry-run mode |
80 | + mode = None |
81 | + if config['debug']: |
82 | + mode = TrialRunner.DEBUG |
83 | + if config['dry-run']: |
84 | + mode = TrialRunner.DRY_RUN |
85 | + |
86 | + # Hook up to the parent test runner |
87 | + super(TestRunner, self).__init__( |
88 | + reporterFactory=config['reporter'], |
89 | + mode=mode, |
90 | + profile=config['profile'], |
91 | + logfile=config['logfile'], |
92 | + tracebackFormat=config['tbformat'], |
93 | + realTimeErrors=config['rterrors'], |
94 | + uncleanWarnings=config['unclean-warnings'], |
95 | + workingDirectory=working_dir, |
96 | + forceGarbageCollection=config['force-gc']) |
97 | + |
98 | self.required_services = [] |
99 | self.source_files = [] |
100 | |
101 | @@ -117,18 +135,6 @@ |
102 | pattern = re.compile('.*%s.*' % test_pattern) |
103 | else: |
104 | pattern = None |
105 | - |
106 | - # get the ignored modules/tests |
107 | - if ignored_modules: |
108 | - ignored_modules = map(str.strip, ignored_modules.split(',')) |
109 | - else: |
110 | - ignored_modules = [] |
111 | - |
112 | - # get the ignored paths |
113 | - if ignored_paths: |
114 | - ignored_paths = map(str.strip, ignored_paths.split(',')) |
115 | - else: |
116 | - ignored_paths = [] |
117 | |
118 | # Disable this lint warning as we need to access _tests in the |
119 | # test suites, to collect the tests |
120 | @@ -169,100 +175,150 @@ |
121 | suite.addTests(module_suite) |
122 | return suite |
123 | |
124 | - # pylint: disable=E0202 |
125 | - def run(self, args, options=None): |
126 | + def get_suite(self, config): |
127 | + """Get the test suite to use.""" |
128 | + suite = unittest.TestSuite() |
129 | + for path in config['tests']: |
130 | + suite.addTest(self._collect_tests(path, config['test'], |
131 | + config['ignore-modules'], |
132 | + config['ignore-paths'])) |
133 | + if config['loop']: |
134 | + old_suite = suite |
135 | + suite = unittest.TestSuite() |
136 | + for _ in xrange(config['loop']): |
137 | + suite.addTest(old_suite) |
138 | + |
139 | + return suite |
140 | + |
141 | + # pylint: disable=C0103 |
142 | + def _runWithoutDecoration(self, test): |
143 | """run the tests.""" |
144 | - success = 0 |
145 | + result = None |
146 | running_services = [] |
147 | - if options.coverage: |
148 | - coverage.erase() |
149 | - coverage.start() |
150 | |
151 | try: |
152 | - suite = unittest.TestSuite() |
153 | - for path in args: |
154 | - print "Adding path" |
155 | - suite.addTest(self._collect_tests(path, options.test, |
156 | - options.ignored_modules, |
157 | - options.ignored_paths)) |
158 | - if options.loops: |
159 | - old_suite = suite |
160 | - suite = unittest.TestSuite() |
161 | - for _ in xrange(options.loops): |
162 | - suite.addTest(old_suite) |
163 | - |
164 | # Start any required services |
165 | for service in self.required_services: |
166 | runner = service() |
167 | runner.start_service(tempdir=self.tempdir) |
168 | running_services.append(runner) |
169 | |
170 | - result = super(TestRunner, self).run(suite) |
171 | - success = result.wasSuccessful() |
172 | + result = super(TestRunner, self)._runWithoutDecoration(test) |
173 | finally: |
174 | # Stop all the running services |
175 | for runner in running_services: |
176 | runner.stop_service() |
177 | |
178 | - if options.coverage: |
179 | - coverage.stop() |
180 | - coverage.report(self.source_files, ignore_errors=True, |
181 | - show_missing=False) |
182 | - |
183 | - if not success: |
184 | - sys.exit(1) |
185 | - else: |
186 | - sys.exit(0) |
187 | + return result |
188 | + |
189 | + |
190 | +class Options(trial.Options): |
191 | + """Class for options handling.""" |
192 | + |
193 | + optFlags = [["coverage", "c"], |
194 | + ["gui", None], |
195 | + ["help-reactors", None], |
196 | + ] |
197 | + |
198 | + optParameters = [["test", "t", None], |
199 | + ["loop", None, 1], |
200 | + ["ignore-modules", "i", ""], |
201 | + ["ignore-paths", "p", ""], |
202 | + ["reactor", "r", "glib"], |
203 | + ] |
204 | + |
205 | + def __init__(self): |
206 | + self['tests'] = set() |
207 | + super(Options, self).__init__() |
208 | + self['rterrors'] = True |
209 | + |
210 | + def opt_coverage(self): |
211 | + """Generate a coverage report for the run tests""" |
212 | + self['coverage'] = True |
213 | + |
214 | + def opt_gui(self): |
215 | + """Use the GUI mode of some reactors""" |
216 | + self['gui'] = True |
217 | + |
218 | + def opt_help_reactors(self): |
219 | + """Help on available reactors for use with tests""" |
220 | + synopsis = ('') |
221 | + print synopsis |
222 | + print 'Need to get list of reactors and print them here.' |
223 | |
224 | + sys.exit(0) |
225 | + |
226 | + def opt_test(self, option): |
227 | + """Run specific tests, e.g: className.methodName""" |
228 | + self['test'] = option |
229 | + |
230 | + def opt_loop(self, option): |
231 | + """Loop tests the specified number of times.""" |
232 | + try: |
233 | + self['loop'] = long(option) |
234 | + except ValueError: |
235 | + raise UsageError('A positive integer value must be specified.') |
236 | + |
237 | + def opt_ignore_modules(self, option): |
238 | + """Comma-separate list of test modules to ignore, |
239 | + e.g: test_gtk.py, test_account.py |
240 | + """ |
241 | + self['ignore-modules'] = map(str.strip, option.split(',')) |
242 | + |
243 | + def opt_ignore_paths(self, option): |
244 | + """Comma-separated list of relative paths to ignore, |
245 | + e.g: tests/platform/windows, tests/platform/macosx |
246 | + """ |
247 | + self['ignore-paths'] = map(str.strip, option.split(',')) |
248 | + |
249 | + def opt_reactor(self, option): |
250 | + """Which reactor to use (see --help-reactors for a list |
251 | + of possibilities) |
252 | + """ |
253 | + self['reactor'] = option |
254 | + opt_r = opt_reactor |
255 | |
256 | |
257 | def main(): |
258 | """Do the deed.""" |
259 | - from optparse import OptionParser |
260 | - usage = '%prog [options] path' |
261 | - parser = OptionParser(usage=usage) |
262 | - parser.add_option("-t", "--test", dest="test", |
263 | - help = "run specific tests, e.g: className.methodName") |
264 | - parser.add_option("-l", "--loop", dest="loops", type="int", default=1, |
265 | - help = "loop selected tests LOOPS number of times", |
266 | - metavar="LOOPS") |
267 | - parser.add_option("-c", "--coverage", action="store_true", dest="coverage", |
268 | - help="print a coverage report when finished") |
269 | - parser.add_option("-i", "--ignored-modules", dest="ignored_modules", |
270 | - default=None, help="comma-separated test moodules " |
271 | - + "to ignore, e.g: test_gtk.py, test_account.py") |
272 | - parser.add_option("-p", "--ignore-paths", dest="ignored_paths", |
273 | - default=None, help="comma-separated relative " |
274 | - + "paths to ignore. " |
275 | - + "e.g: tests/platform/windows, tests/platform/macosx") |
276 | - parser.add_option("--force-gc", action="store_true", dest="force_gc", |
277 | - default=False, help="Run gc.collect() before and after " |
278 | - "each test case.") |
279 | - parser.add_option("--reactor", type="string", dest="reactor", |
280 | - default='glib', |
281 | - help="Run the tests using the specified reactor.", |
282 | - metavar="REACTOR") |
283 | - parser.add_option("--gui", action="store_true", dest="use_gui", |
284 | - help="Use the GUI mode of some reactors.") |
285 | - (options, args) = parser.parse_args() |
286 | - if not args: |
287 | - parser.print_help() |
288 | - sys.exit(2) |
289 | + if len(sys.argv) == 1: |
290 | + sys.argv.append('--help') |
291 | + |
292 | + config = Options() |
293 | + config.parseOptions() |
294 | |
295 | try: |
296 | - reactor_name = 'ubuntuone.devtools.reactors.%s' % options.reactor |
297 | + reactor_name = 'ubuntuone.devtools.reactors.%s' % config['reactor'] |
298 | reactor = __import__(reactor_name, None, None, ['']) |
299 | except ImportError: |
300 | print 'The specified reactor is not supported.' |
301 | sys.exit(1) |
302 | else: |
303 | try: |
304 | - reactor.install(options=options) |
305 | + reactor.install(options=config) |
306 | except ImportError: |
307 | print('The Python package providing the requested reactor is not ' |
308 | 'installed. You can find it here: %s' % reactor.REACTOR_URL) |
309 | raise |
310 | |
311 | - TestRunner(force_gc=options.force_gc).run(args, options) |
312 | + trial_runner = TestRunner(config=config) |
313 | + suite = trial_runner.get_suite(config) |
314 | + |
315 | + if config['coverage']: |
316 | + coverage.erase() |
317 | + coverage.start() |
318 | + |
319 | + if config['until-failure']: |
320 | + result = trial_runner.runUntilFailure(suite) |
321 | + else: |
322 | + result = trial_runner.run(suite) |
323 | + |
324 | + if config['coverage']: |
325 | + coverage.stop() |
326 | + coverage.report(trial_runner.source_files, ignore_errors=True, |
327 | + show_missing=False) |
328 | + |
329 | + sys.exit(not result.wasSuccessful()) |
330 | |
331 | |
332 | if __name__ == '__main__': |
333 | |
334 | === modified file 'run-tests' |
335 | --- run-tests 2011-05-26 15:49:41 +0000 |
336 | +++ run-tests 2011-11-21 20:08:24 +0000 |
337 | @@ -1,7 +1,7 @@ |
338 | #!/bin/bash |
339 | # Author: Natalia Bidart <natalia.bidart@canonical.com> |
340 | # |
341 | -# Copyright 2010 Canonical Ltd. |
342 | +# Copyright 2010-2011 Canonical Ltd. |
343 | # |
344 | # This program is free software: you can redistribute it and/or modify it |
345 | # under the terms of the GNU General Public License version 3, as published |
346 | @@ -18,7 +18,8 @@ |
347 | |
348 | bin/u1trial -c ubuntuone |
349 | bin/u1trial --reactor=twisted ubuntuone |
350 | +echo "Running style checks..." |
351 | bin/u1lint |
352 | -pep8 --repeat . |
353 | +pep8 --repeat . bin/* |
354 | rm -rf _trial_temp |
355 | rm -rf .coverage |
356 | |
357 | === modified file 'ubuntuone/devtools/reactors/glib.py' |
358 | --- ubuntuone/devtools/reactors/glib.py 2011-05-26 15:49:41 +0000 |
359 | +++ ubuntuone/devtools/reactors/glib.py 2011-11-21 20:08:24 +0000 |
360 | @@ -17,7 +17,7 @@ |
361 | def install(options=None): |
362 | """Install the reactor and parse any options we might need.""" |
363 | reactor_name = None |
364 | - if options is not None and options.use_gui: |
365 | + if options is not None and options['gui']: |
366 | reactor_name = 'twisted.internet.gtk2reactor' |
367 | else: |
368 | reactor_name = 'twisted.internet.glib2reactor' |
369 | |
370 | === modified file 'ubuntuone/devtools/reactors/qt4.py' |
371 | --- ubuntuone/devtools/reactors/qt4.py 2011-11-11 13:31:18 +0000 |
372 | +++ ubuntuone/devtools/reactors/qt4.py 2011-11-21 20:08:24 +0000 |
373 | @@ -22,7 +22,7 @@ |
374 | |
375 | def install(options=None): |
376 | """Install the reactor and parse any options we might need.""" |
377 | - if options is not None and options.use_gui: |
378 | + if options is not None and options['gui']: |
379 | from PyQt4.QtGui import QApplication |
380 | # We must assign this to a variable, or we will get crashes in Qt |
381 | # pylint: disable=W0612 |
382 | |
383 | === modified file 'ubuntuone/devtools/services/tests/test_dbus.py' |
384 | --- ubuntuone/devtools/services/tests/test_dbus.py 2011-02-03 14:32:01 +0000 |
385 | +++ ubuntuone/devtools/services/tests/test_dbus.py 2011-11-21 20:08:24 +0000 |
386 | @@ -1,6 +1,7 @@ |
387 | """Tests for the test runner.""" |
388 | |
389 | import os |
390 | +import shutil |
391 | |
392 | from ubuntuone.devtools.testcase import DBusTestCase |
393 | from ubuntuone.devtools.services.dbus import DBusRunner |
394 | @@ -25,4 +26,5 @@ |
395 | # pylint: disable=W0212 |
396 | os.makedirs(self.tmpdir) |
397 | runner._find_config_file(tempdir=self.tmpdir) |
398 | + shutil.rmtree(self.tmpdir) |
399 | self.assertEqual(expected, runner.config_file) |
1. Typo at 'Need to et list of reactors and print them here.'
2. Does help-reactors need to be overriden? Seems like trial already implements it.
Other than that that, +1!