Merge lp:~thomir-deactivatedaccount/autopilot/add-launch-command-args into lp:~thomir-deactivatedaccount/autopilot/split-tests

Proposed by Thomi Richards
Status: Superseded
Proposed branch: lp:~thomir-deactivatedaccount/autopilot/add-launch-command-args
Merge into: lp:~thomir-deactivatedaccount/autopilot/split-tests
Diff against target: 486 lines (+325/-86)
5 files modified
autopilot/__init__.py (+82/-0)
autopilot/tests/unit/test_command_line_args.py (+234/-0)
bin/autopilot (+2/-86)
debian/changelog (+6/-0)
debian/control (+1/-0)
To merge this branch: bzr merge lp:~thomir-deactivatedaccount/autopilot/add-launch-command-args
Reviewer Review Type Date Requested Status
Thomi Richards Pending
Review via email: mp+162682@code.launchpad.net

This proposal has been superseded by a proposal from 2013-05-06.

Commit message

Pass additional arguments to the 'launch' command to the application launched.

Description of the change

This branch fixes autopilot so you can run:

autopilot launch gnome-control-center credentials

and the "credentals" argument will be passed to the application launched. In order to do this, I moved the parse_arguments code into the autopilot module, and added a full suite of unit tests to ensure it works as we expect.

To post a comment you must log in.
201. By Thomi Richards

PEP8 fixes.

202. By Thomi Richards

merged trunk.

Unmerged revisions

202. By Thomi Richards

merged trunk.

201. By Thomi Richards

PEP8 fixes.

200. By Thomi Richards

autopilot launch command now passes remaining arguments to the application itself.

199. By Thomi Richards

Fully tested command line argument parsing code.

198. By Thomi Richards

command line args parser now accepts application arguments.

197. By Thomi Richards

Merged code that splits tests, since we're about to add more test.

196. By Thomi Richards

moved the code that specifies command line arguments into the autopilot module, so it can be tested properly.

195. By PS Jenkins bot

Releasing 1.3daily13.05.06ubuntu.unity.next-0ubuntu1 to ubuntu.

