Merge lp:~canonical-platform-qa/unity8/dash-as-app-autopilot into lp:~unity-team/unity8/dash-as-app
- dash-as-app-autopilot
- Merge into dash-as-app
Status: | Superseded |
---|---|
Proposed branch: | lp:~canonical-platform-qa/unity8/dash-as-app-autopilot |
Merge into: | lp:~unity-team/unity8/dash-as-app |
Prerequisite: | lp:~gerboland/unity8/fix-run.sh-script |
Diff against target: |
958 lines (+410/-182) 12 files modified
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py (+1/-1) tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py (+3/-2) tests/autopilot/unity8/fixture_setup.py (+65/-0) tests/autopilot/unity8/process_helpers.py (+92/-23) tests/autopilot/unity8/shell/emulators/dash.py (+21/-8) tests/autopilot/unity8/shell/emulators/greeter.py (+4/-1) tests/autopilot/unity8/shell/emulators/main_window.py (+34/-20) tests/autopilot/unity8/shell/tests/__init__.py (+143/-50) tests/autopilot/unity8/shell/tests/test_emulators.py (+7/-18) tests/autopilot/unity8/shell/tests/test_lock_screen.py (+8/-47) tests/autopilot/unity8/shell/tests/test_notifications.py (+12/-7) tests/autopilot/unity8/shell/tests/test_upstart.py (+20/-5) |
To merge this branch: | bzr merge lp:~canonical-platform-qa/unity8/dash-as-app-autopilot |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity Team | Pending | ||
Review via email: mp+228928@code.launchpad.net |
This proposal supersedes a proposal from 2014-07-30.
This proposal has been superseded by a proposal from 2014-07-31.
Commit message
Update the autopilot tests to work with the new dash app.
Description of the change
Leo Arias (elopio) wrote : Posted in a previous version of this proposal | # |
- 1109. By Leo Arias
-
Updated the notifications tests.
- 1110. By Leo Arias
-
Updated the wait for unity.
- 1111. By Leo Arias
-
Updated the test search.
- 1112. By Leo Arias
-
Updated the upstart tests.
- 1113. By Leo Arias
-
Removed the unused function.
- 1114. By Leo Arias
-
Fixed the error reporting.
- 1115. By Leo Arias
-
Make sure that unity is running and the dash is not.
- 1116. By Leo Arias
-
Hide unity7 launcher.
- 1117. By Leo Arias
-
Removed unused helper.
- 1118. By Leo Arias
-
Updated the lifecycle tests.
- 1119. By Leo Arias
-
Pass the testability as an argument.
- 1120. By Leo Arias
-
Merged with trunk.
- 1121. By Leo Arias
-
Removed extra space.
- 1122. By Leo Arias
-
Removed tags.
- 1123. By Leo Arias
-
Merged with prerequisite.
- 1124. By Leo Arias
-
Remove unused import.
- 1125. By Leo Arias
-
Fixed typo.
- 1126. By Leo Arias
-
Fixed typo.
- 1127. By Leo Arias
-
Fixed grammar erro.
- 1128. By Leo Arias
-
Only check for the start part of the status, as suggested by saviq.
Unmerged revisions
- 1128. By Leo Arias
-
Only check for the start part of the status, as suggested by saviq.
- 1127. By Leo Arias
-
Fixed grammar erro.
- 1126. By Leo Arias
-
Fixed typo.
- 1125. By Leo Arias
-
Fixed typo.
- 1124. By Leo Arias
-
Remove unused import.
- 1123. By Leo Arias
-
Merged with prerequisite.
- 1122. By Leo Arias
-
Removed tags.
- 1121. By Leo Arias
-
Removed extra space.
- 1120. By Leo Arias
-
Merged with trunk.
- 1119. By Leo Arias
-
Pass the testability as an argument.
Preview Diff
1 | === modified file 'tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py' |
2 | --- tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py 2014-06-11 15:36:51 +0000 |
3 | +++ tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py 2014-07-31 14:59:26 +0000 |
4 | @@ -106,7 +106,7 @@ |
5 | self.assert_current_focused_application(application_name) |
6 | |
7 | self.main_window.show_dash_swiping() |
8 | - self.assert_current_focused_application('') |
9 | + self.assert_current_focused_application('unity8-dash') |
10 | |
11 | process_helpers.lock_unity() |
12 | greeter = self.main_window.get_greeter() |
13 | |
14 | === modified file 'tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py' |
15 | --- tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py 2014-06-11 15:36:51 +0000 |
16 | +++ tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py 2014-07-31 14:59:26 +0000 |
17 | @@ -39,7 +39,8 @@ |
18 | desktop_file_name = os.path.basename(desktop_file_path) |
19 | application_name, _ = os.path.splitext(desktop_file_name) |
20 | |
21 | - self.assertEqual('', self.main_window.get_current_focused_app_id()) |
22 | + self.assertEqual( |
23 | + 'unity8-dash', self.main_window.get_current_focused_app_id()) |
24 | self.addCleanup(os.system, 'pkill qmlscene') |
25 | |
26 | subprocess.check_call( |
27 | @@ -47,4 +48,4 @@ |
28 | self.assert_current_focused_application(application_name) |
29 | |
30 | self.main_window.show_dash_swiping() |
31 | - self.assert_current_focused_application('') |
32 | + self.assert_current_focused_application('unity8-dash') |
33 | |
34 | === added file 'tests/autopilot/unity8/fixture_setup.py' |
35 | --- tests/autopilot/unity8/fixture_setup.py 1970-01-01 00:00:00 +0000 |
36 | +++ tests/autopilot/unity8/fixture_setup.py 2014-07-31 14:59:26 +0000 |
37 | @@ -0,0 +1,65 @@ |
38 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
39 | +# |
40 | +# Unity Autopilot Test Suite |
41 | +# Copyright (C) 2014 Canonical |
42 | +# |
43 | +# This program is free software: you can redistribute it and/or modify |
44 | +# it under the terms of the GNU General Public License as published by |
45 | +# the Free Software Foundation, either version 3 of the License, or |
46 | +# (at your option) any later version. |
47 | +# |
48 | +# This program is distributed in the hope that it will be useful, |
49 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
50 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
51 | +# GNU General Public License for more details. |
52 | +# |
53 | +# You should have received a copy of the GNU General Public License |
54 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
55 | +# |
56 | + |
57 | +import fixtures |
58 | +from autopilot import introspection |
59 | +from ubuntuuitoolkit import fixture_setup as toolkit_fixtures |
60 | + |
61 | +from unity8 import process_helpers |
62 | +from unity8.shell import emulators |
63 | + |
64 | + |
65 | +class LaunchDashApp(fixtures.Fixture): |
66 | + |
67 | + """Fixture to launch the Dashh app.""" |
68 | + |
69 | + def __init__(self, binary_path, variables): |
70 | + """Initialize an instance. |
71 | + |
72 | + :param str binary_path: The path to the Dash app binary. |
73 | + :param variables: The variables to use when launching the app. |
74 | + :type variables: A dictionary. |
75 | + |
76 | + """ |
77 | + super(LaunchDashApp, self).__init__() |
78 | + self.binary_path = binary_path |
79 | + self.variables = variables |
80 | + |
81 | + def setUp(self): |
82 | + """Launch the dash app when the fixture is used.""" |
83 | + super(LaunchDashApp, self).setUp() |
84 | + self.addCleanup(self.stop_application) |
85 | + self.application_proxy = self.launch_application() |
86 | + |
87 | + def launch_application(self): |
88 | + binary_arg = 'BINARY={}'.format(self.binary_path) |
89 | + testability_arg = 'QT_LOAD_TESTABILITY={}'.format(1) |
90 | + env_args = [ |
91 | + '{}={}'.format(key, value) for key, value in self.variables.items() |
92 | + ] |
93 | + all_args = [binary_arg, testability_arg] + env_args |
94 | + |
95 | + pid = process_helpers.start_job('unity8-dash', *all_args) |
96 | + return introspection.get_proxy_object_for_existing_process( |
97 | + pid=pid, |
98 | + emulator_base=emulators.UnityEmulatorBase, |
99 | + ) |
100 | + |
101 | + def stop_application(self): |
102 | + process_helpers.stop_job('unity8-dash') |
103 | |
104 | === modified file 'tests/autopilot/unity8/process_helpers.py' |
105 | --- tests/autopilot/unity8/process_helpers.py 2014-06-27 13:13:04 +0000 |
106 | +++ tests/autopilot/unity8/process_helpers.py 2014-07-31 14:59:26 +0000 |
107 | @@ -36,6 +36,10 @@ |
108 | logger = logging.getLogger(__name__) |
109 | |
110 | |
111 | +class JobError(Exception): |
112 | + pass |
113 | + |
114 | + |
115 | class CannotAccessUnity(Exception): |
116 | pass |
117 | |
118 | @@ -134,48 +138,113 @@ |
119 | """ |
120 | status = _get_unity_status() |
121 | if "start/" in status: |
122 | - try: |
123 | - output = subprocess.check_output( |
124 | - ['/sbin/initctl', 'stop', 'unity8']) |
125 | - logger.info(output) |
126 | - except subprocess.CalledProcessError as e: |
127 | - e.args += ( |
128 | - "Failed to stop running instance of unity8: %s" % e.output, |
129 | - ) |
130 | - raise |
131 | - |
132 | + stop_job('unity8') |
133 | + |
134 | + pid = start_job('unity8', *args) |
135 | + return _get_unity_proxy_object(pid) |
136 | + |
137 | + |
138 | +def start_job(name, *args): |
139 | + """Start a job. |
140 | + |
141 | + :param str name: The name of the job. |
142 | + :param args: The arguments to be used when starting the job. |
143 | + :return: The process id of the started job. |
144 | + :raises CalledProcessError: if the job failed to start. |
145 | + |
146 | + """ |
147 | + logger.info('Starting job {} with arguments {}.'.format(name, args)) |
148 | + command = ['/sbin/initctl', 'start', name] + list(args) |
149 | try: |
150 | - command = ['/sbin/initctl', 'start', 'unity8'] + list(args) |
151 | output = subprocess.check_output( |
152 | command, |
153 | stderr=subprocess.STDOUT, |
154 | universal_newlines=True, |
155 | ) |
156 | logger.info(output) |
157 | - pid = _get_unity_pid() |
158 | + pid = get_job_pid(name) |
159 | except subprocess.CalledProcessError as e: |
160 | - e.args += ("Failed to start unity8: %s" % e.output,) |
161 | + e.args += ('Failed to start {}: {}.'.format(name, e.output),) |
162 | raise |
163 | else: |
164 | - return _get_unity_proxy_object(pid) |
165 | - |
166 | - |
167 | -def _get_unity_status(): |
168 | + return pid |
169 | + |
170 | + |
171 | +def get_job_pid(name): |
172 | + """Return the process id of a running job. |
173 | + |
174 | + :param str name: The name of the job. |
175 | + :raises JobError: if the job is not running. |
176 | + |
177 | + """ |
178 | + status = get_job_status(name) |
179 | + if "start/" not in status: |
180 | + raise JobError('{} is not in the running state.'.format(name)) |
181 | + return int(status.split()[-1]) |
182 | + |
183 | + |
184 | +def get_job_status(name): |
185 | + """Return the status of a job. |
186 | + |
187 | + :param str name: The name of the job. |
188 | + :raises JobError: if it's not possible to get the status of the job. |
189 | + |
190 | + """ |
191 | try: |
192 | return subprocess.check_output([ |
193 | '/sbin/initctl', |
194 | 'status', |
195 | - 'unity8' |
196 | + name |
197 | ], universal_newlines=True) |
198 | + except subprocess.CalledProcessError as error: |
199 | + raise JobError( |
200 | + "Unable to get {}'s status: {}".format(name, error) |
201 | + ) |
202 | + |
203 | + |
204 | +def stop_job(name): |
205 | + """Stop a job. |
206 | + |
207 | + :param str name: The name of the job. |
208 | + :raises CalledProcessError: if the job failed to stop. |
209 | + |
210 | + """ |
211 | + logger.info('Stoping job {}.'.format(name)) |
212 | + command = ['/sbin/initctl', 'stop', name] |
213 | + try: |
214 | + output = subprocess.check_output( |
215 | + command, |
216 | + stderr=subprocess.STDOUT, |
217 | + universal_newlines=True, |
218 | + ) |
219 | + logger.info(output) |
220 | except subprocess.CalledProcessError as e: |
221 | - raise CannotAccessUnity("Unable to get unity's status: %s" % str(e)) |
222 | + e.args += ('Failed to stop {}: {}.'.format(name, e.output),) |
223 | + raise |
224 | + |
225 | + |
226 | +def is_job_running(name): |
227 | + """Return True if the job is running. Otherwise, False. |
228 | + |
229 | + :param str name: The name of the job. |
230 | + :raises JobError: if it's not possible to get the status of the job. |
231 | + |
232 | + """ |
233 | + return 'start/running' in get_job_status(name) |
234 | + |
235 | + |
236 | +def _get_unity_status(): |
237 | + try: |
238 | + return get_job_status('unity8') |
239 | + except JobError as error: |
240 | + raise CannotAccessUnity(str(error)) |
241 | |
242 | |
243 | def _get_unity_pid(): |
244 | - status = _get_unity_status() |
245 | - if "start/" not in status: |
246 | - raise CannotAccessUnity("Unity is not in the running state.") |
247 | - return int(status.split()[-1]) |
248 | + try: |
249 | + return get_job_pid('unity8') |
250 | + except JobError as error: |
251 | + raise CannotAccessUnity(str(error)) |
252 | |
253 | |
254 | def _get_unity_proxy_object(pid): |
255 | |
256 | === modified file 'tests/autopilot/unity8/shell/emulators/dash.py' |
257 | --- tests/autopilot/unity8/shell/emulators/dash.py 2014-07-28 17:06:57 +0000 |
258 | +++ tests/autopilot/unity8/shell/emulators/dash.py 2014-07-31 14:59:26 +0000 |
259 | @@ -31,6 +31,17 @@ |
260 | logger = logging.getLogger(__name__) |
261 | |
262 | |
263 | +class DashApp(object): |
264 | + |
265 | + """Autopilot helper for the Dash app.""" |
266 | + |
267 | + def __init__(self, app_proxy): |
268 | + self.app_proxy = app_proxy |
269 | + self.main_view = self.app_proxy.select_single( |
270 | + toolkit_emulators.MainView) |
271 | + self.dash = self.main_view.select_single(Dash) |
272 | + |
273 | + |
274 | class Dash(emulators.UnityEmulatorBase): |
275 | """An emulator that understands the Dash.""" |
276 | |
277 | @@ -109,20 +120,22 @@ |
278 | @autopilot_logging.log_action(logger.info) |
279 | def _scroll_to_left_scope(self): |
280 | original_index = self.dash_content_list.currentIndex |
281 | - dashContent = self.select_single(objectName="dashContent") |
282 | - start_x = dashContent.width / 3 |
283 | - stop_x = dashContent.width / 3 * 2 |
284 | - start_y = stop_y = dashContent.globalRect.y + 1 |
285 | + dash_content = self.select_single(objectName="dashContent") |
286 | + x, y, width, height = dash_content.globalRect |
287 | + start_x = x + width / 3 |
288 | + stop_x = x + width / 3 * 2 |
289 | + start_y = stop_y = y + 1 |
290 | self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
291 | self.dash_content_list.currentIndex.wait_for(original_index - 1) |
292 | |
293 | @autopilot_logging.log_action(logger.info) |
294 | def _scroll_to_right_scope(self): |
295 | original_index = self.dash_content_list.currentIndex |
296 | - dashContent = self.select_single(objectName="dashContent") |
297 | - start_x = dashContent.width / 3 * 2 |
298 | - stop_x = dashContent.width / 3 |
299 | - start_y = stop_y = dashContent.globalRect.y + 1 |
300 | + dash_content = self.select_single(objectName="dashContent") |
301 | + x, y, width, height = dash_content.globalRect |
302 | + start_x = x + width / 3 * 2 |
303 | + stop_x = x + width / 3 |
304 | + start_y = stop_y = y + 1 |
305 | self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
306 | self.dash_content_list.currentIndex.wait_for(original_index + 1) |
307 | |
308 | |
309 | === modified file 'tests/autopilot/unity8/shell/emulators/greeter.py' |
310 | --- tests/autopilot/unity8/shell/emulators/greeter.py 2014-01-09 15:53:05 +0000 |
311 | +++ tests/autopilot/unity8/shell/emulators/greeter.py 2014-07-31 14:59:26 +0000 |
312 | @@ -17,6 +17,8 @@ |
313 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
314 | # |
315 | |
316 | +import ubuntuuitoolkit |
317 | + |
318 | from unity8.shell.emulators import UnityEmulatorBase |
319 | |
320 | |
321 | @@ -37,4 +39,5 @@ |
322 | self.created.wait_for(False) |
323 | |
324 | def get_prompt(self): |
325 | - return self.select_single("TextField", objectName="passwordInput") |
326 | + return self.select_single( |
327 | + ubuntuuitoolkit.TextField, objectName='passwordInput') |
328 | |
329 | === modified file 'tests/autopilot/unity8/shell/emulators/main_window.py' |
330 | --- tests/autopilot/unity8/shell/emulators/main_window.py 2014-07-09 13:16:20 +0000 |
331 | +++ tests/autopilot/unity8/shell/emulators/main_window.py 2014-07-31 14:59:26 +0000 |
332 | @@ -25,7 +25,6 @@ |
333 | from unity8.shell import emulators |
334 | from unity8.shell.emulators.greeter import Greeter |
335 | from unity8.shell.emulators.hud import Hud |
336 | -from unity8.shell.emulators.dash import Dash |
337 | from unity8.shell.emulators.launcher import Launcher |
338 | |
339 | logger = logging.getLogger(__name__) |
340 | @@ -61,9 +60,6 @@ |
341 | def get_hud_edge_drag_area(self): |
342 | return self.select_single(objectName="hudDragArea") |
343 | |
344 | - def get_dash(self): |
345 | - return self.select_single(Dash) |
346 | - |
347 | def get_bottombar(self): |
348 | return self.select_single("Bottombar") |
349 | |
350 | @@ -76,12 +72,6 @@ |
351 | objectName="pinPadLoader" |
352 | ) |
353 | |
354 | - def get_pinPadButton(self, buttonId): |
355 | - return self.select_single( |
356 | - "PinPadButton", |
357 | - objectName="pinPadButton%i" % buttonId |
358 | - ) |
359 | - |
360 | def get_lockscreen(self): |
361 | return self.select_single("Lockscreen") |
362 | |
363 | @@ -117,20 +107,44 @@ |
364 | @autopilot_logging.log_action(logger.info) |
365 | def show_dash_swiping(self): |
366 | """Show the dash swiping from the left.""" |
367 | - width = self.width |
368 | - height = self.height |
369 | - start_x = 0 |
370 | - start_y = height // 2 |
371 | - end_x = width |
372 | - end_y = start_y |
373 | + x, y, width, height = self._get_shell().globalRect |
374 | + start_x = x |
375 | + end_x = x + width |
376 | + start_y = end_y = y + height // 2 |
377 | |
378 | self.pointing_device.drag(start_x, start_y, end_x, end_y) |
379 | - return self.get_dash() |
380 | + |
381 | + def _get_shell(self): |
382 | + return self.select_single('Shell') |
383 | |
384 | def get_current_focused_app_id(self): |
385 | """Return the id of the focused application.""" |
386 | - return self.select_single('Shell').focusedApplicationId |
387 | + return self._get_shell().focusedApplicationId |
388 | |
389 | @autopilot_logging.log_action(logger.info) |
390 | - def search(self, query): |
391 | - self.get_dash().enter_search_query(query) |
392 | + def enter_pin_code(self, code): |
393 | + """Enter code 'code' into the single-pin lightdm pincode entry screen. |
394 | + |
395 | + :param code: must be a string of numeric characters. |
396 | + :raises: TypeError if code is not a string. |
397 | + :raises: ValueError if code contains non-numeric characters. |
398 | + |
399 | + """ |
400 | + if not isinstance(code, str): |
401 | + raise TypeError( |
402 | + "'code' parameter must be a string, not %r." |
403 | + % type(code) |
404 | + ) |
405 | + for num in code: |
406 | + if not num.isdigit(): |
407 | + raise ValueError( |
408 | + "'code' parameter contains non-numeric characters." |
409 | + ) |
410 | + self.pointing_device.click_object( |
411 | + self._get_pinpad_button(int(num))) |
412 | + |
413 | + def _get_pinpad_button(self, button_id): |
414 | + return self.select_single( |
415 | + 'PinPadButton', |
416 | + objectName='pinPadButton{}'.format(button_id) |
417 | + ) |
418 | |
419 | === modified file 'tests/autopilot/unity8/shell/tests/__init__.py' |
420 | --- tests/autopilot/unity8/shell/tests/__init__.py 2014-06-27 13:13:04 +0000 |
421 | +++ tests/autopilot/unity8/shell/tests/__init__.py 2014-07-31 14:59:26 +0000 |
422 | @@ -24,6 +24,7 @@ |
423 | except ImportError: |
424 | Gio = None |
425 | |
426 | +from autopilot import introspection |
427 | from autopilot.platform import model |
428 | from autopilot.testcase import AutopilotTestCase |
429 | from autopilot.matchers import Eventually |
430 | @@ -34,6 +35,10 @@ |
431 | import subprocess |
432 | import sys |
433 | from testtools.matchers import Equals |
434 | +from ubuntuuitoolkit import ( |
435 | + fixture_setup as toolkit_fixtures, |
436 | + ubuntu_scenarios |
437 | +) |
438 | |
439 | from unity8 import ( |
440 | get_lib_path, |
441 | @@ -42,9 +47,15 @@ |
442 | get_default_extra_mock_libraries, |
443 | get_data_dirs |
444 | ) |
445 | -from unity8.process_helpers import restart_unity_with_testability |
446 | -from unity8.shell.emulators import main_window as main_window_emulator |
447 | -from unity8.shell.emulators.dash import Dash |
448 | +from unity8 import ( |
449 | + fixture_setup, |
450 | + process_helpers |
451 | +) |
452 | +from unity8.shell import emulators |
453 | +from unity8.shell.emulators import ( |
454 | + dash as dash_helpers, |
455 | + main_window as main_window_emulator, |
456 | +) |
457 | |
458 | |
459 | logger = logging.getLogger(__name__) |
460 | @@ -78,6 +89,26 @@ |
461 | return [native] |
462 | |
463 | |
464 | +def is_unity7_running(): |
465 | + """Return True if Unity7 is running. Otherwise, return False.""" |
466 | + return ( |
467 | + Gio is not None and |
468 | + UNITYSHELL_GSETTINGS_SCHEMA in |
469 | + Gio.Settings.list_relocatable_schemas() |
470 | + ) |
471 | + |
472 | + |
473 | +def get_qml_import_path_with_mock(): |
474 | + """Return the QML2_IMPORT_PATH value with the mock path preppended.""" |
475 | + qml_import_path = [get_mocks_library_path()] |
476 | + if os.getenv('QML2_IMPORT_PATH') is not None: |
477 | + qml_import_path.append(os.getenv('QML2_IMPORT_PATH')) |
478 | + |
479 | + qml_import_path = ':'.join(qml_import_path) |
480 | + logger.info("New QML2 import path: %s", qml_import_path) |
481 | + return qml_import_path |
482 | + |
483 | + |
484 | class UnityTestCase(AutopilotTestCase): |
485 | |
486 | """A test case base class for the Unity shell tests.""" |
487 | @@ -118,23 +149,8 @@ |
488 | |
489 | def setUp(self): |
490 | super(UnityTestCase, self).setUp() |
491 | - if (Gio is not None and |
492 | - UNITYSHELL_GSETTINGS_SCHEMA in |
493 | - Gio.Settings.list_relocatable_schemas()): |
494 | - |
495 | - # Hide Unity launcher |
496 | - self._unityshell_schema = Gio.Settings.new_with_path( |
497 | - UNITYSHELL_GSETTINGS_SCHEMA, |
498 | - UNITYSHELL_GSETTINGS_PATH, |
499 | - ) |
500 | - self._launcher_hide_mode = self._unityshell_schema.get_int( |
501 | - UNITYSHELL_LAUNCHER_KEY, |
502 | - ) |
503 | - self._unityshell_schema.set_int( |
504 | - UNITYSHELL_LAUNCHER_KEY, |
505 | - UNITYSHELL_LAUNCHER_MODE, |
506 | - ) |
507 | - self.addCleanup(self._reset_launcher) |
508 | + if is_unity7_running(): |
509 | + self.useFixture(toolkit_fixtures.HideUnity7Launcher()) |
510 | |
511 | self._proxy = None |
512 | self._lightdm_mock_type = None |
513 | @@ -151,13 +167,6 @@ |
514 | self.touch = Touch.create() |
515 | self._setup_display_details() |
516 | |
517 | - def _reset_launcher(self): |
518 | - """Reset Unity launcher hide mode""" |
519 | - self._unityshell_schema.set_int( |
520 | - UNITYSHELL_LAUNCHER_KEY, |
521 | - self._launcher_hide_mode, |
522 | - ) |
523 | - |
524 | def _setup_display_details(self): |
525 | scale_divisor = self._determine_geometry() |
526 | self._setup_grid_size(scale_divisor) |
527 | @@ -263,7 +272,9 @@ |
528 | self.patch_lightdm_mock() |
529 | |
530 | if self._qml_mock_enabled: |
531 | - self._setup_extra_mock_environment_patch() |
532 | + self._environment['QML2_IMPORT_PATH'] = ( |
533 | + get_qml_import_path_with_mock() |
534 | + ) |
535 | |
536 | if self._data_dirs_mock_enabled: |
537 | self._patch_data_dirs() |
538 | @@ -292,9 +303,14 @@ |
539 | |
540 | # Ensure that the dash is visible before we return: |
541 | logger.debug("Unity started, waiting for it to be ready.") |
542 | - self.assertUnityReady() |
543 | + self.wait_for_unity() |
544 | logger.debug("Unity loaded and ready.") |
545 | |
546 | + if model() == 'Desktop': |
547 | + # On desktop, close the dash because it's opened in a separate |
548 | + # window and it gets on the way. |
549 | + process_helpers.stop_job('unity8-dash') |
550 | + |
551 | return app_proxy |
552 | |
553 | def _launch_unity_with_upstart(self, binary_path, args): |
554 | @@ -308,7 +324,7 @@ |
555 | |
556 | self.addCleanup(self._cleanup_launching_upstart_unity) |
557 | |
558 | - return restart_unity_with_testability(*all_args) |
559 | + return process_helpers.restart_unity_with_testability(*all_args) |
560 | |
561 | def _cleanup_launching_upstart_unity(self): |
562 | logger.info("Stopping unity") |
563 | @@ -353,15 +369,6 @@ |
564 | ) |
565 | return lightdm_mock_path |
566 | |
567 | - def _setup_extra_mock_environment_patch(self): |
568 | - qml_import_path = [get_mocks_library_path()] |
569 | - if os.getenv('QML2_IMPORT_PATH') is not None: |
570 | - qml_import_path.append(os.getenv('QML2_IMPORT_PATH')) |
571 | - |
572 | - qml_import_path = ':'.join(qml_import_path) |
573 | - logger.info("New QML2 import path: %s", qml_import_path) |
574 | - self._environment['QML2_IMPORT_PATH'] = qml_import_path |
575 | - |
576 | def _set_proxy(self, proxy): |
577 | """Keep a copy of the proxy object, so we can use it to get common |
578 | parts of the shell later on. |
579 | @@ -373,10 +380,80 @@ |
580 | def _clear_proxy(self): |
581 | self._proxy = None |
582 | |
583 | - def assertUnityReady(self): |
584 | - dash = self.get_dash() |
585 | - home_scope = dash.get_scope('clickscope') |
586 | - |
587 | + def wait_for_unity(self): |
588 | + greeter_content_loader = self.main_window.wait_select_single( |
589 | + objectName='greeterContentLoader') |
590 | + greeter_content_loader.progress.wait_for(1) |
591 | + |
592 | + def get_dash(self): |
593 | + pid = process_helpers.get_job_pid('unity8-dash') |
594 | + dash_proxy = introspection.get_proxy_object_for_existing_process( |
595 | + pid=pid, |
596 | + emulator_base=emulators.UnityEmulatorBase, |
597 | + ) |
598 | + dash_app = dash_helpers.DashApp(dash_proxy) |
599 | + return dash_app.dash |
600 | + |
601 | + @property |
602 | + def main_window(self): |
603 | + return self._proxy.select_single(main_window_emulator.QQuickView) |
604 | + |
605 | + |
606 | +class DashBaseTestCase(AutopilotTestCase): |
607 | + |
608 | + scenarios = ubuntu_scenarios.get_device_simulation_scenarios() |
609 | + qml_mock_enabled = True |
610 | + environment = {} |
611 | + |
612 | + def setUp(self): |
613 | + super(DashBaseTestCase, self).setUp() |
614 | + |
615 | + if is_unity7_running(): |
616 | + self.useFixture(toolkit_fixtures.HideUnity7Launcher()) |
617 | + |
618 | + if model() != 'Desktop': |
619 | + # On the phone, we need unity to be running and unlocked. |
620 | + self.addCleanup(process_helpers.stop_job, 'unity8') |
621 | + process_helpers.restart_unity_with_testability() |
622 | + process_helpers.unlock_unity() |
623 | + |
624 | + self.ensure_dash_not_running() |
625 | + |
626 | + if self.qml_mock_enabled: |
627 | + self.environment['QML2_IMPORT_PATH'] = ( |
628 | + get_qml_import_path_with_mock() |
629 | + ) |
630 | + |
631 | + if self.should_simulate_device(): |
632 | + # This sets the grid units, so it should be called before launching |
633 | + # the app. |
634 | + self.simulate_device() |
635 | + |
636 | + binary_path = get_binary_path('unity8-dash') |
637 | + dash_proxy = self.launch_dash(binary_path, self.environment) |
638 | + |
639 | + if self.should_simulate_device(): |
640 | + # XXX Currently we have no way to launch the application with a |
641 | + # specific size, so we must resize it after it's launched. |
642 | + # --elopio - 2014-06-25 |
643 | + self.resize_window() |
644 | + |
645 | + self.dash_app = dash_helpers.DashApp(dash_proxy) |
646 | + self.dash = self.dash_app.dash |
647 | + self.wait_for_dash() |
648 | + |
649 | + def ensure_dash_not_running(self): |
650 | + if process_helpers.is_job_running('unity8-dash'): |
651 | + process_helpers.stop_job('unity8-dash') |
652 | + |
653 | + def launch_dash(self, binary_path, variables): |
654 | + launch_dash_app_fixture = fixture_setup.LaunchDashApp( |
655 | + binary_path, variables) |
656 | + self.useFixture(launch_dash_app_fixture) |
657 | + return launch_dash_app_fixture.application_proxy |
658 | + |
659 | + def wait_for_dash(self): |
660 | + home_scope = self.dash.get_scope('clickscope') |
661 | # FIXME! There is a huge timeout here for when we're doing CI on |
662 | # VMs. See lp:1203715 |
663 | self.assertThat( |
664 | @@ -385,10 +462,26 @@ |
665 | ) |
666 | self.assertThat(home_scope.isCurrent, Eventually(Equals(True))) |
667 | |
668 | - def get_dash(self): |
669 | - dash = self._proxy.wait_select_single(Dash) |
670 | - return dash |
671 | - |
672 | - @property |
673 | - def main_window(self): |
674 | - return self._proxy.select_single(main_window_emulator.QQuickView) |
675 | + def should_simulate_device(self): |
676 | + return (hasattr(self, 'app_width') and hasattr(self, 'app_height') and |
677 | + hasattr(self, 'grid_unit_px')) |
678 | + |
679 | + def simulate_device(self): |
680 | + simulate_device_fixture = self.useFixture( |
681 | + toolkit_fixtures.SimulateDevice( |
682 | + self.app_width, self.app_height, self.grid_unit_px)) |
683 | + self.app_width = simulate_device_fixture.app_width |
684 | + self.app_height = simulate_device_fixture.app_height |
685 | + |
686 | + def resize_window(self): |
687 | + application = self.process_manager.get_running_applications()[0] |
688 | + window = application.get_windows()[0] |
689 | + window.resize(self.app_width, self.app_height) |
690 | + |
691 | + def get_window_size(): |
692 | + _, _, window_width, window_height = window.geometry |
693 | + return window_width, window_height |
694 | + |
695 | + self.assertThat( |
696 | + get_window_size, |
697 | + Eventually(Equals((self.app_width, self.app_height)))) |
698 | |
699 | === modified file 'tests/autopilot/unity8/shell/tests/test_emulators.py' |
700 | --- tests/autopilot/unity8/shell/tests/test_emulators.py 2014-07-25 11:49:28 +0000 |
701 | +++ tests/autopilot/unity8/shell/tests/test_emulators.py 2014-07-31 14:59:26 +0000 |
702 | @@ -47,25 +47,14 @@ |
703 | unity_proxy = self.launch_unity() |
704 | process_helpers.unlock_unity(unity_proxy) |
705 | |
706 | + |
707 | +class DashEmulatorTestCase(tests.DashBaseTestCase): |
708 | + |
709 | def test_search(self): |
710 | - self.main_window.search('Test') |
711 | - text_field = self.main_window.get_dash()._get_search_text_field() |
712 | + self.dash.enter_search_query('Test') |
713 | + text_field = self.dash._get_search_text_field() |
714 | self.assertEqual(text_field.text, 'Test') |
715 | |
716 | - |
717 | -class DashBaseTestCase(tests.UnityTestCase): |
718 | - |
719 | - scenarios = tests._get_device_emulation_scenarios() |
720 | - |
721 | - def setUp(self): |
722 | - super(DashBaseTestCase, self).setUp() |
723 | - unity_proxy = self.launch_unity() |
724 | - process_helpers.unlock_unity(unity_proxy) |
725 | - self.dash = self.main_window.get_dash() |
726 | - |
727 | - |
728 | -class DashEmulatorTestCase(DashBaseTestCase): |
729 | - |
730 | def test_open_unexisting_scope(self): |
731 | scope_name = 'unexisting' |
732 | with mock.patch.object(self.dash, 'pointing_device') as mock_pointer: |
733 | @@ -145,7 +134,7 @@ |
734 | self.assertIsInstance(scope, dash_emulators.GenericScopeView) |
735 | |
736 | |
737 | -class GenericScopeViewEmulatorTestCase(DashBaseTestCase): |
738 | +class GenericScopeViewEmulatorTestCase(tests.DashBaseTestCase): |
739 | |
740 | def setUp(self): |
741 | # Set up the fake scopes before launching unity. |
742 | @@ -159,7 +148,7 @@ |
743 | self.assertTrue(preview.isCurrent) |
744 | |
745 | |
746 | -class DashAppsEmulatorTestCase(DashBaseTestCase): |
747 | +class DashAppsEmulatorTestCase(tests.DashBaseTestCase): |
748 | |
749 | available_applications = [ |
750 | 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4', |
751 | |
752 | === modified file 'tests/autopilot/unity8/shell/tests/test_lock_screen.py' |
753 | --- tests/autopilot/unity8/shell/tests/test_lock_screen.py 2014-06-18 01:52:15 +0000 |
754 | +++ tests/autopilot/unity8/shell/tests/test_lock_screen.py 2014-07-31 14:59:26 +0000 |
755 | @@ -48,10 +48,11 @@ |
756 | unity_proxy = self.launch_unity() |
757 | greeter = self.main_window.get_greeter() |
758 | |
759 | + |
760 | if greeter.narrowMode: |
761 | unlock_unity(unity_proxy) |
762 | lockscreen = self._wait_for_lockscreen() |
763 | - self._enter_pincode("1234") |
764 | + self.main_window.enter_pin_code("1234") |
765 | self.assertThat(lockscreen.shown, Eventually(Equals(False))) |
766 | else: |
767 | self._enter_prompt_passphrase("1234") |
768 | @@ -81,7 +82,7 @@ |
769 | if greeter.narrowMode: |
770 | unlock_unity(unity_proxy) |
771 | lockscreen = self._wait_for_lockscreen() |
772 | - self._enter_pincode("4321") |
773 | + self.main_window.enter_pin_code("4321") |
774 | pinentryField = self.main_window.get_pinentryField() |
775 | self.assertThat(pinentryField.text, Eventually(Equals(""))) |
776 | self.assertThat(lockscreen.shown, Eventually(Equals(True))) |
777 | @@ -118,28 +119,6 @@ |
778 | self.assertThat(lockscreen.shown, Eventually(Equals(True))) |
779 | return lockscreen |
780 | |
781 | - def _enter_pincode(self, code): |
782 | - """Enter code 'code' into the single-pin lightdm pincode entry |
783 | - screen. |
784 | - |
785 | - :param code: must be a string of numeric characters. |
786 | - :raises: TypeError if code is not a string. |
787 | - :raises: ValueError if code contains non-numeric characters. |
788 | - |
789 | - """ |
790 | - |
791 | - if not isinstance(code, basestring): |
792 | - raise TypeError( |
793 | - "'code' parameter must be a string, not %r." |
794 | - % type(code) |
795 | - ) |
796 | - for num in code: |
797 | - if not num.isdigit(): |
798 | - raise ValueError( |
799 | - "'code' parameter contains non-numeric characters." |
800 | - ) |
801 | - self.touch.tap_object(self.main_window.get_pinPadButton(int(num))) |
802 | - |
803 | def _enter_pin_passphrase(self, passphrase): |
804 | """Enter the password specified in 'passphrase' into the password entry |
805 | field of the pin lock screen. |
806 | @@ -148,18 +127,15 @@ |
807 | :raises: TypeError if passphrase is not a string. |
808 | |
809 | """ |
810 | - if not isinstance(passphrase, basestring): |
811 | + if not isinstance(passphrase, str): |
812 | raise TypeError( |
813 | "'passphrase' parameter must be a string, not %r." |
814 | % type(passphrase) |
815 | ) |
816 | |
817 | - pinentryField = self.main_window.get_pinentryField() |
818 | - self.touch.tap_object(pinentryField) |
819 | - self.assertThat(pinentryField.activeFocus, Eventually(Equals(True))) |
820 | - for character in passphrase: |
821 | - self._type_character(character, pinentryField) |
822 | - logger.debug("Typed passphrase: %s", pinentryField.text) |
823 | + pin_entry_field = self.main_window.get_pinentryField() |
824 | + pin_entry_field.write(passphrase) |
825 | + logger.debug("Typed passphrase: %s", pin_entry_field.text) |
826 | self.keyboard.type("\n") |
827 | |
828 | def _enter_prompt_passphrase(self, passphrase): |
829 | @@ -177,21 +153,6 @@ |
830 | ) |
831 | |
832 | prompt = self.main_window.get_greeter().get_prompt() |
833 | - self.touch.tap_object(prompt) |
834 | - self.assertThat(prompt.activeFocus, Eventually(Equals(True))) |
835 | - for character in passphrase: |
836 | - self._type_character(character, prompt) |
837 | + prompt.write(passphrase) |
838 | logger.debug("Typed passphrase: %s", prompt.text) |
839 | self.keyboard.type("\n") |
840 | - |
841 | - def _type_character(self, character, prompt, retries=5): |
842 | - current_text = prompt.text |
843 | - self.keyboard.type(character) |
844 | - try: |
845 | - self.assertThat( |
846 | - prompt.text, Eventually(Equals(current_text + character))) |
847 | - except AssertionError: |
848 | - if retries > 0: |
849 | - self._type_character(character, prompt, retries-1) |
850 | - else: |
851 | - raise |
852 | |
853 | === modified file 'tests/autopilot/unity8/shell/tests/test_notifications.py' |
854 | --- tests/autopilot/unity8/shell/tests/test_notifications.py 2014-07-18 15:13:35 +0000 |
855 | +++ tests/autopilot/unity8/shell/tests/test_notifications.py 2014-07-31 14:59:26 +0000 |
856 | @@ -154,7 +154,7 @@ |
857 | 'Notification', objectName='notification1') |
858 | notification = get_notification() |
859 | |
860 | - self.touch.tap_object( |
861 | + notification.pointing_device.click_object( |
862 | notification.select_single(objectName="interactiveArea") |
863 | ) |
864 | |
865 | @@ -201,11 +201,14 @@ |
866 | 'Notification', objectName='notification1') |
867 | notification = get_notification() |
868 | self._assert_notification(notification, summary, body, True, True, 1.0) |
869 | - initial_height = notification.height |
870 | - self.touch.tap_object(notification.select_single(objectName="combobutton_dropdown")) |
871 | - self.assertThat(notification.select_single(objectName="button2").expanded, Eventually(Equals(True))) |
872 | + notification.pointing_device.click_object( |
873 | + notification.select_single(objectName="combobutton_dropdown")) |
874 | + self.assertThat( |
875 | + notification.select_single(objectName="button2").expanded, |
876 | + Eventually(Equals(True))) |
877 | time.sleep(2) |
878 | - self.touch.tap_object(notification.select_single(objectName="button4")) |
879 | + notification.pointing_device.click_object( |
880 | + notification.select_single(objectName="button4")) |
881 | self.assert_notification_action_id_was_called("action_decline_4") |
882 | |
883 | def test_modal_sd_without_greeter(self): |
884 | @@ -249,7 +252,8 @@ |
885 | notification = get_notification() |
886 | self._assert_notification( |
887 | notification, summary, body, True, False, 1.0) |
888 | - self.touch.tap_object(notification.select_single(objectName="button0")) |
889 | + notification.pointing_device.click_object( |
890 | + notification.select_single(objectName="button0")) |
891 | self.assert_notification_action_id_was_called("action_accept") |
892 | |
893 | def test_modal_sd_with_greeter(self): |
894 | @@ -291,7 +295,8 @@ |
895 | notification = get_notification() |
896 | self._assert_notification( |
897 | notification, summary, body, True, False, 1.0) |
898 | - self.touch.tap_object(notification.select_single(objectName="button0")) |
899 | + notification.pointing_device.click_object( |
900 | + notification.select_single(objectName="button0")) |
901 | self.assert_notification_action_id_was_called("action_accept") |
902 | |
903 | def _create_interactive_notification( |
904 | |
905 | === modified file 'tests/autopilot/unity8/shell/tests/test_upstart.py' |
906 | --- tests/autopilot/unity8/shell/tests/test_upstart.py 2014-07-22 21:07:44 +0000 |
907 | +++ tests/autopilot/unity8/shell/tests/test_upstart.py 2014-07-31 14:59:26 +0000 |
908 | @@ -25,7 +25,8 @@ |
909 | import subprocess |
910 | import time |
911 | |
912 | -from testtools.matchers._basic import Equals |
913 | +import fixtures |
914 | +from testtools.matchers import Equals, MismatchError |
915 | from autopilot.matchers import Eventually |
916 | from autopilot.introspection import get_proxy_object_for_existing_process |
917 | |
918 | @@ -100,16 +101,30 @@ |
919 | emulator_base=UnityEmulatorBase,)) |
920 | |
921 | def test_no_sigstop(self): |
922 | - self.patch_environment("UNITY_MIR_EMITS_SIGSTOP", "") |
923 | + self.useFixture( |
924 | + fixtures.EnvironmentVariable( |
925 | + 'UNITY_MIR_EMITS_SIGSTOP', newvalue=None)) |
926 | self._launch_unity() |
927 | + |
928 | + try: |
929 | + self.assertThat( |
930 | + lambda: os.WIFSTOPPED(self._get_status()), |
931 | + Eventually(Equals(True))) |
932 | + except MismatchError: |
933 | + pass |
934 | + else: |
935 | + self.process.send_singal(signal.SIGCONT) |
936 | + self.fail('Unity8 raised SIGSTOP') |
937 | + |
938 | self._set_proxy() |
939 | |
940 | logger.debug("Unity started, waiting for it to be ready.") |
941 | - self.assertUnityReady() |
942 | + self.wait_for_unity() |
943 | logger.debug("Unity loaded and ready.") |
944 | |
945 | def test_expect_sigstop(self): |
946 | - self.patch_environment("UNITY_MIR_EMITS_SIGSTOP", "1") |
947 | + self.useFixture( |
948 | + fixtures.EnvironmentVariable('UNITY_MIR_EMITS_SIGSTOP', '1')) |
949 | self._launch_unity() |
950 | self.assertThat( |
951 | lambda: os.WIFSTOPPED(self._get_status()), |
952 | @@ -122,5 +137,5 @@ |
953 | |
954 | logger.debug("Unity started, waiting for it to be ready.") |
955 | self._set_proxy() |
956 | - self.assertUnityReady() |
957 | + self.wait_for_unity() |
958 | logger.debug("Unity loaded and ready.") |
Not ready yet. Just proposing to start getting jenkins results earlier.