Merge lp:~nuclearbob/autopilot/launch-function into lp:~autopilot/autopilot/temp-dev
- launch-function
- Merge into temp-dev
Status: | Merged |
---|---|
Approved by: | Thomi Richards |
Approved revision: | 550 |
Merged at revision: | 517 |
Proposed branch: | lp:~nuclearbob/autopilot/launch-function |
Merge into: | lp:~autopilot/autopilot/temp-dev |
Diff against target: |
1274 lines (+661/-297) 11 files modified
autopilot/application/__init__.py (+1/-1) autopilot/application/_launcher.py (+216/-45) autopilot/testcase.py (+23/-71) autopilot/tests/acceptance/test_vis_main.py (+5/-34) autopilot/tests/functional/test_ap_apps.py (+9/-3) autopilot/tests/functional/test_application_mixin.py (+0/-22) autopilot/tests/unit/test_application_launcher.py (+323/-121) autopilot/tests/unit/test_testcase.py (+50/-0) debian/control (+1/-0) docs/api/autopilot.application.rst (+5/-0) docs/tutorial/advanced_autopilot.rst (+28/-0) |
To merge this branch: | bzr merge lp:~nuclearbob/autopilot/launch-function |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Thomi Richards (community) | Approve | ||
Max Brustkern (community) | Needs Resubmitting | ||
Review via email: mp+220094@code.launchpad.net |
Commit message
Add fixtures for launching applications
Description of the change
The work to enable app launch outside of the testcase class via fixtures is ongoing, but I'd like to get a report on whether my current changes have broken anything before proceeding further, so I'll get the gatekeeper kicked off and then make this work in progress.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:499
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:/
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Max Brustkern (nuclearbob) wrote : | # |
I'd like to get a review of everything except test_ap_apps.py. It currently passes, but I think it should probably be rewritten in spots to account for the new fixtures, so I'll have that up later today.
- 535. By Max Brustkern
-
Added new fixtures to functional tests
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:534
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:/
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:535
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:/
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 536. By Max Brustkern
-
Merged temp-dev and added some updates
- 537. By Max Brustkern
-
Fixed sphinx warnings
- 538. By Max Brustkern
-
Named modules properly
- 539. By Max Brustkern
-
Doc fixes and removal of 'emulator' in most places
- 540. By Max Brustkern
-
Better rename
- 541. By Max Brustkern
-
Updated class docstrings
- 542. By Max Brustkern
-
Updated insensible docs
- 543. By Max Brustkern
-
Updated doc ordering
- 544. By Max Brustkern
-
Replaced unique things with tokens
- 545. By Max Brustkern
-
Named and documented tests better
- 546. By Max Brustkern
-
Doc updates
- 547. By Max Brustkern
-
Restored old keyword argument in signature
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:536
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:547
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:547
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 548. By Max Brustkern
-
Fixed unit test
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:548
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 549. By Max Brustkern
-
Removed stray underscore
- 550. By Max Brustkern
-
Double backticks
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
LGTM, thanks
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:550
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'autopilot/application/__init__.py' |
2 | --- autopilot/application/__init__.py 2014-01-24 04:18:10 +0000 |
3 | +++ autopilot/application/__init__.py 2014-05-23 09:57:29 +0000 |
4 | @@ -28,7 +28,7 @@ |
5 | |
6 | __all__ = [ |
7 | 'ClickApplicationLauncher', |
8 | - 'get_application_launcher_wrapper', |
9 | 'NormalApplicationLauncher', |
10 | 'UpstartApplicationLauncher', |
11 | + 'get_application_launcher_wrapper', |
12 | ] |
13 | |
14 | === modified file 'autopilot/application/_launcher.py' |
15 | --- autopilot/application/_launcher.py 2014-05-20 15:27:06 +0000 |
16 | +++ autopilot/application/_launcher.py 2014-05-23 09:57:29 +0000 |
17 | @@ -25,17 +25,18 @@ |
18 | import logging |
19 | import os |
20 | import psutil |
21 | -import six |
22 | import subprocess |
23 | import signal |
24 | from testtools.content import content_from_file, text_content |
25 | |
26 | from autopilot._timeout import Timeout |
27 | -from autopilot.utilities import _raise_on_unknown_kwargs |
28 | from autopilot.application._environment import ( |
29 | GtkApplicationEnvironment, |
30 | QtApplicationEnvironment, |
31 | ) |
32 | +from autopilot.introspection import ( |
33 | + get_proxy_object_for_existing_process, |
34 | +) |
35 | |
36 | _logger = logging.getLogger(__name__) |
37 | |
38 | @@ -45,11 +46,30 @@ |
39 | """A class that knows how to launch an application with a certain type of |
40 | introspection enabled. |
41 | |
42 | + :keyword case_addDetail: addDetail method to use (self.addDetail if not |
43 | + specified) |
44 | + :keyword proxy_base: custom proxy base class to use, defaults to None |
45 | + :keyword dbus_bus: dbus bus to use, if set to something other than the |
46 | + default ('session') the environment will be patched |
47 | + |
48 | """ |
49 | |
50 | - def __init__(self, case_addDetail): |
51 | - self.case_addDetail = case_addDetail |
52 | - super(ApplicationLauncher, self).__init__() |
53 | + def __init__(self, case_addDetail=None, emulator_base=None, |
54 | + dbus_bus='session'): |
55 | + super().__init__() |
56 | + self.case_addDetail = case_addDetail or self.addDetail |
57 | + self.proxy_base = emulator_base |
58 | + self.dbus_bus = dbus_bus |
59 | + |
60 | + def setUp(self): |
61 | + super().setUp() |
62 | + if self.dbus_bus != 'session': |
63 | + self.useFixture( |
64 | + fixtures.EnvironmentVariable( |
65 | + "DBUS_SESSION_BUS_ADDRESS", |
66 | + self.dbus_bus |
67 | + ) |
68 | + ) |
69 | |
70 | def launch(self, *arguments): |
71 | raise NotImplementedError("Sub-classes must implement this method.") |
72 | @@ -57,23 +77,44 @@ |
73 | |
74 | class UpstartApplicationLauncher(ApplicationLauncher): |
75 | |
76 | - """A launcher class that launched applications with UpstartAppLaunch.""" |
77 | + """A launcher class that launches applications with UpstartAppLaunch.""" |
78 | + __doc__ += ApplicationLauncher.__doc__ |
79 | |
80 | Timeout = object() |
81 | Failed = object() |
82 | Started = object() |
83 | Stopped = object() |
84 | |
85 | - def __init__(self, case_addDetail, **kwargs): |
86 | - super(UpstartApplicationLauncher, self).__init__(case_addDetail) |
87 | - |
88 | - self.emulator_base = kwargs.pop('emulator_base', None) |
89 | - self.dbus_bus = kwargs.pop('dbus_bus', 'session') |
90 | - self.dbus_application_name = kwargs.pop('application_name', None) |
91 | - |
92 | - _raise_on_unknown_kwargs(kwargs) |
93 | - |
94 | def launch(self, app_id, app_uris=[]): |
95 | + """Launch an application with upstart. |
96 | + |
97 | + This method launches an application via the ``upstart-app-launch`` |
98 | + library, on platforms that support it. |
99 | + |
100 | + Usage is similar to NormalApplicationLauncher:: |
101 | + |
102 | + from autopilot.application import UpstartApplicationLauncher |
103 | + launcher = UpstartApplicationLauncher() |
104 | + launcher.setUp() |
105 | + app_proxy = launcher.launch('gallery-app') |
106 | + |
107 | + :param app_id: name of the application to launch |
108 | + :param app_uris: list of separate application uris to launch |
109 | + :raises RuntimeError: If the specified application cannot be launched. |
110 | + |
111 | + :returns: proxy object for the launched package application |
112 | + |
113 | + """ |
114 | + if isinstance(app_uris, str): |
115 | + app_uris = [app_uris] |
116 | + if isinstance(app_uris, bytes): |
117 | + app_uris = [app_uris.decode()] |
118 | + _logger.info( |
119 | + "Attempting to launch application '%s' with URIs '%s' via " |
120 | + "upstart-app-launch", |
121 | + app_id, |
122 | + ','.join(app_uris) |
123 | + ) |
124 | state = {} |
125 | state['loop'] = self._get_glib_loop() |
126 | state['expected_app_id'] = app_id |
127 | @@ -94,7 +135,13 @@ |
128 | state.get('status', None), |
129 | state.get('message', '') |
130 | ) |
131 | - return self._get_pid_for_launched_app(app_id) |
132 | + pid = self._get_pid_for_launched_app(app_id) |
133 | + proxy_object = get_proxy_object_for_existing_process( |
134 | + dbus_bus=self.dbus_bus, |
135 | + emulator_base=self.proxy_base, |
136 | + pid=pid |
137 | + ) |
138 | + return proxy_object |
139 | |
140 | @staticmethod |
141 | def _on_failed(launched_app_id, failure_type, state): |
142 | @@ -184,48 +231,172 @@ |
143 | |
144 | class ClickApplicationLauncher(UpstartApplicationLauncher): |
145 | |
146 | - def launch(self, package_id, app_name, app_uris): |
147 | + """Fixture to manage launching a Click application.""" |
148 | + __doc__ += ApplicationLauncher.__doc__ |
149 | + |
150 | + def launch(self, package_id, app_name=None, app_uris=[]): |
151 | + """Launch a click package application with introspection enabled. |
152 | + |
153 | + This method takes care of launching a click package with introspection |
154 | + exabled. You probably want to use this method if your application is |
155 | + packaged in a click application, or is started via upstart. |
156 | + |
157 | + Usage is similar to NormalApplicationLauncher.launch:: |
158 | + |
159 | + from autopilot.application import ClickApplicationLauncher |
160 | + launcher = ClickApplicationLauncher() |
161 | + launcher.setUp() |
162 | + app_proxy = launcher.launch('com.ubuntu.dropping-letters') |
163 | + |
164 | + :param package_id: The Click package name you want to launch. For |
165 | + example: ``com.ubuntu.dropping-letters`` |
166 | + :param app_name: Currently, only one application can be packaged in a |
167 | + click package, and this parameter can be left at None. If |
168 | + specified, it should be the application name you wish to launch. |
169 | + :param app_uris: Parameters used to launch the click package. This |
170 | + parameter will be left empty if not used. |
171 | + |
172 | + :raises RuntimeError: If the specified package_id cannot be found in |
173 | + the click package manifest. |
174 | + :raises RuntimeError: If the specified app_name cannot be found within |
175 | + the specified click package. |
176 | + |
177 | + :returns: proxy object for the launched package application |
178 | + |
179 | + """ |
180 | + if isinstance(app_uris, str): |
181 | + app_uris = [app_uris] |
182 | + if isinstance(app_uris, bytes): |
183 | + app_uris = [app_uris.decode()] |
184 | + _logger.info( |
185 | + "Attempting to launch click application '%s' from click package " |
186 | + " '%s' and URIs '%s'", |
187 | + app_name if app_name is not None else "(default)", |
188 | + package_id, |
189 | + ','.join(app_uris) |
190 | + ) |
191 | app_id = _get_click_app_id(package_id, app_name) |
192 | - return self._do_upstart_launch(app_id, app_uris) |
193 | - |
194 | - def _do_upstart_launch(self, app_id, app_uris): |
195 | - return super(ClickApplicationLauncher, self).launch(app_id, app_uris) |
196 | + return super().launch(app_id, app_uris) |
197 | |
198 | |
199 | class NormalApplicationLauncher(ApplicationLauncher): |
200 | - def __init__(self, case_addDetail, **kwargs): |
201 | - super(NormalApplicationLauncher, self).__init__(case_addDetail) |
202 | - self.app_type = kwargs.pop('app_type', None) |
203 | - self.cwd = kwargs.pop('launch_dir', None) |
204 | - self.capture_output = kwargs.pop('capture_output', True) |
205 | - |
206 | - self.dbus_bus = kwargs.pop('dbus_bus', 'session') |
207 | - self.emulator_base = kwargs.pop('emulator_base', None) |
208 | - |
209 | - _raise_on_unknown_kwargs(kwargs) |
210 | - |
211 | - def launch(self, application, *arguments): |
212 | + |
213 | + """Fixture to manage launching an application.""" |
214 | + __doc__ += ApplicationLauncher.__doc__ |
215 | + |
216 | + def launch(self, application, arguments=[], app_type=None, cwd=None, |
217 | + capture_output=True): |
218 | + """Launch an application and return a proxy object. |
219 | + |
220 | + Use this method to launch an application and start testing it. The |
221 | + arguments passed in ``arguments`` are used as arguments to the |
222 | + application to launch. Additional keyword arguments are used to control |
223 | + the manner in which the application is launched. |
224 | + |
225 | + This fixture is designed to be flexible enough to launch all supported |
226 | + types of applications. Autopilot can automatically determine how to |
227 | + enable introspection support for dynamically linked binary |
228 | + applications. For example, to launch a binary Gtk application, a test |
229 | + might start with:: |
230 | + |
231 | + from autopilot.application import NormalApplicationLauncher |
232 | + launcher = NormalApplicationLauncher() |
233 | + launcher.setUp() |
234 | + app_proxy = launcher.launch('gedit') |
235 | + |
236 | + For use within a testcase, use useFixture: |
237 | + |
238 | + from autopilot.application import NormalApplicationLauncher |
239 | + launcher = self.useFixture(NormalApplicationLauncher()) |
240 | + app_proxy = launcher.launch('gedit') |
241 | + |
242 | + Applications can be given command line arguments by supplying an |
243 | + ``arguments`` argument to this method. For example, if we want to |
244 | + launch ``gedit`` with a certain document loaded, we might do this:: |
245 | + |
246 | + app_proxy = launcher.launch( |
247 | + 'gedit', arguments=['/tmp/test-document.txt']) |
248 | + |
249 | + ... a Qt5 Qml application is launched in a similar fashion:: |
250 | + |
251 | + app_proxy = launcher.launch( |
252 | + 'qmlscene', arguments=['my_scene.qml']) |
253 | + |
254 | + If you wish to launch an application that is not a dynamically linked |
255 | + binary, you must specify the application type. For example, a Qt4 |
256 | + python application might be launched like this:: |
257 | + |
258 | + app_proxy = launcher.launch( |
259 | + 'my_qt_app.py', app_type='qt') |
260 | + |
261 | + Similarly, a python/Gtk application is launched like so:: |
262 | + |
263 | + app_proxy = launcher.launch( |
264 | + 'my_gtk_app.py', app_type='gtk') |
265 | + |
266 | + :param application: The application to launch. The application can be |
267 | + specified as: |
268 | + |
269 | + * A full, absolute path to an executable file. |
270 | + (``/usr/bin/gedit``) |
271 | + * A relative path to an executable file. |
272 | + (``./build/my_app``) |
273 | + * An app name, which will be searched for in $PATH (``my_app``) |
274 | + |
275 | + :keyword arguments: If set, the list of arguments is passed to the |
276 | + launched app. |
277 | + |
278 | + :keyword app_type: If set, provides a hint to autopilot as to which |
279 | + kind of introspection to enable. This is needed when the |
280 | + application you wish to launch is *not* a dynamically linked |
281 | + binary. Valid values are 'gtk' or 'qt'. These strings are case |
282 | + insensitive. |
283 | + |
284 | + :keyword launch_dir: If set to a directory that exists the process |
285 | + will be launched from that directory. |
286 | + |
287 | + :keyword capture_output: If set to True (the default), the process |
288 | + output will be captured and attached to the test as test detail. |
289 | + |
290 | + :return: A proxy object that represents the application. Introspection |
291 | + data is retrievable via this object. |
292 | + |
293 | + """ |
294 | + _logger.info( |
295 | + "Attempting to launch application '%s' with arguments '%s' as a " |
296 | + "normal process", |
297 | + application, |
298 | + ' '.join(arguments) |
299 | + ) |
300 | app_path = _get_application_path(application) |
301 | - app_path, arguments = self._setup_environment(app_path, *arguments) |
302 | - self.process = self._launch_application_process(app_path, *arguments) |
303 | - |
304 | - return self.process.pid |
305 | - |
306 | - def _setup_environment(self, app_path, *arguments): |
307 | + app_path, arguments = self._setup_environment( |
308 | + app_path, app_type, arguments) |
309 | + process = self._launch_application_process( |
310 | + app_path, capture_output, cwd, arguments) |
311 | + proxy_object = get_proxy_object_for_existing_process( |
312 | + dbus_bus=self.dbus_bus, |
313 | + emulator_base=self.proxy_base, |
314 | + process=process, |
315 | + pid=process.pid |
316 | + ) |
317 | + return proxy_object |
318 | + |
319 | + def _setup_environment(self, app_path, app_type, arguments): |
320 | app_env = self.useFixture( |
321 | - _get_application_environment(self.app_type, app_path) |
322 | + _get_application_environment(app_type, app_path) |
323 | ) |
324 | return app_env.prepare_environment( |
325 | app_path, |
326 | list(arguments), |
327 | ) |
328 | |
329 | - def _launch_application_process(self, app_path, *arguments): |
330 | + def _launch_application_process(self, app_path, capture_output, cwd, |
331 | + arguments): |
332 | process = launch_process( |
333 | app_path, |
334 | arguments, |
335 | - self.capture_output, |
336 | - cwd=self.cwd, |
337 | + capture_output, |
338 | + cwd=cwd, |
339 | ) |
340 | |
341 | self.addCleanup(self._kill_process_and_attach_logs, process, app_path) |
342 | @@ -369,9 +540,9 @@ |
343 | _attempt_kill_pid(process.pid) |
344 | for _ in Timeout.default(): |
345 | tmp_out, tmp_err = process.communicate() |
346 | - if isinstance(tmp_out, six.binary_type): |
347 | + if isinstance(tmp_out, bytes): |
348 | tmp_out = tmp_out.decode('utf-8', errors='replace') |
349 | - if isinstance(tmp_err, six.binary_type): |
350 | + if isinstance(tmp_err, bytes): |
351 | tmp_err = tmp_err.decode('utf-8', errors='replace') |
352 | stdout_parts.append(tmp_out) |
353 | stderr_parts.append(tmp_err) |
354 | |
355 | === modified file 'autopilot/testcase.py' |
356 | --- autopilot/testcase.py 2014-05-15 15:18:12 +0000 |
357 | +++ autopilot/testcase.py 2014-05-23 09:57:29 +0000 |
358 | @@ -49,7 +49,6 @@ |
359 | from __future__ import absolute_import |
360 | |
361 | import logging |
362 | -import six |
363 | |
364 | from fixtures import EnvironmentVariable |
365 | from testscenarios import TestWithScenarios |
366 | @@ -65,9 +64,6 @@ |
367 | from autopilot.display import Display |
368 | from autopilot.globals import get_debug_profile_fixture |
369 | from autopilot.input import Keyboard, Mouse |
370 | -from autopilot.introspection import ( |
371 | - get_proxy_object_for_existing_process, |
372 | -) |
373 | from autopilot.keybindings import KeybindingsHelper |
374 | from autopilot.matchers import Eventually |
375 | from autopilot.process import ProcessManager |
376 | @@ -246,22 +242,22 @@ |
377 | :keyword emulator_base: If set, specifies the base class to be used for |
378 | all emulators for this loaded application. |
379 | |
380 | - :raises ValueError: if unknown keyword arguments are passed. |
381 | :return: A proxy object that represents the application. Introspection |
382 | data is retrievable via this object. |
383 | |
384 | """ |
385 | - _logger.info( |
386 | - "Attempting to launch application '%s' with arguments '%s' as a " |
387 | - "normal process", |
388 | - application, |
389 | - ' '.join(arguments) |
390 | - ) |
391 | + launch_args = {} |
392 | + launch_arg_list = ['app_type', 'launch_dir', 'capture_output'] |
393 | + for arg in launch_arg_list: |
394 | + if arg in kwargs: |
395 | + launch_args[arg] = kwargs.pop(arg) |
396 | launcher = self.useFixture( |
397 | - NormalApplicationLauncher(self.addDetailUniqueName, **kwargs) |
398 | + NormalApplicationLauncher( |
399 | + case_addDetail=self.addDetailUniqueName, |
400 | + **kwargs |
401 | + ) |
402 | ) |
403 | - |
404 | - return self._launch_test_application(launcher, application, *arguments) |
405 | + return launcher.launch(application, arguments, **launch_args) |
406 | |
407 | def launch_click_package(self, package_id, app_name=None, app_uris=[], |
408 | **kwargs): |
409 | @@ -297,20 +293,13 @@ |
410 | :returns: proxy object for the launched package application |
411 | |
412 | """ |
413 | - if isinstance(app_uris, (six.text_type, six.binary_type)): |
414 | - app_uris = [app_uris] |
415 | - _logger.info( |
416 | - "Attempting to launch click application '%s' from click package " |
417 | - " '%s' and URIs '%s'", |
418 | - app_name if app_name is not None else "(default)", |
419 | - package_id, |
420 | - ','.join(app_uris) |
421 | - ) |
422 | launcher = self.useFixture( |
423 | - ClickApplicationLauncher(self.addDetailUniqueName, **kwargs) |
424 | + ClickApplicationLauncher( |
425 | + case_addDetail=self.addDetailUniqueName, |
426 | + **kwargs |
427 | + ) |
428 | ) |
429 | - return self._launch_test_application(launcher, package_id, app_name, |
430 | - app_uris) |
431 | + return launcher.launch(package_id, app_name, app_uris) |
432 | |
433 | def launch_upstart_application(self, application_name, uris=[], **kwargs): |
434 | """Launch an application with upstart. |
435 | @@ -328,52 +317,14 @@ |
436 | all emulators for this loaded application. |
437 | |
438 | :raises RuntimeError: If the specified application cannot be launched. |
439 | - :raises ValueError: If unknown keyword arguments are specified. |
440 | """ |
441 | - if isinstance(uris, (six.text_type, six.binary_type)): |
442 | - uris = [uris] |
443 | - _logger.info( |
444 | - "Attempting to launch application '%s' with URIs '%s' via " |
445 | - "upstart-app-launch", |
446 | - application_name, |
447 | - ','.join(uris) |
448 | - ) |
449 | launcher = self.useFixture( |
450 | - UpstartApplicationLauncher(self.addDetailUniqueName, **kwargs) |
451 | - ) |
452 | - return self._launch_test_application(launcher, application_name, uris) |
453 | - |
454 | - # Wrapper function tying the newer ApplicationLauncher behaviour with the |
455 | - # previous (to be depreciated) behaviour |
456 | - def _launch_test_application(self, launcher_instance, application, *args): |
457 | - |
458 | - dbus_bus = launcher_instance.dbus_bus |
459 | - if dbus_bus != 'session': |
460 | - self.useFixture( |
461 | - EnvironmentVariable("DBUS_SESSION_BUS_ADDRESS", dbus_bus)) |
462 | - |
463 | - pid = launcher_instance.launch(application, *args) |
464 | - application_name = getattr( |
465 | - launcher_instance, |
466 | - 'dbus_application_name', |
467 | - None |
468 | - ) |
469 | - process = getattr(launcher_instance, 'process', None) |
470 | - |
471 | - search_params = dict( |
472 | - pid=pid, |
473 | - dbus_bus=dbus_bus, |
474 | - emulator_base=launcher_instance.emulator_base |
475 | - ) |
476 | - if application_name is not None: |
477 | - search_params['application_name'] = application_name |
478 | - if process is not None: |
479 | - search_params['process'] = process |
480 | - |
481 | - proxy_obj = get_proxy_object_for_existing_process(**search_params) |
482 | - proxy_obj.set_process(process) |
483 | - |
484 | - return proxy_obj |
485 | + UpstartApplicationLauncher( |
486 | + case_addDetail=self.addDetailUniqueName, |
487 | + **kwargs |
488 | + ) |
489 | + ) |
490 | + return launcher.launch(application_name, uris) |
491 | |
492 | def _compare_system_with_app_snapshot(self): |
493 | """Compare the currently running application with the last snapshot. |
494 | @@ -396,7 +347,8 @@ |
495 | |
496 | This function is deprecated and planned for removal in autopilot 1.6. |
497 | New implementations should use EnvironmenVariable from the fixtures |
498 | - module: |
499 | + module:: |
500 | + |
501 | from fixtures import EnvironmentVariable |
502 | |
503 | def my_test(AutopilotTestCase): |
504 | |
505 | === modified file 'autopilot/tests/acceptance/test_vis_main.py' |
506 | --- autopilot/tests/acceptance/test_vis_main.py 2014-05-05 03:51:21 +0000 |
507 | +++ autopilot/tests/acceptance/test_vis_main.py 2014-05-23 09:57:29 +0000 |
508 | @@ -24,7 +24,6 @@ |
509 | from testtools import skipIf |
510 | from testtools.matchers import Equals |
511 | |
512 | -from autopilot.application import NormalApplicationLauncher |
513 | from autopilot.introspection.dbus import CustomEmulatorBase |
514 | from autopilot.matchers import Eventually |
515 | from autopilot.platform import model |
516 | @@ -35,47 +34,19 @@ |
517 | pass |
518 | |
519 | |
520 | -class VisToolLauncher(NormalApplicationLauncher): |
521 | - |
522 | - """Override code that prepares application environment. |
523 | - |
524 | - The vis tool does not accept the '-testability' argument as the first |
525 | - argument, so we override _setup_environment to put the argument in the |
526 | - correct place. |
527 | - |
528 | - """ |
529 | - |
530 | - def _setup_environment(self, app_path, *arguments): |
531 | - return app_path, arguments + ('-testability',) |
532 | - |
533 | - |
534 | class VisAcceptanceTests(AutopilotTestCase): |
535 | |
536 | def launch_windowmocker(self): |
537 | return self.launch_test_application("window-mocker", app_type="qt") |
538 | |
539 | - def launch_vis(self): |
540 | - """Launch the vis tool and return it's proxy object.""" |
541 | - launcher = self.useFixture( |
542 | - VisToolLauncher( |
543 | - self.addDetail, |
544 | - app_type="qt", |
545 | - emulator_base=VisToolEmulatorBase |
546 | - ) |
547 | - ) |
548 | - vis_proxy = self._launch_test_application( |
549 | - launcher, |
550 | - sys.executable, |
551 | - "-m" |
552 | - "autopilot.run", |
553 | - "vis", |
554 | - ) |
555 | - return vis_proxy |
556 | - |
557 | @skipIf(model() != "Desktop", "Vis not usable on device.") |
558 | def test_can_select_windowmocker(self): |
559 | wm = self.launch_windowmocker() |
560 | - vis = self.launch_vis() |
561 | + vis = self.launch_test_application( |
562 | + sys.executable, |
563 | + '-m', 'autopilot.run', 'vis', '-testability', |
564 | + app_type='qt', |
565 | + ) |
566 | connection_list = vis.select_single('ConnectionList') |
567 | connection_list.slots.trySetSelectedItem(wm.applicationName) |
568 | self.assertThat( |
569 | |
570 | === modified file 'autopilot/tests/functional/test_ap_apps.py' |
571 | --- autopilot/tests/functional/test_ap_apps.py 2014-05-12 21:00:00 +0000 |
572 | +++ autopilot/tests/functional/test_ap_apps.py 2014-05-23 09:57:29 +0000 |
573 | @@ -36,6 +36,10 @@ |
574 | |
575 | from fixtures import EnvironmentVariable |
576 | |
577 | +from autopilot.application import ( |
578 | + NormalApplicationLauncher, |
579 | + UpstartApplicationLauncher, |
580 | +) |
581 | from autopilot.exceptions import ProcessSearchError |
582 | from autopilot.process import ProcessManager |
583 | from autopilot.platform import model |
584 | @@ -290,9 +294,10 @@ |
585 | def test_can_launch_normal_app(self): |
586 | path = self.get_qml_viewer_app_path() |
587 | fixture = self.useFixture(TempDesktopFile(exec_=path,)) |
588 | - app_proxy = self.launch_test_application( |
589 | + launcher = self.useFixture(NormalApplicationLauncher()) |
590 | + app_proxy = launcher.launch( |
591 | path, |
592 | - '--desktop_file_hint=%s' % fixture.get_desktop_file_path(), |
593 | + ['--desktop_file_hint=%s' % fixture.get_desktop_file_path()], |
594 | app_type='qt' |
595 | ) |
596 | self.assertTrue(app_proxy is not None) |
597 | @@ -300,7 +305,8 @@ |
598 | def test_can_launch_upstart_app(self): |
599 | path = self.get_qml_viewer_app_path() |
600 | fixture = self.useFixture(TempDesktopFile(exec_=path,)) |
601 | - self.launch_upstart_application(fixture.get_desktop_file_id()) |
602 | + launcher = self.useFixture(UpstartApplicationLauncher()) |
603 | + launcher.launch(fixture.get_desktop_file_id()) |
604 | |
605 | @skipIf(model() != "Desktop", "Only suitable on Desktop (Qt4)") |
606 | def test_can_launch_normal_qt_script(self): |
607 | |
608 | === modified file 'autopilot/tests/functional/test_application_mixin.py' |
609 | --- autopilot/tests/functional/test_application_mixin.py 2013-12-16 01:07:43 +0000 |
610 | +++ autopilot/tests/functional/test_application_mixin.py 2014-05-23 09:57:29 +0000 |
611 | @@ -44,25 +44,3 @@ |
612 | lambda: self.launch_test_application([]), raises(TypeError)) |
613 | self.assertThat( |
614 | lambda: self.launch_test_application((None,)), raises(TypeError)) |
615 | - |
616 | - def test_launch_raises_ValueError_on_unknown_kwargs(self): |
617 | - """launch_test_application must raise ValueError when given unknown |
618 | - keyword arguments. |
619 | - |
620 | - """ |
621 | - fn = lambda: self.launch_test_application( |
622 | - 'gedit', arg1=123, arg2='asd') |
623 | - self.assertThat( |
624 | - fn, |
625 | - raises(ValueError("Unknown keyword arguments: 'arg1', 'arg2'."))) |
626 | - |
627 | - def test_launch_raises_ValueError_on_unknown_kwargs_with_known(self): |
628 | - """launch_test_application must raise ValueError when given unknown |
629 | - keyword arguments. |
630 | - |
631 | - """ |
632 | - fn = lambda: self.launch_test_application( |
633 | - 'gedit', arg1=123, arg2='asd', launch_dir='/') |
634 | - self.assertThat( |
635 | - fn, |
636 | - raises(ValueError("Unknown keyword arguments: 'arg1', 'arg2'."))) |
637 | |
638 | === modified file 'autopilot/tests/unit/test_application_launcher.py' |
639 | --- autopilot/tests/unit/test_application_launcher.py 2014-04-22 22:00:25 +0000 |
640 | +++ autopilot/tests/unit/test_application_launcher.py 2014-05-23 09:57:29 +0000 |
641 | @@ -34,7 +34,6 @@ |
642 | IsInstance, |
643 | MatchesListwise, |
644 | Not, |
645 | - Raises, |
646 | raises, |
647 | ) |
648 | from testtools.content import text_content |
649 | @@ -76,28 +75,34 @@ |
650 | ) |
651 | ) |
652 | |
653 | + def test_init_uses_default_values(self): |
654 | + launcher = ApplicationLauncher() |
655 | + self.assertEqual(launcher.case_addDetail, launcher.addDetail) |
656 | + self.assertEqual(launcher.proxy_base, None) |
657 | + self.assertEqual(launcher.dbus_bus, 'session') |
658 | + |
659 | + def test_init_uses_passed_values(self): |
660 | + case_addDetail = self.getUniqueString() |
661 | + emulator_base = self.getUniqueString() |
662 | + dbus_bus = self.getUniqueString() |
663 | + |
664 | + launcher = ApplicationLauncher( |
665 | + case_addDetail=case_addDetail, |
666 | + emulator_base=emulator_base, |
667 | + dbus_bus=dbus_bus, |
668 | + ) |
669 | + self.assertEqual(launcher.case_addDetail, case_addDetail) |
670 | + self.assertEqual(launcher.proxy_base, emulator_base) |
671 | + self.assertEqual(launcher.dbus_bus, dbus_bus) |
672 | + |
673 | + @patch('autopilot.application._launcher.fixtures.EnvironmentVariable') |
674 | + def test_setUp_patches_environment(self, ev): |
675 | + self.useFixture(ApplicationLauncher(dbus_bus='')) |
676 | + ev.assert_called_with('DBUS_SESSION_BUS_ADDRESS', '') |
677 | + |
678 | |
679 | class NormalApplicationLauncherTests(TestCase): |
680 | |
681 | - def test_consumes_all_known_kwargs(self): |
682 | - test_kwargs = dict( |
683 | - app_type=True, |
684 | - launch_dir=True, |
685 | - capture_output=True, |
686 | - dbus_bus=True, |
687 | - emulator_base=True |
688 | - ) |
689 | - self.assertThat( |
690 | - lambda: NormalApplicationLauncher(self.addDetail, **test_kwargs), |
691 | - Not(Raises()) |
692 | - ) |
693 | - |
694 | - def test_raises_value_error_on_unknown_kwargs(self): |
695 | - self.assertThat( |
696 | - lambda: NormalApplicationLauncher(self.addDetail, unknown=True), |
697 | - raises(ValueError("Unknown keyword arguments: 'unknown'.")) |
698 | - ) |
699 | - |
700 | def test_kill_process_and_attach_logs(self): |
701 | mock_addDetail = Mock() |
702 | app_launcher = NormalApplicationLauncher(mock_addDetail) |
703 | @@ -123,31 +128,100 @@ |
704 | ) |
705 | |
706 | def test_setup_environment_returns_prepare_environment_return_value(self): |
707 | - token = self.getUniqueString() |
708 | - fake_env = Mock() |
709 | - fake_env.prepare_environment.return_value = token |
710 | - |
711 | - app_launcher = NormalApplicationLauncher(self.addDetail) |
712 | - app_launcher.setUp() |
713 | - |
714 | - with patch.object( |
715 | - _l, '_get_application_environment', return_value=fake_env |
716 | - ): |
717 | + app_launcher = self.useFixture(NormalApplicationLauncher()) |
718 | + with patch.object(_l, '_get_application_environment') as gae: |
719 | self.assertThat( |
720 | - app_launcher._setup_environment(self.getUniqueString()), |
721 | - Equals(token) |
722 | - ) |
723 | - |
724 | - def test_launch_returns_process_id(self): |
725 | - app_launcher = NormalApplicationLauncher(self.addDetail) |
726 | - |
727 | - with patch.object(_l, '_get_application_path', return_value=""): |
728 | - app_launcher._setup_environment = Mock(return_value=("", "",)) |
729 | - app_launcher._launch_application_process = Mock( |
730 | - return_value=Mock(pid=123) |
731 | - ) |
732 | - |
733 | - self.assertThat(app_launcher.launch(""), Equals(123)) |
734 | + app_launcher._setup_environment( |
735 | + self.getUniqueString(), None, []), |
736 | + Equals(gae.return_value.prepare_environment.return_value) |
737 | + ) |
738 | + |
739 | + @patch('autopilot.application._launcher.' |
740 | + 'get_proxy_object_for_existing_process') |
741 | + @patch('autopilot.application._launcher._get_application_path') |
742 | + def test_launch_call_to_get_application_path(self, gap, _): |
743 | + """Test that NormalApplicationLauncher.launch calls |
744 | + _get_application_path with the arguments it was passed,""" |
745 | + launcher = NormalApplicationLauncher() |
746 | + with patch.object(launcher, '_launch_application_process'): |
747 | + with patch.object(launcher, '_setup_environment') as se: |
748 | + se.return_value = ('', []) |
749 | + token = self.getUniqueString() |
750 | + launcher.launch(token) |
751 | + gap.assert_called_once_with(token) |
752 | + |
753 | + @patch('autopilot.application._launcher.' |
754 | + 'get_proxy_object_for_existing_process') |
755 | + @patch('autopilot.application._launcher._get_application_path') |
756 | + def test_launch_call_to_setup_environment(self, gap, _): |
757 | + """Test the NornmalApplicationLauncher.launch calls |
758 | + self._setup_environment with the correct application path from |
759 | + _get_application_path and the arguments passed to it.""" |
760 | + launcher = NormalApplicationLauncher() |
761 | + with patch.object(launcher, '_launch_application_process'): |
762 | + with patch.object(launcher, '_setup_environment') as se: |
763 | + se.return_value = ('', []) |
764 | + token_a = self.getUniqueString() |
765 | + token_b = self.getUniqueString() |
766 | + token_c = self.getUniqueString() |
767 | + launcher.launch(token_a, arguments=[token_b, token_c]) |
768 | + se.assert_called_once_with( |
769 | + gap.return_value, |
770 | + None, |
771 | + [token_b, token_c], |
772 | + ) |
773 | + |
774 | + @patch('autopilot.application._launcher.' |
775 | + 'get_proxy_object_for_existing_process') |
776 | + @patch('autopilot.application._launcher._get_application_path') |
777 | + def test_launch_call_to_launch_application_process(self, _, __): |
778 | + """Test that NormalApplicationLauncher.launch calls |
779 | + launch_application_process with the return values of |
780 | + setup_environment.""" |
781 | + launcher = NormalApplicationLauncher() |
782 | + with patch.object(launcher, '_launch_application_process') as lap: |
783 | + with patch.object(launcher, '_setup_environment') as se: |
784 | + token_a = self.getUniqueString() |
785 | + token_b = self.getUniqueString() |
786 | + token_c = self.getUniqueString() |
787 | + se.return_value = (token_a, [token_b, token_c]) |
788 | + launcher.launch('', arguments=['', '']) |
789 | + lap.assert_called_once_with( |
790 | + token_a, |
791 | + True, |
792 | + None, |
793 | + [token_b, token_c], |
794 | + ) |
795 | + |
796 | + @patch('autopilot.application._launcher.' |
797 | + 'get_proxy_object_for_existing_process') |
798 | + @patch('autopilot.application._launcher._get_application_path') |
799 | + def test_launch_gets_correct_proxy_object(self, _, gpofep): |
800 | + """Test that NormalApplicationLauncher.launch calls |
801 | + get_proxy_object_for_existing_process with the correct return values of |
802 | + other functions.""" |
803 | + launcher = NormalApplicationLauncher() |
804 | + with patch.object(launcher, '_launch_application_process') as lap: |
805 | + with patch.object(launcher, '_setup_environment') as se: |
806 | + se.return_value = ('', []) |
807 | + launcher.launch('') |
808 | + gpofep.assert_called_once_with(process=lap.return_value, |
809 | + pid=lap.return_value.pid, |
810 | + emulator_base=None, |
811 | + dbus_bus='session') |
812 | + |
813 | + @patch('autopilot.application._launcher.' |
814 | + 'get_proxy_object_for_existing_process') |
815 | + @patch('autopilot.application._launcher._get_application_path') |
816 | + def test_launch_returns_proxy_object(self, _, gpofep): |
817 | + """Test that NormalApplicationLauncher.launch returns the proxy object |
818 | + returned by get_proxy_object_for_existing_process.""" |
819 | + launcher = NormalApplicationLauncher() |
820 | + with patch.object(launcher, '_launch_application_process'): |
821 | + with patch.object(launcher, '_setup_environment') as se: |
822 | + se.return_value = ('', []) |
823 | + result = launcher.launch('') |
824 | + self.assertEqual(result, gpofep.return_value) |
825 | |
826 | def test_launch_application_process(self): |
827 | """The _launch_application_process method must return the process |
828 | @@ -162,7 +236,8 @@ |
829 | with patch.object( |
830 | _l, 'launch_process', return_value=expected_process_return |
831 | ) as patched_launch_process: |
832 | - process = launcher._launch_application_process("/foo/bar") |
833 | + process = launcher._launch_application_process( |
834 | + "/foo/bar", False, None, []) |
835 | |
836 | self.assertThat(process, Equals(expected_process_return)) |
837 | self.assertThat( |
838 | @@ -171,9 +246,9 @@ |
839 | ) |
840 | patched_launch_process.assert_called_with( |
841 | "/foo/bar", |
842 | - (), |
843 | - launcher.capture_output, |
844 | - cwd=launcher.cwd |
845 | + [], |
846 | + False, |
847 | + cwd=None |
848 | ) |
849 | |
850 | |
851 | @@ -182,49 +257,126 @@ |
852 | def test_raises_exception_on_unknown_kwargs(self): |
853 | self.assertThat( |
854 | lambda: ClickApplicationLauncher(self.addDetail, unknown=True), |
855 | - raises(ValueError("Unknown keyword arguments: 'unknown'.")) |
856 | - ) |
857 | - |
858 | - def test_application_name_kwarg_stored(self): |
859 | - app_name = self.getUniqueString() |
860 | - launcher = ClickApplicationLauncher( |
861 | - self.addDetail, |
862 | - application_name=app_name |
863 | - ) |
864 | - |
865 | - self.assertThat( |
866 | - launcher.dbus_application_name, Equals(app_name) |
867 | - ) |
868 | - |
869 | - def test_click_launch_calls_upstart_launch(self): |
870 | - launcher = ClickApplicationLauncher(self.addDetail) |
871 | - token = self.getUniqueString() |
872 | - with patch.object(launcher, '_do_upstart_launch') as p_dul: |
873 | - with patch.object(_l, '_get_click_app_id') as p_gcai: |
874 | - p_gcai.return_value = token |
875 | - launcher.launch('some_app_id', 'some_app_name', []) |
876 | - p_dul.assert_called_once_with(token, []) |
877 | - |
878 | - def test_upcalls_to_upstart(self): |
879 | - class FakeUpstartBase(_l.ApplicationLauncher): |
880 | - launch_call_args = [] |
881 | - |
882 | - def launch(self, *args): |
883 | - FakeUpstartBase.launch_call_args = list(args) |
884 | - |
885 | - patcher = patch.object( |
886 | - _l.ClickApplicationLauncher, |
887 | - '__bases__', |
888 | - (FakeUpstartBase,) |
889 | - ) |
890 | - with patcher: |
891 | - # Prevent mock from trying to delete __bases__ |
892 | - patcher.is_local = True |
893 | - launcher = ClickApplicationLauncher(self.addDetail) |
894 | - launcher._do_upstart_launch('app_id', []) |
895 | - self.assertEqual( |
896 | - FakeUpstartBase.launch_call_args, |
897 | - ['app_id', []]) |
898 | + raises(TypeError("__init__() got an unexpected keyword argument " |
899 | + "'unknown'")) |
900 | + ) |
901 | + |
902 | + @patch('autopilot.application._launcher._get_click_app_id') |
903 | + def test_handle_string(self, gcai): |
904 | + class FakeUpstartBase(_l.ApplicationLauncher): |
905 | + launch_call_args = [] |
906 | + |
907 | + def launch(self, *args): |
908 | + FakeUpstartBase.launch_call_args = list(args) |
909 | + |
910 | + patcher = patch.object( |
911 | + _l.ClickApplicationLauncher, |
912 | + '__bases__', |
913 | + (FakeUpstartBase,) |
914 | + ) |
915 | + token = self.getUniqueString() |
916 | + with patcher: |
917 | + # Prevent mock from trying to delete __bases__ |
918 | + patcher.is_local = True |
919 | + launcher = self.useFixture( |
920 | + _l.ClickApplicationLauncher()) |
921 | + launcher.launch('', '', token) |
922 | + self.assertEqual( |
923 | + FakeUpstartBase.launch_call_args, |
924 | + [gcai.return_value, [token]]) |
925 | + |
926 | + @patch('autopilot.application._launcher._get_click_app_id') |
927 | + def test_handle_bytes(self, gcai): |
928 | + class FakeUpstartBase(_l.ApplicationLauncher): |
929 | + launch_call_args = [] |
930 | + |
931 | + def launch(self, *args): |
932 | + FakeUpstartBase.launch_call_args = list(args) |
933 | + |
934 | + patcher = patch.object( |
935 | + _l.ClickApplicationLauncher, |
936 | + '__bases__', |
937 | + (FakeUpstartBase,) |
938 | + ) |
939 | + token = self.getUniqueString() |
940 | + with patcher: |
941 | + # Prevent mock from trying to delete __bases__ |
942 | + patcher.is_local = True |
943 | + launcher = self.useFixture( |
944 | + _l.ClickApplicationLauncher()) |
945 | + launcher.launch('', '', token.encode()) |
946 | + self.assertEqual( |
947 | + FakeUpstartBase.launch_call_args, |
948 | + [gcai.return_value, [token]]) |
949 | + |
950 | + @patch('autopilot.application._launcher._get_click_app_id') |
951 | + def test_handle_list(self, gcai): |
952 | + class FakeUpstartBase(_l.ApplicationLauncher): |
953 | + launch_call_args = [] |
954 | + |
955 | + def launch(self, *args): |
956 | + FakeUpstartBase.launch_call_args = list(args) |
957 | + |
958 | + patcher = patch.object( |
959 | + _l.ClickApplicationLauncher, |
960 | + '__bases__', |
961 | + (FakeUpstartBase,) |
962 | + ) |
963 | + token = self.getUniqueString() |
964 | + with patcher: |
965 | + # Prevent mock from trying to delete __bases__ |
966 | + patcher.is_local = True |
967 | + launcher = self.useFixture( |
968 | + _l.ClickApplicationLauncher()) |
969 | + launcher.launch('', '', [token]) |
970 | + self.assertEqual( |
971 | + FakeUpstartBase.launch_call_args, |
972 | + [gcai.return_value, [token]]) |
973 | + |
974 | + @patch('autopilot.application._launcher._get_click_app_id') |
975 | + def test_call_get_click_app_id(self, gcai): |
976 | + class FakeUpstartBase(_l.ApplicationLauncher): |
977 | + launch_call_args = [] |
978 | + |
979 | + def launch(self, *args): |
980 | + FakeUpstartBase.launch_call_args = list(args) |
981 | + |
982 | + patcher = patch.object( |
983 | + _l.ClickApplicationLauncher, |
984 | + '__bases__', |
985 | + (FakeUpstartBase,) |
986 | + ) |
987 | + token_a = self.getUniqueString() |
988 | + token_b = self.getUniqueString() |
989 | + with patcher: |
990 | + # Prevent mock from trying to delete __bases__ |
991 | + patcher.is_local = True |
992 | + launcher = self.useFixture( |
993 | + _l.ClickApplicationLauncher()) |
994 | + launcher.launch(token_a, token_b) |
995 | + gcai.assert_called_once_with(token_a, token_b) |
996 | + |
997 | + @patch('autopilot.application._launcher._get_click_app_id') |
998 | + def test_call_upstart_launch(self, gcai): |
999 | + class FakeUpstartBase(_l.ApplicationLauncher): |
1000 | + launch_call_args = [] |
1001 | + |
1002 | + def launch(self, *args): |
1003 | + FakeUpstartBase.launch_call_args = list(args) |
1004 | + |
1005 | + patcher = patch.object( |
1006 | + _l.ClickApplicationLauncher, |
1007 | + '__bases__', |
1008 | + (FakeUpstartBase,) |
1009 | + ) |
1010 | + with patcher: |
1011 | + # Prevent mock from trying to delete __bases__ |
1012 | + patcher.is_local = True |
1013 | + launcher = self.useFixture( |
1014 | + _l.ClickApplicationLauncher()) |
1015 | + launcher.launch('', '') |
1016 | + self.assertEqual(launcher.launch_call_args, |
1017 | + [gcai.return_value, []]) |
1018 | |
1019 | |
1020 | class ClickFunctionTests(TestCase): |
1021 | @@ -316,32 +468,11 @@ |
1022 | def test_can_construct_UpstartApplicationLauncher(self): |
1023 | UpstartApplicationLauncher(self.addDetail) |
1024 | |
1025 | - def test_default_values_are_set(self): |
1026 | - launcher = UpstartApplicationLauncher(self.addDetail) |
1027 | - self.assertThat(launcher.emulator_base, Equals(None)) |
1028 | - self.assertThat(launcher.dbus_bus, Equals('session')) |
1029 | - |
1030 | - def test_can_set_emulator_base(self): |
1031 | - mock_emulator_base = Mock() |
1032 | - launcher = UpstartApplicationLauncher( |
1033 | - self.addDetail, |
1034 | - emulator_base=mock_emulator_base |
1035 | - ) |
1036 | - |
1037 | - self.assertThat(launcher.emulator_base, Equals(mock_emulator_base)) |
1038 | - |
1039 | - def test_can_set_dbus_bus(self): |
1040 | - launcher = UpstartApplicationLauncher( |
1041 | - self.addDetail, |
1042 | - dbus_bus='system' |
1043 | - ) |
1044 | - |
1045 | - self.assertThat(launcher.dbus_bus, Equals('system')) |
1046 | - |
1047 | def test_raises_exception_on_unknown_kwargs(self): |
1048 | self.assertThat( |
1049 | lambda: UpstartApplicationLauncher(self.addDetail, unknown=True), |
1050 | - raises(ValueError("Unknown keyword arguments: 'unknown'.")) |
1051 | + raises(TypeError("__init__() got an unexpected keyword argument " |
1052 | + "'unknown'")) |
1053 | ) |
1054 | |
1055 | def test_on_failed_only_sets_status_on_correct_app_id(self): |
1056 | @@ -491,13 +622,84 @@ |
1057 | loop = UpstartApplicationLauncher._get_glib_loop() |
1058 | self.assertThat(loop, IsInstance(GLib.MainLoop)) |
1059 | |
1060 | - def test_launch(self): |
1061 | - launcher = UpstartApplicationLauncher(self.addDetail) |
1062 | - with patch.object(launcher, '_launch_app') as patched_launch: |
1063 | - with patch.object(launcher, '_get_glib_loop'): |
1064 | - launcher.launch('gedit') |
1065 | - |
1066 | - patched_launch.assert_called_once_with('gedit', []) |
1067 | + @patch('autopilot.application._launcher.' |
1068 | + 'get_proxy_object_for_existing_process') |
1069 | + def test_handle_string(self, _): |
1070 | + launcher = UpstartApplicationLauncher() |
1071 | + token_a = self.getUniqueString() |
1072 | + token_b = self.getUniqueString() |
1073 | + with patch.object(launcher, '_launch_app') as la: |
1074 | + with patch.object(launcher, '_get_pid_for_launched_app'): |
1075 | + with patch.object(launcher, '_get_glib_loop'): |
1076 | + launcher.launch(token_a, token_b) |
1077 | + la.assert_called_once_with(token_a, [token_b]) |
1078 | + |
1079 | + @patch('autopilot.application._launcher.' |
1080 | + 'get_proxy_object_for_existing_process') |
1081 | + def test_handle_bytes(self, _): |
1082 | + launcher = UpstartApplicationLauncher() |
1083 | + token_a = self.getUniqueString() |
1084 | + token_b = self.getUniqueString() |
1085 | + with patch.object(launcher, '_launch_app') as la: |
1086 | + with patch.object(launcher, '_get_pid_for_launched_app'): |
1087 | + with patch.object(launcher, '_get_glib_loop'): |
1088 | + launcher.launch(token_a, token_b.encode()) |
1089 | + la.assert_called_once_with(token_a, [token_b]) |
1090 | + |
1091 | + @patch('autopilot.application._launcher.' |
1092 | + 'get_proxy_object_for_existing_process') |
1093 | + def test_handle_list(self, _): |
1094 | + launcher = UpstartApplicationLauncher() |
1095 | + token_a = self.getUniqueString() |
1096 | + token_b = self.getUniqueString() |
1097 | + with patch.object(launcher, '_launch_app') as la: |
1098 | + with patch.object(launcher, '_get_pid_for_launched_app'): |
1099 | + with patch.object(launcher, '_get_glib_loop'): |
1100 | + launcher.launch(token_a, [token_b]) |
1101 | + la.assert_called_once_with(token_a, [token_b]) |
1102 | + |
1103 | + @patch('autopilot.application._launcher.' |
1104 | + 'get_proxy_object_for_existing_process') |
1105 | + def test_calls_get_pid(self, _): |
1106 | + launcher = UpstartApplicationLauncher() |
1107 | + token = self.getUniqueString() |
1108 | + with patch.object(launcher, '_launch_app'): |
1109 | + with patch.object(launcher, '_get_pid_for_launched_app') as gp: |
1110 | + with patch.object(launcher, '_get_glib_loop'): |
1111 | + launcher.launch(token) |
1112 | + gp.assert_called_once_with(token) |
1113 | + |
1114 | + @patch('autopilot.application._launcher.' |
1115 | + 'get_proxy_object_for_existing_process') |
1116 | + def test_gets_correct_proxy_object(self, gpofep): |
1117 | + launcher = UpstartApplicationLauncher() |
1118 | + with patch.object(launcher, '_launch_app'): |
1119 | + with patch.object(launcher, '_get_pid_for_launched_app') as gp: |
1120 | + with patch.object(launcher, '_get_glib_loop'): |
1121 | + launcher.launch('') |
1122 | + gpofep.assert_called_once_with(pid=gp.return_value, |
1123 | + emulator_base=None, |
1124 | + dbus_bus='session') |
1125 | + |
1126 | + @patch('autopilot.application._launcher.' |
1127 | + 'get_proxy_object_for_existing_process') |
1128 | + def test_returns_proxy_object(self, gpofep): |
1129 | + launcher = UpstartApplicationLauncher() |
1130 | + with patch.object(launcher, '_launch_app'): |
1131 | + with patch.object(launcher, '_get_pid_for_launched_app'): |
1132 | + with patch.object(launcher, '_get_glib_loop'): |
1133 | + result = launcher.launch('') |
1134 | + self.assertEqual(result, gpofep.return_value) |
1135 | + |
1136 | + @patch('autopilot.application._launcher.' |
1137 | + 'get_proxy_object_for_existing_process') |
1138 | + def test_calls_get_glib_loop(self, gpofep): |
1139 | + launcher = UpstartApplicationLauncher() |
1140 | + with patch.object(launcher, '_launch_app'): |
1141 | + with patch.object(launcher, '_get_pid_for_launched_app'): |
1142 | + with patch.object(launcher, '_get_glib_loop') as ggl: |
1143 | + launcher.launch('') |
1144 | + ggl.assert_called_once_with() |
1145 | |
1146 | def assertFailedObserverSetsExtraMessage(self, fail_type, expected_msg): |
1147 | """Assert that the on_failed observer must set the expected message |
1148 | |
1149 | === modified file 'autopilot/tests/unit/test_testcase.py' |
1150 | --- autopilot/tests/unit/test_testcase.py 2014-05-12 20:59:37 +0000 |
1151 | +++ autopilot/tests/unit/test_testcase.py 2014-05-23 09:57:29 +0000 |
1152 | @@ -110,3 +110,53 @@ |
1153 | ep.assert_called_once_with('foo', 'bar') |
1154 | self.assertIn(call().setUp(), ep.mock_calls) |
1155 | self.assertIn(call().cleanUp(), ep.mock_calls) |
1156 | + |
1157 | + @patch('autopilot.testcase.NormalApplicationLauncher') |
1158 | + def test_launch_test_application(self, nal): |
1159 | + class LauncherTest(AutopilotTestCase): |
1160 | + |
1161 | + """Test launchers.""" |
1162 | + |
1163 | + def test_anything(self): |
1164 | + pass |
1165 | + |
1166 | + test_case = LauncherTest('test_anything') |
1167 | + with patch.object(test_case, 'useFixture') as uf: |
1168 | + result = test_case.launch_test_application('a', 'b', 'c') |
1169 | + uf.assert_called_once_with(nal.return_value) |
1170 | + uf.return_value.launch.assert_called_once_with('a', ('b', 'c')) |
1171 | + self.assertEqual(result, uf.return_value.launch.return_value) |
1172 | + |
1173 | + @patch('autopilot.testcase.ClickApplicationLauncher') |
1174 | + def test_launch_click_package(self, cal): |
1175 | + class LauncherTest(AutopilotTestCase): |
1176 | + |
1177 | + """Test launchers.""" |
1178 | + |
1179 | + def test_anything(self): |
1180 | + pass |
1181 | + |
1182 | + test_case = LauncherTest('test_anything') |
1183 | + with patch.object(test_case, 'useFixture') as uf: |
1184 | + result = test_case.launch_click_package('a', 'b', ['c', 'd']) |
1185 | + uf.assert_called_once_with(cal.return_value) |
1186 | + uf.return_value.launch.assert_called_once_with( |
1187 | + 'a', 'b', ['c', 'd'] |
1188 | + ) |
1189 | + self.assertEqual(result, uf.return_value.launch.return_value) |
1190 | + |
1191 | + @patch('autopilot.testcase.UpstartApplicationLauncher') |
1192 | + def test_launch_upstart_application(self, ual): |
1193 | + class LauncherTest(AutopilotTestCase): |
1194 | + |
1195 | + """Test launchers.""" |
1196 | + |
1197 | + def test_anything(self): |
1198 | + pass |
1199 | + |
1200 | + test_case = LauncherTest('test_anything') |
1201 | + with patch.object(test_case, 'useFixture') as uf: |
1202 | + result = test_case.launch_upstart_application('a', ['b']) |
1203 | + uf.assert_called_once_with(ual.return_value) |
1204 | + uf.return_value.launch.assert_called_once_with('a', ['b']) |
1205 | + self.assertEqual(result, uf.return_value.launch.return_value) |
1206 | |
1207 | === modified file 'debian/control' |
1208 | --- debian/control 2014-05-15 08:31:35 +0000 |
1209 | +++ debian/control 2014-05-23 09:57:29 +0000 |
1210 | @@ -134,6 +134,7 @@ |
1211 | libautopilot-gtk (>= 1.4), |
1212 | libautopilot-qt (>= 1.4), |
1213 | python3-autopilot, |
1214 | + python3-dbus.mainloop.qt, |
1215 | python3-evdev, |
1216 | python3-mock, |
1217 | python3-pyqt4, |
1218 | |
1219 | === added file 'docs/api/autopilot.application.rst' |
1220 | --- docs/api/autopilot.application.rst 1970-01-01 00:00:00 +0000 |
1221 | +++ docs/api/autopilot.application.rst 2014-05-23 09:57:29 +0000 |
1222 | @@ -0,0 +1,5 @@ |
1223 | +``autopilot.application`` - Autopilot Application Launchers |
1224 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1225 | + |
1226 | +.. automodule:: autopilot.application |
1227 | + :members: |
1228 | |
1229 | === renamed file 'docs/api/display.rst' => 'docs/api/autopilot.display.rst' |
1230 | === renamed file 'docs/api/emulators.rst' => 'docs/api/autopilot.emulators.rst' |
1231 | === renamed file 'docs/api/exceptions.rst' => 'docs/api/autopilot.exceptions.rst' |
1232 | === renamed file 'docs/api/gestures.rst' => 'docs/api/autopilot.gestures.rst' |
1233 | === renamed file 'docs/api/input.rst' => 'docs/api/autopilot.input.rst' |
1234 | === renamed file 'docs/api/introspection.rst' => 'docs/api/autopilot.introspection.rst' |
1235 | === renamed file 'docs/api/introspection.types.rst' => 'docs/api/autopilot.introspection.types.rst' |
1236 | === renamed file 'docs/api/matchers.rst' => 'docs/api/autopilot.matchers.rst' |
1237 | === renamed file 'docs/api/platform.rst' => 'docs/api/autopilot.platform.rst' |
1238 | === renamed file 'docs/api/process.rst' => 'docs/api/autopilot.process.rst' |
1239 | === renamed file 'docs/api/testcase.rst' => 'docs/api/autopilot.testcase.rst' |
1240 | === modified file 'docs/tutorial/advanced_autopilot.rst' |
1241 | --- docs/tutorial/advanced_autopilot.rst 2014-05-19 07:29:26 +0000 |
1242 | +++ docs/tutorial/advanced_autopilot.rst 2014-05-23 09:57:29 +0000 |
1243 | @@ -409,3 +409,31 @@ |
1244 | |
1245 | # Get all QLabels in the applicaton: |
1246 | labels = self.app.select_many(QLabel) |
1247 | + |
1248 | +.. launching_applications: |
1249 | + |
1250 | +Launching Applications |
1251 | +====================== |
1252 | + |
1253 | +Applications can be launched inside of a testcase using :meth:`~autopilot.testcase.AutopilotTestCase.launch_test_application`, :meth:`~autopilot.testcase.AutopilotTestCase.launch_upstart_application`, and :meth:`~autopilot.testcase.AutopilotTestCase.launch_click_application`. |
1254 | + |
1255 | +Outside of testcase classes, the :class:`~autopilot.application.NormalApplicationLauncher`, :class:`~autopilot.application.UpstartApplicationLauncher`, and :class:`~autopilot.application.ClickApplicationLauncher` fixtures can be used, i.e.:: |
1256 | + |
1257 | + from autopilot.application import NormalApplicationLauncher |
1258 | + |
1259 | + with NormalApplicationLauncher() as launcher: |
1260 | + launcher.launch('gedit') |
1261 | + |
1262 | +Within a fixture or a testcase, ``self.useFixture``can be used:: |
1263 | + |
1264 | + launcher = self.useFixture(NormalApplicationLauncher()) |
1265 | + launcher.launch('gedit', ['--new-window', '/path/to/file']) |
1266 | + |
1267 | +Additional options can also be specified to set a custom addDetail method, a custom proxy base, or a custom dbus bus with which to patch the environment:: |
1268 | + |
1269 | + |
1270 | + launcher = self.useFixture(NormalApplicationLauncher( |
1271 | + case_addDetail=self.addDetail, |
1272 | + dbus_bus='some_other_bus', |
1273 | + proxy_base=my_proxy_class, |
1274 | + )) |
FAILED: Continuous integration, rev:499 /code.launchpad .net/~nuclearbo b/autopilot/ launch- function/ +merge/ 220094/ +edit-commit- message
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:/
http:// jenkins. qa.ubuntu. com/job/ autopilot- autopilot- temp-dev- ci/78/ jenkins. qa.ubuntu. com/job/ autopilot- autopilot- temp-dev- utopic- amd64-ci/ 36/console jenkins. qa.ubuntu. com/job/ autopilot- autopilot- temp-dev- utopic- armhf-ci/ 36/console jenkins. qa.ubuntu. com/job/ autopilot- autopilot- temp-dev- utopic- i386-ci/ 36/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- utopic- autopilot/ 76/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/363/ console
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/autopilot- autopilot- temp-dev- ci/78/rebuild
http://