Approved by PS Jenkins bot.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'autopilot/__init__.py'
2--- autopilot/__init__.py 2013-04-23 04:15:54 +0000
3+++ autopilot/__init__.py 2013-05-06 23:30:33 +0000
4@@ -17,6 +17,7 @@
5 # along with this program. If not, see <http://www.gnu.org/licenses/>.
6 #
7
8+from argparse import ArgumentParser, REMAINDER
9
10 version = '1.3'
11
12@@ -31,3 +32,84 @@
13 + original_exception.message
14 )
15 self.original_exception = original_exception
16+
17+
18+def parse_arguments(argv=None):
19+ """Parse command-line arguments, and return an argparse arguments
20+ object.
21+ """
22+ parser = ArgumentParser(description="Autopilot test tool.")
23+ subparsers = parser.add_subparsers(help='Run modes', dest="mode")
24+
25+ parser_run = subparsers.add_parser('run', help="Run autopilot tests")
26+ parser_run.add_argument('-o', "--output", required=False,
27+ help='Write test result report to file.\
28+ Defaults to stdout.\
29+ If given a directory instead of a file will \
30+ write to a file in that directory named: \
31+ <hostname>_<dd.mm.yyy_HHMMSS>.log')
32+ parser_run.add_argument('-f', "--format", choices=['text', 'xml'],
33+ default='text',
34+ required=False,
35+ help='Specify desired output format. \
36+ Default is "text".')
37+ parser_run.add_argument('-r', '--record', action='store_true',
38+ default=False, required=False,
39+ help="Record failing tests. Required \
40+ 'recordmydesktop' app to be installed.\
41+ Videos are stored in /tmp/autopilot.")
42+ parser_run.add_argument("-rd", "--record-directory", required=False,
43+ default="/tmp/autopilot", type=str,
44+ help="Directory to put recorded tests \
45+ (only if -r) specified.")
46+ parser_run.add_argument('-v', '--verbose', default=False, required=False,
47+ action='count',
48+ help="If set, autopilot will output test log data \
49+ to stderr during a test run. Set twice to also log \
50+ data useful for debugging autopilot itself.")
51+ parser_run.add_argument("suite", nargs="+",
52+ help="Specify test suite(s) to run.")
53+
54+ parser_list = subparsers.add_parser('list', help="List autopilot tests")
55+ parser_list.add_argument("-ro", "--run-order", required=False, default=False,
56+ action="store_true",
57+ help="List tests in run order, rather than alphabetical \
58+ order (the default).")
59+ parser_list.add_argument("suite", nargs="+",
60+ help="Specify test suite(s) to run.")
61+
62+ if have_vis():
63+ parser_vis = subparsers.add_parser('vis',
64+ help="Open the Autopilot visualiser tool")
65+ parser_vis.add_argument('-v', '--verbose', required=False, default=False,
66+ action='count', help="Show autopilot log messages. \
67+ Set twice to also log data useful for debugging \
68+ autopilot itself.")
69+
70+ parser_launch = subparsers.add_parser('launch',
71+ help="Launch an application with introspection enabled")
72+ parser_launch.add_argument('-i', '--interface',
73+ choices=('Gtk', 'Qt', 'Auto'), default='Auto',
74+ help="Specify which introspection interface to load. \
75+ The default ('Auto') uses ldd to try and detect which \
76+ interface to load.")
77+ parser_launch.add_argument('-v', '--verbose', required=False, default=False,
78+ action='count', help="Show autopilot log messages. \
79+ Set twice to also log data useful for debugging \
80+ autopilot itself.")
81+ parser_launch.add_argument('application', nargs=REMAINDER, type=str,
82+ help="The application to launch. Can be a full path, \
83+ or just an application name (in which case Autopilot \
84+ will search for it in $PATH).")
85+ args = parser.parse_args(args=argv)
86+
87+ return args
88+
89+
90+def have_vis():
91+ """Return true if the vis package is installed."""
92+ try:
93+ from autopilot.vis import vis_main
94+ return True
95+ except ImportError:
96+ return False
97
98=== added file 'autopilot/tests/unit/test_command_line_args.py'
99--- autopilot/tests/unit/test_command_line_args.py 1970-01-01 00:00:00 +0000
100+++ autopilot/tests/unit/test_command_line_args.py 2013-05-06 23:30:33 +0000
101@@ -0,0 +1,234 @@
102+#!/usr/bin/env python
103+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
104+#
105+# Autopilot Functional Test Tool
106+# Copyright (C) 2012-2013 Canonical
107+#
108+# This program is free software: you can redistribute it and/or modify
109+# it under the terms of the GNU General Public License as published by
110+# the Free Software Foundation, either version 3 of the License, or
111+# (at your option) any later version.
112+#
113+# This program is distributed in the hope that it will be useful,
114+# but WITHOUT ANY WARRANTY; without even the implied warranty of
115+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
116+# GNU General Public License for more details.
117+#
118+# You should have received a copy of the GNU General Public License
119+# along with this program. If not, see <http://www.gnu.org/licenses/>.
120+#
121+
122+
123+"Unit tests for the command line parser in autopilot."
124+
125+
126+from mock import patch
127+from StringIO import StringIO
128+from testtools import TestCase
129+from testtools.matchers import Equals
130+from unittest import expectedFailure
131+
132+from autopilot import parse_arguments
133+
134+
135+class CommandLineArgsTests(TestCase):
136+
137+ def parse_args(self, args):
138+ if isinstance(args, basestring):
139+ args = args.split()
140+ try:
141+ return parse_arguments(args)
142+ except SystemExit as e:
143+ self.fail("Caught exception: %r" % e)
144+
145+ def test_launch_command_accepts_application(self):
146+ args = self.parse_args("launch app")
147+ self.assertThat(args.mode, Equals("launch"))
148+
149+ def test_launch_command_has_correct_default_interface(self):
150+ args = self.parse_args("launch app")
151+ self.assertThat(args.interface, Equals("Auto"))
152+
153+ def test_launch_command_can_specify_Qt_interface(self):
154+ args = self.parse_args("launch -i Qt app")
155+ self.assertThat(args.interface, Equals("Qt"))
156+
157+ def test_launch_command_can_specify_Gtk_interface(self):
158+ args = self.parse_args("launch -i Gtk app")
159+ self.assertThat(args.interface, Equals("Gtk"))
160+
161+ @patch('sys.stderr', new=StringIO())
162+ @expectedFailure
163+ def test_launch_command_fails_on_unknown_interface(self):
164+ self.parse_args("launch -i unknown app")
165+
166+ def test_launch_command_has_correct_default_verbosity(self):
167+ args = self.parse_args("launch app")
168+ self.assertThat(args.verbose, Equals(False))
169+
170+ def test_launch_command_can_specify_verbosity(self):
171+ args = self.parse_args("launch -v app")
172+ self.assertThat(args.verbose, Equals(1))
173+
174+ def test_launch_command_can_specify_extra_verbosity(self):
175+ args = self.parse_args("launch -vv app")
176+ self.assertThat(args.verbose, Equals(2))
177+ args = self.parse_args("launch -v -v app")
178+ self.assertThat(args.verbose, Equals(2))
179+
180+ def test_launch_command_stores_application(self):
181+ args = self.parse_args("launch app")
182+ self.assertThat(args.application, Equals(["app"]))
183+
184+ def test_launch_command_stores_application_with_args(self):
185+ args = self.parse_args("launch app arg1 arg2")
186+ self.assertThat(args.application, Equals(["app", "arg1", "arg2"]))
187+
188+ def test_launch_command_accepts_different_app_arg_formats(self):
189+ args = self.parse_args("launch app -s --long --key=val arg1 arg2")
190+ self.assertThat(args.application,
191+ Equals(["app", "-s", "--long", "--key=val", "arg1", "arg2"]))
192+
193+ @patch('autopilot.have_vis', new=lambda: True)
194+ def test_vis_present_when_vis_module_installed(self):
195+ args = self.parse_args('vis')
196+ self.assertThat(args.mode, Equals("vis"))
197+
198+ @patch('autopilot.have_vis', new=lambda: False)
199+ @patch('sys.stderr', new=StringIO())
200+ @expectedFailure
201+ def test_vis_not_present_when_vis_module_not_installed(self):
202+ self.parse_args('vis')
203+
204+ @patch('autopilot.have_vis', new=lambda: True)
205+ def test_vis_default_verbosity(self):
206+ args = self.parse_args('vis')
207+ self.assertThat(args.verbose, Equals(False))
208+
209+ @patch('autopilot.have_vis', new=lambda: True)
210+ def test_vis_single_verbosity(self):
211+ args = self.parse_args('vis -v')
212+ self.assertThat(args.verbose, Equals(1))
213+
214+ @patch('autopilot.have_vis', new=lambda: True)
215+ def test_vis_double_verbosity(self):
216+ args = self.parse_args('vis -vv')
217+ self.assertThat(args.verbose, Equals(2))
218+ args = self.parse_args('vis -v -v')
219+ self.assertThat(args.verbose, Equals(2))
220+
221+ def test_list_mode(self):
222+ args = self.parse_args('list foo')
223+ self.assertThat(args.mode, Equals("list"))
224+
225+ def test_list_mode_accepts_suite_name(self):
226+ args = self.parse_args('list foo')
227+ self.assertThat(args.suite, Equals(["foo"]))
228+
229+ def test_list_mode_accepts_many_suite_names(self):
230+ args = self.parse_args('list foo bar baz')
231+ self.assertThat(args.suite, Equals(["foo", "bar", "baz"]))
232+
233+ def test_list_run_order_long_option(self):
234+ args = self.parse_args('list --run-order foo')
235+ self.assertThat(args.run_order, Equals(True))
236+
237+ def test_list_run_order_short_option(self):
238+ args = self.parse_args('list -ro foo')
239+ self.assertThat(args.run_order, Equals(True))
240+
241+ def test_list_no_run_order(self):
242+ args = self.parse_args('list foo')
243+ self.assertThat(args.run_order, Equals(False))
244+
245+ def test_run_mode(self):
246+ args = self.parse_args('run foo')
247+ self.assertThat(args.mode, Equals("run"))
248+
249+ def test_run_mode_accepts_suite_name(self):
250+ args = self.parse_args('run foo')
251+ self.assertThat(args.suite, Equals(["foo"]))
252+
253+ def test_run_mode_accepts_many_suite_names(self):
254+ args = self.parse_args('run foo bar baz')
255+ self.assertThat(args.suite, Equals(["foo", "bar", "baz"]))
256+
257+ def test_run_command_default_output(self):
258+ args = self.parse_args('run foo')
259+ self.assertThat(args.output, Equals(None))
260+
261+ def test_run_command_path_output_short(self):
262+ args = self.parse_args('run -o /path/to/file foo')
263+ self.assertThat(args.output, Equals("/path/to/file"))
264+
265+ def test_run_command_path_output_long(self):
266+ args = self.parse_args('run --output ../file foo')
267+ self.assertThat(args.output, Equals("../file"))
268+
269+ def test_run_command_default_format(self):
270+ args = self.parse_args('run foo')
271+ self.assertThat(args.format, Equals("text"))
272+
273+ def test_run_command_text_format_short_version(self):
274+ args = self.parse_args('run -f text foo')
275+ self.assertThat(args.format, Equals("text"))
276+
277+ def test_run_command_text_format_long_version(self):
278+ args = self.parse_args('run --format text foo')
279+ self.assertThat(args.format, Equals("text"))
280+
281+ def test_run_command_xml_format_short_version(self):
282+ args = self.parse_args('run -f xml foo')
283+ self.assertThat(args.format, Equals("xml"))
284+
285+ def test_run_command_xml_format_long_version(self):
286+ args = self.parse_args('run --format xml foo')
287+ self.assertThat(args.format, Equals("xml"))
288+
289+ @patch('sys.stderr', new=StringIO())
290+ @expectedFailure
291+ def test_run_command_unknown_format_short_version(self):
292+ self.parse_args('run -f unknown foo')
293+
294+ @patch('sys.stderr', new=StringIO())
295+ @expectedFailure
296+ def test_run_command_unknown_format_long_version(self):
297+ self.parse_args('run --format unknown foo')
298+
299+ def test_run_command_record_flag_default(self):
300+ args = self.parse_args("run foo")
301+ self.assertThat(args.record, Equals(False))
302+
303+ def test_run_command_record_flag_short(self):
304+ args = self.parse_args("run -r foo")
305+ self.assertThat(args.record, Equals(True))
306+
307+ def test_run_command_record_flag_long(self):
308+ args = self.parse_args("run --record foo")
309+ self.assertThat(args.record, Equals(True))
310+
311+ def test_run_command_record_dir_flag_default(self):
312+ args = self.parse_args("run foo")
313+ self.assertThat(args.record_directory, Equals("/tmp/autopilot"))
314+
315+ def test_run_command_record_dir_flag_short(self):
316+ args = self.parse_args("run -rd /path/to/dir foo")
317+ self.assertThat(args.record_directory, Equals("/path/to/dir"))
318+
319+ def test_run_command_record_dir_flag_long(self):
320+ args = self.parse_args("run --record-directory /path/to/dir foo")
321+ self.assertThat(args.record_directory, Equals("/path/to/dir"))
322+
323+ def test_run_default_verbosity(self):
324+ args = self.parse_args('run foo')
325+ self.assertThat(args.verbose, Equals(False))
326+
327+ def test_run_single_verbosity(self):
328+ args = self.parse_args('run -v foo')
329+ self.assertThat(args.verbose, Equals(1))
330+
331+ def test_run_double_verbosity(self):
332+ args = self.parse_args('run -vv foo')
333+ self.assertThat(args.verbose, Equals(2))
334+ args = self.parse_args('run -v -v foo')
335+ self.assertThat(args.verbose, Equals(2))
336
337=== modified file 'bin/autopilot'
338--- bin/autopilot 2013-05-02 22:24:57 +0000
339+++ bin/autopilot 2013-05-06 23:30:33 +0000
340@@ -39,8 +39,6 @@
341 import subprocess
342 from testtools import iterate_tests
343 from testtools import TextTestResult
344-from textwrap import dedent
345-from argparse import ArgumentParser
346 from unittest.loader import TestLoader
347 from unittest import TestSuite
348
349@@ -48,80 +46,6 @@
350 _output_stream=None
351
352
353-def parse_arguments():
354- """Parse command-line arguments, and return an argparse arguments
355- object.
356- """
357- parser = ArgumentParser(description=dedent("""\
358- Autopilot test tool.
359- """))
360- subparsers = parser.add_subparsers(help='Run modes', dest="mode")
361-
362- parser_run = subparsers.add_parser('run', help="Run autopilot tests")
363- parser_run.add_argument('-o', "--output", required=False,
364- help='Write test result report to file.\
365- Defaults to stdout.\
366- If given a directory instead of a file will \
367- write to a file in that directory named: \
368- <hostname>_<dd.mm.yyy_HHMMSS>.log')
369- parser_run.add_argument('-f', "--format", choices=['text', 'xml'],
370- default='text',
371- required=False,
372- help='Specify desired output format. \
373- Default is "text".')
374- parser_run.add_argument('-r', '--record', action='store_true',
375- default=False, required=False,
376- help="Record failing tests. Required \
377- 'recordmydesktop' app to be installed.\
378- Videos are stored in /tmp/autopilot.")
379- parser_run.add_argument("-rd", "--record-directory", required=False,
380- default="/tmp/autopilot", type=str,
381- help="Directory to put recorded tests \
382- (only if -r) specified.")
383- parser_run.add_argument('-v', '--verbose', default=False, required=False,
384- action='count',
385- help="If set, autopilot will output test log data \
386- to stderr during a test run. Set twice to also log \
387- data useful for debugging autopilot itself.")
388- parser_run.add_argument("suite", nargs="+",
389- help="Specify test suite(s) to run.")
390-
391- parser_list = subparsers.add_parser('list', help="List autopilot tests")
392- parser_list.add_argument("-ro", "--run-order", required=False, default=False,
393- action="store_true",
394- help="List tests in run order, rather than alphabetical \
395- order (the default).")
396- parser_list.add_argument("suite", nargs="+",
397- help="Specify test suite(s) to run.")
398-
399- if have_vis():
400- parser_vis = subparsers.add_parser('vis',
401- help="Open the Autopilot visualiser tool")
402- parser_vis.add_argument('-v', '--verbose', required=False, default=False,
403- action='count', help="Show autopilot log messages. \
404- Set twice to also log data useful for debugging \
405- autopilot itself.")
406-
407- parser_launch = subparsers.add_parser('launch',
408- help="Launch an application with introspection enabled")
409- parser_launch.add_argument('-i', '--interface',
410- choices=('Gtk', 'Qt', 'Auto'), default='Auto',
411- help="Specify which introspection interface to load. \
412- The default ('Auto') uses ldd to try and detect which \
413- interface to load.")
414- parser_launch.add_argument('-v', '--verbose', required=False, default=False,
415- action='count', help="Show autopilot log messages. \
416- Set twice to also log data useful for debugging \
417- autopilot itself.")
418- parser_launch.add_argument('application', nargs=1, type=str,
419- help="The application to launch. Can be a full path, \
420- or just an application name (in which case Autopilot \
421- will search for it in $PATH).")
422- args = parser.parse_args()
423-
424- return args
425-
426-
427 def list_tests(args):
428 """Print a list of tests we find inside autopilot.tests."""
429 num_tests = 0
430@@ -341,21 +265,12 @@
431 exit(1)
432
433 try:
434- launch_application(launcher, app_name, capture_output=False)
435+ launch_application(launcher, *args.application, capture_output=False)
436 except RuntimeError as e:
437 print "Error: " + e.message
438 exit(1)
439
440
441-def have_vis():
442- """Return true if the vis package is installed."""
443- try:
444- from autopilot.vis import vis_main
445- return True
446- except ImportError:
447- return False
448-
449-
450 def run_vis(args):
451 setup_logging(args.verbose)
452 # importing this requires that DISPLAY is set. Since we don't always want
453@@ -374,6 +289,7 @@
454
455
456 def main():
457+ from autopilot import parse_arguments
458 args = parse_arguments()
459 if args.mode == 'list':
460 list_tests(args)
461
462=== modified file 'debian/changelog'
463--- debian/changelog 2013-05-03 00:01:17 +0000
464+++ debian/changelog 2013-05-06 23:30:33 +0000
465@@ -1,3 +1,9 @@
466+autopilot (1.3daily13.05.06ubuntu.unity.next-0ubuntu1) raring; urgency=low
467+
468+ * Automatic snapshot from revision 194 (ubuntu-unity/next)
469+
470+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 06 May 2013 00:01:03 +0000
471+
472 autopilot (1.3daily13.05.03ubuntu.unity.next-0ubuntu1) raring; urgency=low
473
474 [ Thomi Richards ]
475
476=== modified file 'debian/control'
477--- debian/control 2013-05-05 21:22:50 +0000
478+++ debian/control 2013-05-06 23:30:33 +0000
479@@ -60,6 +60,7 @@
480 gir1.2-ibus-1.0,
481 python-autopilot,
482 python-xlib,
483+Recommends: python-autopilot-vis,
484 Description: Autopilot support for the ubuntu Desktop platform
485 This metapackage exists to depend on the packages needed to install and use
486 autopilot on the Ubuntu Desktop platform.

Subscribers

No one subscribed via source and target branches