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

Proposed by Thomi Richards
Status: Merged
Approved by: Thomi Richards
Approved revision: 202
Merged at revision: 199
Proposed branch: lp:~thomir-deactivatedaccount/autopilot/add-launch-command-args
Merge into: lp:autopilot
Diff against target: 460 lines (+318/-86)
3 files modified
autopilot/__init__.py (+82/-0)
autopilot/tests/unit/test_command_line_args.py (+234/-0)
bin/autopilot (+2/-86)
To merge this branch: bzr merge lp:~thomir-deactivatedaccount/autopilot/add-launch-command-args
Reviewer Review Type Date Requested Status
Thomi Richards (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+162684@code.launchpad.net

This proposal supersedes a proposal from 2013-05-06.

Commit message

Pass additional arguments to application being 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.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:202
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~thomir/autopilot/add-launch-command-args/+merge/162684/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/autopilot-ci/77/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-raring-amd64-ci/77
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-raring-armhf-ci/76
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-saucy-amd64-ci/5
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-saucy-armhf-ci/5

Click here to trigger a rebuild:
http://s-jenkins:8080/job/autopilot-ci/77/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) :
review: Approve

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:31:25 +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:31:25 +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:31:25 +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)

Subscribers

People subscribed via source and target branches