on xenial help sign in
Update the autopilot tests to work with the new dash app.
af3058bLeo Arias
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+1−1
@@ -106,7 +106,7 @@ class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
106 self.assert_current_focused_application(application_name)
106 self.assert_current_focused_application(application_name)
107
107
108 self.main_window.show_dash_swiping()
108 self.main_window.show_dash_swiping()
109− self.assert_current_focused_application('')
109+ self.assert_current_focused_application('unity8-dash')
110
110
111 process_helpers.lock_unity()
111 process_helpers.lock_unity()
112 greeter = self.main_window.get_greeter()
112 greeter = self.main_window.get_greeter()
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+3−2
@@ -39,7 +39,8 @@ class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
39 desktop_file_name = os.path.basename(desktop_file_path)
39 desktop_file_name = os.path.basename(desktop_file_path)
40 application_name, _ = os.path.splitext(desktop_file_name)
40 application_name, _ = os.path.splitext(desktop_file_name)
41
41
42+ self.assertEqual(
42− self.assertEqual('', self.main_window.get_current_focused_app_id())
43+ 'unity8-dash', self.main_window.get_current_focused_app_id())
43 self.addCleanup(os.system, 'pkill qmlscene')
44 self.addCleanup(os.system, 'pkill qmlscene')
44
45
45 subprocess.check_call(
46 subprocess.check_call(
@@ -47,4 +48,4 @@ class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
47 self.assert_current_focused_application(application_name)
48 self.assert_current_focused_application(application_name)
48
49
49 self.main_window.show_dash_swiping()
50 self.main_window.show_dash_swiping()
50− self.assert_current_focused_application('')
51+ self.assert_current_focused_application('unity8-dash')
tests/autopilot/unity8/fixture_setup.pynew file+64
@@ -0,0 +1,64 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+import fixtures
21+from autopilot import introspection
22+
23+from unity8 import process_helpers
24+from unity8.shell import emulators
25+
26+
27+class LaunchDashApp(fixtures.Fixture):
28+
29+ """Fixture to launch the Dash app."""
30+
31+ def __init__(self, binary_path, variables):
32+ """Initialize an instance.
33+
34+ :param str binary_path: The path to the Dash app binary.
35+ :param variables: The variables to use when launching the app.
36+ :type variables: A dictionary.
37+
38+ """
39+ super(LaunchDashApp, self).__init__()
40+ self.binary_path = binary_path
41+ self.variables = variables
42+
43+ def setUp(self):
44+ """Launch the dash app when the fixture is used."""
45+ super(LaunchDashApp, self).setUp()
46+ self.addCleanup(self.stop_application)
47+ self.application_proxy = self.launch_application()
48+
49+ def launch_application(self):
50+ binary_arg = 'BINARY={}'.format(self.binary_path)
51+ testability_arg = 'QT_LOAD_TESTABILITY={}'.format(1)
52+ env_args = [
53+ '{}={}'.format(key, value) for key, value in self.variables.items()
54+ ]
55+ all_args = [binary_arg, testability_arg] + env_args
56+
57+ pid = process_helpers.start_job('unity8-dash', *all_args)
58+ return introspection.get_proxy_object_for_existing_process(
59+ pid=pid,
60+ emulator_base=emulators.UnityEmulatorBase,
61+ )
62+
63+ def stop_application(self):
64+ process_helpers.stop_job('unity8-dash')
tests/autopilot/unity8/process_helpers.py+89−20
@@ -36,6 +36,10 @@ from unity8.shell.emulators import main_window as main_window_emulator
36logger = logging.getLogger(__name__)
36logger = logging.getLogger(__name__)
37
37
38
38
39+class JobError(Exception):
40+ pass
41+
42+
39class CannotAccessUnity(Exception):
43class CannotAccessUnity(Exception):
40 pass
44 pass
41
45
@@ -134,48 +138,113 @@ def restart_unity(*args):
134 """
138 """
135 status = _get_unity_status()
139 status = _get_unity_status()
136 if "start/" in status:
140 if "start/" in status:
137− try:
141+ stop_job('unity8')
138− output = subprocess.check_output(
142+
139− ['/sbin/initctl', 'stop', 'unity8'])
143+ pid = start_job('unity8', *args)
140− logger.info(output)
144+ return _get_unity_proxy_object(pid)
141− except subprocess.CalledProcessError as e:
142− e.args += (
143− "Failed to stop running instance of unity8: %s" % e.output,
144− )
145− raise
146
145
146+
147+def start_job(name, *args):
148+ """Start a job.
149+
150+ :param str name: The name of the job.
151+ :param args: The arguments to be used when starting the job.
152+ :return: The process id of the started job.
153+ :raises CalledProcessError: if the job failed to start.
154+
155+ """
156+ logger.info('Starting job {} with arguments {}.'.format(name, args))
157+ command = ['/sbin/initctl', 'start', name] + list(args)
147 try:
158 try:
148− command = ['/sbin/initctl', 'start', 'unity8'] + list(args)
149 output = subprocess.check_output(
159 output = subprocess.check_output(
150 command,
160 command,
151 stderr=subprocess.STDOUT,
161 stderr=subprocess.STDOUT,
152 universal_newlines=True,
162 universal_newlines=True,
153 )
163 )
154 logger.info(output)
164 logger.info(output)
155− pid = _get_unity_pid()
165+ pid = get_job_pid(name)
156 except subprocess.CalledProcessError as e:
166 except subprocess.CalledProcessError as e:
157− e.args += ("Failed to start unity8: %s" % e.output,)
167+ e.args += ('Failed to start {}: {}.'.format(name, e.output),)
158 raise
168 raise
159 else:
169 else:
160− return _get_unity_proxy_object(pid)
170+ return pid
161
171
162
172
163−def _get_unity_status():
173+def get_job_pid(name):
174+ """Return the process id of a running job.
175+
176+ :param str name: The name of the job.
177+ :raises JobError: if the job is not running.
178+
179+ """
180+ status = get_job_status(name)
181+ if "start/" not in status:
182+ raise JobError('{} is not in the running state.'.format(name))
183+ return int(status.split()[-1])
184+
185+
186+def get_job_status(name):
187+ """Return the status of a job.
188+
189+ :param str name: The name of the job.
190+ :raises JobError: if it's not possible to get the status of the job.
191+
192+ """
164 try:
193 try:
165 return subprocess.check_output([
194 return subprocess.check_output([
166 '/sbin/initctl',
195 '/sbin/initctl',
167 'status',
196 'status',
168− 'unity8'
197+ name
169 ], universal_newlines=True)
198 ], universal_newlines=True)
199+ except subprocess.CalledProcessError as error:
200+ raise JobError(
201+ "Unable to get {}'s status: {}".format(name, error)
202+ )
203+
204+
205+def stop_job(name):
206+ """Stop a job.
207+
208+ :param str name: The name of the job.
209+ :raises CalledProcessError: if the job failed to stop.
210+
211+ """
212+ logger.info('Stoping job {}.'.format(name))
213+ command = ['/sbin/initctl', 'stop', name]
214+ try:
215+ output = subprocess.check_output(
216+ command,
217+ stderr=subprocess.STDOUT,
218+ universal_newlines=True,
219+ )
220+ logger.info(output)
170 except subprocess.CalledProcessError as e:
221 except subprocess.CalledProcessError as e:
171− 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/' 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))
172
241
173
242
174def _get_unity_pid():
243def _get_unity_pid():
175− status = _get_unity_status()
244+ try:
176− if "start/" not in status:
245+ return get_job_pid('unity8')
246+ except JobError as error:
177− raise CannotAccessUnity("Unity is not in the running state.")
247+ raise CannotAccessUnity(str(error))
178− return int(status.split()[-1])
179
248
180
249
181def _get_unity_proxy_object(pid):
250def _get_unity_proxy_object(pid):
tests/autopilot/unity8/shell/emulators/dash.py+21−8
@@ -31,6 +31,17 @@ from ubuntuuitoolkit import emulators as toolkit_emulators
31logger = logging.getLogger(__name__)
31logger = logging.getLogger(__name__)
32
32
33
33
34+class DashApp(object):
35+
36+ """Autopilot helper for the Dash app."""
37+
38+ def __init__(self, app_proxy):
39+ self.app_proxy = app_proxy
40+ self.main_view = self.app_proxy.select_single(
41+ toolkit_emulators.MainView)
42+ self.dash = self.main_view.select_single(Dash)
43+
44+
34class Dash(emulators.UnityEmulatorBase):
45class Dash(emulators.UnityEmulatorBase):
35 """An emulator that understands the Dash."""
46 """An emulator that understands the Dash."""
36
47
@@ -109,20 +120,22 @@ class Dash(emulators.UnityEmulatorBase):
109 @autopilot_logging.log_action(logger.info)
120 @autopilot_logging.log_action(logger.info)
110 def _scroll_to_left_scope(self):
121 def _scroll_to_left_scope(self):
111 original_index = self.dash_content_list.currentIndex
122 original_index = self.dash_content_list.currentIndex
112− dashContent = self.select_single(objectName="dashContent")
123+ dash_content = self.select_single(objectName="dashContent")
124+ x, y, width, height = dash_content.globalRect
113− start_x = dashContent.width / 3
125+ start_x = x + width / 3
114− stop_x = dashContent.width / 3 * 2
126+ stop_x = x + width / 3 * 2
115− start_y = stop_y = dashContent.globalRect.y + 1
127+ start_y = stop_y = y + 1
116 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
128 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
117 self.dash_content_list.currentIndex.wait_for(original_index - 1)
129 self.dash_content_list.currentIndex.wait_for(original_index - 1)
118
130
119 @autopilot_logging.log_action(logger.info)
131 @autopilot_logging.log_action(logger.info)
120 def _scroll_to_right_scope(self):
132 def _scroll_to_right_scope(self):
121 original_index = self.dash_content_list.currentIndex
133 original_index = self.dash_content_list.currentIndex
122− dashContent = self.select_single(objectName="dashContent")
134+ dash_content = self.select_single(objectName="dashContent")
135+ x, y, width, height = dash_content.globalRect
123− start_x = dashContent.width / 3 * 2
136+ start_x = x + width / 3 * 2
124− stop_x = dashContent.width / 3
137+ stop_x = x + width / 3
125− start_y = stop_y = dashContent.globalRect.y + 1
138+ start_y = stop_y = y + 1
126 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
139 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
127 self.dash_content_list.currentIndex.wait_for(original_index + 1)
140 self.dash_content_list.currentIndex.wait_for(original_index + 1)
128
141
tests/autopilot/unity8/shell/emulators/greeter.py+4−1
@@ -17,6 +17,8 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
18#
19
19
20+import ubuntuuitoolkit
21+
20from unity8.shell.emulators import UnityEmulatorBase
22from unity8.shell.emulators import UnityEmulatorBase
21
23
22
24
@@ -37,4 +39,5 @@ class Greeter(UnityEmulatorBase):
37 self.created.wait_for(False)
39 self.created.wait_for(False)
38
40
39 def get_prompt(self):
41 def get_prompt(self):
42+ return self.select_single(
40− return self.select_single("TextField", objectName="passwordInput")
43+ ubuntuuitoolkit.TextField, objectName='passwordInput')
tests/autopilot/unity8/shell/emulators/main_window.py+34−20
@@ -25,7 +25,6 @@ from autopilot import input
25from unity8.shell import emulators
25from unity8.shell import emulators
26from unity8.shell.emulators.greeter import Greeter
26from unity8.shell.emulators.greeter import Greeter
27from unity8.shell.emulators.hud import Hud
27from unity8.shell.emulators.hud import Hud
28−from unity8.shell.emulators.dash import Dash
29from unity8.shell.emulators.launcher import Launcher
28from unity8.shell.emulators.launcher import Launcher
30
29
31logger = logging.getLogger(__name__)
30logger = logging.getLogger(__name__)
@@ -61,9 +60,6 @@ class QQuickView(emulators.UnityEmulatorBase):
61 def get_hud_edge_drag_area(self):
60 def get_hud_edge_drag_area(self):
62 return self.select_single(objectName="hudDragArea")
61 return self.select_single(objectName="hudDragArea")
63
62
64− def get_dash(self):
65− return self.select_single(Dash)
66−
67 def get_bottombar(self):
63 def get_bottombar(self):
68 return self.select_single("Bottombar")
64 return self.select_single("Bottombar")
69
65
@@ -76,12 +72,6 @@ class QQuickView(emulators.UnityEmulatorBase):
76 objectName="pinPadLoader"
72 objectName="pinPadLoader"
77 )
73 )
78
74
79− def get_pinPadButton(self, buttonId):
80− return self.select_single(
81− "PinPadButton",
82− objectName="pinPadButton%i" % buttonId
83− )
84−
85 def get_lockscreen(self):
75 def get_lockscreen(self):
86 return self.select_single("Lockscreen")
76 return self.select_single("Lockscreen")
87
77
@@ -117,20 +107,44 @@ class QQuickView(emulators.UnityEmulatorBase):
117 @autopilot_logging.log_action(logger.info)
107 @autopilot_logging.log_action(logger.info)
118 def show_dash_swiping(self):
108 def show_dash_swiping(self):
119 """Show the dash swiping from the left."""
109 """Show the dash swiping from the left."""
120− width = self.width
110+ x, y, width, height = self._get_shell().globalRect
121− height = self.height
122− start_x = 0
111+ start_x = x
123− start_y = height // 2
124− end_x = width
112+ end_x = x + width
125− end_y = start_y
113+ start_y = end_y = y + height // 2
126
114
127 self.pointing_device.drag(start_x, start_y, end_x, end_y)
115 self.pointing_device.drag(start_x, start_y, end_x, end_y)
116+
117+ def _get_shell(self):
128− return self.get_dash()
118+ return self.select_single('Shell')
129
119
130 def get_current_focused_app_id(self):
120 def get_current_focused_app_id(self):
131 """Return the id of the focused application."""
121 """Return the id of the focused application."""
132− return self.select_single('Shell').focusedApplicationId
122+ return self._get_shell().focusedApplicationId
133
123
134 @autopilot_logging.log_action(logger.info)
124 @autopilot_logging.log_action(logger.info)
135− def search(self, query):
125+ def enter_pin_code(self, code):
136− self.get_dash().enter_search_query(query)
126+ """Enter code 'code' into the single-pin lightdm pincode entry screen.
127+
128+ :param code: must be a string of numeric characters.
129+ :raises: TypeError if code is not a string.
130+ :raises: ValueError if code contains non-numeric characters.
131+
132+ """
133+ if not isinstance(code, str):
134+ raise TypeError(
135+ "'code' parameter must be a string, not %r."
136+ % type(code)
137+ )
138+ for num in code:
139+ if not num.isdigit():
140+ raise ValueError(
141+ "'code' parameter contains non-numeric characters."
142+ )
143+ self.pointing_device.click_object(
144+ self._get_pinpad_button(int(num)))
145+
146+ def _get_pinpad_button(self, button_id):
147+ return self.select_single(
148+ 'PinPadButton',
149+ objectName='pinPadButton{}'.format(button_id)
150+ )
tests/autopilot/unity8/shell/tests/__init__.py+141−48
@@ -24,6 +24,7 @@ try:
24except ImportError:
24except ImportError:
25 Gio = None
25 Gio = None
26
26
27+from autopilot import introspection
27from autopilot.platform import model
28from autopilot.platform import model
28from autopilot.testcase import AutopilotTestCase
29from autopilot.testcase import AutopilotTestCase
29from autopilot.matchers import Eventually
30from autopilot.matchers import Eventually
@@ -34,6 +35,10 @@ import os.path
34import subprocess
35import subprocess
35import sys
36import sys
36from testtools.matchers import Equals
37from testtools.matchers import Equals
38+from ubuntuuitoolkit import (
39+ fixture_setup as toolkit_fixtures,
40+ ubuntu_scenarios
41+)
37
42
38from unity8 import (
43from unity8 import (
39 get_lib_path,
44 get_lib_path,
@@ -42,9 +47,15 @@ from unity8 import (
42 get_default_extra_mock_libraries,
47 get_default_extra_mock_libraries,
43 get_data_dirs
48 get_data_dirs
44)
49)
45−from unity8.process_helpers import restart_unity_with_testability
50+from unity8 import (
51+ fixture_setup,
52+ process_helpers
53+)
54+from unity8.shell import emulators
55+from unity8.shell.emulators import (
56+ dash as dash_helpers,
46−from unity8.shell.emulators import main_window as main_window_emulator
57+ main_window as main_window_emulator,
47−from unity8.shell.emulators.dash import Dash
58+)
48
59
49
60
50logger = logging.getLogger(__name__)
61logger = logging.getLogger(__name__)
@@ -78,6 +89,26 @@ def _get_device_emulation_scenarios(devices='All'):
78 return [native]
89 return [native]
79
90
80
91
92+def is_unity7_running():
93+ """Return True if Unity7 is running. Otherwise, return False."""
94+ return (
95+ Gio is not None and
96+ UNITYSHELL_GSETTINGS_SCHEMA in
97+ Gio.Settings.list_relocatable_schemas()
98+ )
99+
100+
101+def get_qml_import_path_with_mock():
102+ """Return the QML2_IMPORT_PATH value with the mock path prepended."""
103+ qml_import_path = [get_mocks_library_path()]
104+ if os.getenv('QML2_IMPORT_PATH') is not None:
105+ qml_import_path.append(os.getenv('QML2_IMPORT_PATH'))
106+
107+ qml_import_path = ':'.join(qml_import_path)
108+ logger.info("New QML2 import path: %s", qml_import_path)
109+ return qml_import_path
110+
111+
81class UnityTestCase(AutopilotTestCase):
112class UnityTestCase(AutopilotTestCase):
82
113
83 """A test case base class for the Unity shell tests."""
114 """A test case base class for the Unity shell tests."""
@@ -118,23 +149,8 @@ class UnityTestCase(AutopilotTestCase):
118
149
119 def setUp(self):
150 def setUp(self):
120 super(UnityTestCase, self).setUp()
151 super(UnityTestCase, self).setUp()
121− if (Gio is not None and
152+ if is_unity7_running():
122− UNITYSHELL_GSETTINGS_SCHEMA in
153+ self.useFixture(toolkit_fixtures.HideUnity7Launcher())
123− Gio.Settings.list_relocatable_schemas()):
124−
125− # Hide Unity launcher
126− self._unityshell_schema = Gio.Settings.new_with_path(
127− UNITYSHELL_GSETTINGS_SCHEMA,
128− UNITYSHELL_GSETTINGS_PATH,
129− )
130− self._launcher_hide_mode = self._unityshell_schema.get_int(
131− UNITYSHELL_LAUNCHER_KEY,
132− )
133− self._unityshell_schema.set_int(
134− UNITYSHELL_LAUNCHER_KEY,
135− UNITYSHELL_LAUNCHER_MODE,
136− )
137− self.addCleanup(self._reset_launcher)
138
154
139 self._proxy = None
155 self._proxy = None
140 self._lightdm_mock_type = None
156 self._lightdm_mock_type = None
@@ -151,13 +167,6 @@ class UnityTestCase(AutopilotTestCase):
151 self.touch = Touch.create()
167 self.touch = Touch.create()
152 self._setup_display_details()
168 self._setup_display_details()
153
169
154− def _reset_launcher(self):
155− """Reset Unity launcher hide mode"""
156− self._unityshell_schema.set_int(
157− UNITYSHELL_LAUNCHER_KEY,
158− self._launcher_hide_mode,
159− )
160−
161 def _setup_display_details(self):
170 def _setup_display_details(self):
162 scale_divisor = self._determine_geometry()
171 scale_divisor = self._determine_geometry()
163 self._setup_grid_size(scale_divisor)
172 self._setup_grid_size(scale_divisor)
@@ -263,7 +272,9 @@ class UnityTestCase(AutopilotTestCase):
263 self.patch_lightdm_mock()
272 self.patch_lightdm_mock()
264
273
265 if self._qml_mock_enabled:
274 if self._qml_mock_enabled:
266− self._setup_extra_mock_environment_patch()
275+ self._environment['QML2_IMPORT_PATH'] = (
276+ get_qml_import_path_with_mock()
277+ )
267
278
268 if self._data_dirs_mock_enabled:
279 if self._data_dirs_mock_enabled:
269 self._patch_data_dirs()
280 self._patch_data_dirs()
@@ -292,9 +303,14 @@ class UnityTestCase(AutopilotTestCase):
292
303
293 # Ensure that the dash is visible before we return:
304 # Ensure that the dash is visible before we return:
294 logger.debug("Unity started, waiting for it to be ready.")
305 logger.debug("Unity started, waiting for it to be ready.")
295− self.assertUnityReady()
306+ self.wait_for_unity()
296 logger.debug("Unity loaded and ready.")
307 logger.debug("Unity loaded and ready.")
297
308
309+ if model() == 'Desktop':
310+ # On desktop, close the dash because it's opened in a separate
311+ # window and it gets in the way.
312+ process_helpers.stop_job('unity8-dash')
313+
298 return app_proxy
314 return app_proxy
299
315
300 def _launch_unity_with_upstart(self, binary_path, args):
316 def _launch_unity_with_upstart(self, binary_path, args):
@@ -308,7 +324,7 @@ class UnityTestCase(AutopilotTestCase):
308
324
309 self.addCleanup(self._cleanup_launching_upstart_unity)
325 self.addCleanup(self._cleanup_launching_upstart_unity)
310
326
311− return restart_unity_with_testability(*all_args)
327+ return process_helpers.restart_unity_with_testability(*all_args)
312
328
313 def _cleanup_launching_upstart_unity(self):
329 def _cleanup_launching_upstart_unity(self):
314 logger.info("Stopping unity")
330 logger.info("Stopping unity")
@@ -353,15 +369,6 @@ class UnityTestCase(AutopilotTestCase):
353 )
369 )
354 return lightdm_mock_path
370 return lightdm_mock_path
355
371
356− def _setup_extra_mock_environment_patch(self):
357− qml_import_path = [get_mocks_library_path()]
358− if os.getenv('QML2_IMPORT_PATH') is not None:
359− qml_import_path.append(os.getenv('QML2_IMPORT_PATH'))
360−
361− qml_import_path = ':'.join(qml_import_path)
362− logger.info("New QML2 import path: %s", qml_import_path)
363− self._environment['QML2_IMPORT_PATH'] = qml_import_path
364−
365 def _set_proxy(self, proxy):
372 def _set_proxy(self, proxy):
366 """Keep a copy of the proxy object, so we can use it to get common
373 """Keep a copy of the proxy object, so we can use it to get common
367 parts of the shell later on.
374 parts of the shell later on.
@@ -373,10 +380,80 @@ class UnityTestCase(AutopilotTestCase):
373 def _clear_proxy(self):
380 def _clear_proxy(self):
374 self._proxy = None
381 self._proxy = None
375
382
376− def assertUnityReady(self):
383+ def wait_for_unity(self):
384+ greeter_content_loader = self.main_window.wait_select_single(
385+ objectName='greeterContentLoader')
386+ greeter_content_loader.progress.wait_for(1)
387+
377− dash = self.get_dash()
388+ def get_dash(self):
378− home_scope = dash.get_scope('clickscope')
389+ pid = process_helpers.get_job_pid('unity8-dash')
390+ dash_proxy = introspection.get_proxy_object_for_existing_process(
391+ pid=pid,
392+ emulator_base=emulators.UnityEmulatorBase,
393+ )
394+ dash_app = dash_helpers.DashApp(dash_proxy)
395+ return dash_app.dash
396+
397+ @property
398+ def main_window(self):
399+ return self._proxy.select_single(main_window_emulator.QQuickView)
379
400
401+
402+class DashBaseTestCase(AutopilotTestCase):
403+
404+ scenarios = ubuntu_scenarios.get_device_simulation_scenarios()
405+ qml_mock_enabled = True
406+ environment = {}
407+
408+ def setUp(self):
409+ super(DashBaseTestCase, self).setUp()
410+
411+ if is_unity7_running():
412+ self.useFixture(toolkit_fixtures.HideUnity7Launcher())
413+
414+ if model() != 'Desktop':
415+ # On the phone, we need unity to be running and unlocked.
416+ self.addCleanup(process_helpers.stop_job, 'unity8')
417+ process_helpers.restart_unity_with_testability()
418+ process_helpers.unlock_unity()
419+
420+ self.ensure_dash_not_running()
421+
422+ if self.qml_mock_enabled:
423+ self.environment['QML2_IMPORT_PATH'] = (
424+ get_qml_import_path_with_mock()
425+ )
426+
427+ if self.should_simulate_device():
428+ # This sets the grid units, so it should be called before launching
429+ # the app.
430+ self.simulate_device()
431+
432+ binary_path = get_binary_path('unity8-dash')
433+ dash_proxy = self.launch_dash(binary_path, self.environment)
434+
435+ if self.should_simulate_device():
436+ # XXX Currently we have no way to launch the application with a
437+ # specific size, so we must resize it after it's launched.
438+ # --elopio - 2014-06-25
439+ self.resize_window()
440+
441+ self.dash_app = dash_helpers.DashApp(dash_proxy)
442+ self.dash = self.dash_app.dash
443+ self.wait_for_dash()
444+
445+ def ensure_dash_not_running(self):
446+ if process_helpers.is_job_running('unity8-dash'):
447+ process_helpers.stop_job('unity8-dash')
448+
449+ def launch_dash(self, binary_path, variables):
450+ launch_dash_app_fixture = fixture_setup.LaunchDashApp(
451+ binary_path, variables)
452+ self.useFixture(launch_dash_app_fixture)
453+ return launch_dash_app_fixture.application_proxy
454+
455+ def wait_for_dash(self):
456+ home_scope = self.dash.get_scope('clickscope')
380 # FIXME! There is a huge timeout here for when we're doing CI on
457 # FIXME! There is a huge timeout here for when we're doing CI on
381 # VMs. See lp:1203715
458 # VMs. See lp:1203715
382 self.assertThat(
459 self.assertThat(
@@ -385,10 +462,26 @@ class UnityTestCase(AutopilotTestCase):
385 )
462 )
386 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
463 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
387
464
388− def get_dash(self):
465+ def should_simulate_device(self):
389− dash = self._proxy.wait_select_single(Dash)
466+ return (hasattr(self, 'app_width') and hasattr(self, 'app_height') and
390− return dash
467+ hasattr(self, 'grid_unit_px'))
391
468
392− @property
469+ def simulate_device(self):
393− def main_window(self):
470+ simulate_device_fixture = self.useFixture(
394− return self._proxy.select_single(main_window_emulator.QQuickView)
471+ toolkit_fixtures.SimulateDevice(
472+ self.app_width, self.app_height, self.grid_unit_px))
473+ self.app_width = simulate_device_fixture.app_width
474+ self.app_height = simulate_device_fixture.app_height
475+
476+ def resize_window(self):
477+ application = self.process_manager.get_running_applications()[0]
478+ window = application.get_windows()[0]
479+ window.resize(self.app_width, self.app_height)
480+
481+ def get_window_size():
482+ _, _, window_width, window_height = window.geometry
483+ return window_width, window_height
484+
485+ self.assertThat(
486+ get_window_size,
487+ Eventually(Equals((self.app_width, self.app_height))))
tests/autopilot/unity8/shell/tests/test_emulators.py+7−18
@@ -47,24 +47,13 @@ class MainWindowTestCase(tests.UnityTestCase):
47 unity_proxy = self.launch_unity()
47 unity_proxy = self.launch_unity()
48 process_helpers.unlock_unity(unity_proxy)
48 process_helpers.unlock_unity(unity_proxy)
49
49
50− def test_search(self):
51− self.main_window.search('Test')
52− text_field = self.main_window.get_dash()._get_search_text_field()
53− self.assertEqual(text_field.text, 'Test')
54−
55−
56−class DashBaseTestCase(tests.UnityTestCase):
57−
58− scenarios = tests._get_device_emulation_scenarios()
59
50
60− def setUp(self):
61− super(DashBaseTestCase, self).setUp()
51+class DashEmulatorTestCase(tests.DashBaseTestCase):
62− unity_proxy = self.launch_unity()
63− process_helpers.unlock_unity(unity_proxy)
64− self.dash = self.main_window.get_dash()
65
52
66−
53+ def test_search(self):
67−class DashEmulatorTestCase(DashBaseTestCase):
54+ self.dash.enter_search_query('Test')
55+ text_field = self.dash._get_search_text_field()
56+ self.assertEqual(text_field.text, 'Test')
68
57
69 def test_open_unexisting_scope(self):
58 def test_open_unexisting_scope(self):
70 scope_name = 'unexisting'
59 scope_name = 'unexisting'
@@ -145,7 +134,7 @@ class DashEmulatorTestCase(DashBaseTestCase):
145 self.assertIsInstance(scope, dash_emulators.GenericScopeView)
134 self.assertIsInstance(scope, dash_emulators.GenericScopeView)
146
135
147
136
148−class GenericScopeViewEmulatorTestCase(DashBaseTestCase):
137+class GenericScopeViewEmulatorTestCase(tests.DashBaseTestCase):
149
138
150 def setUp(self):
139 def setUp(self):
151 # Set up the fake scopes before launching unity.
140 # Set up the fake scopes before launching unity.
@@ -159,7 +148,7 @@ class GenericScopeViewEmulatorTestCase(DashBaseTestCase):
159 self.assertTrue(preview.isCurrent)
148 self.assertTrue(preview.isCurrent)
160
149
161
150
162−class DashAppsEmulatorTestCase(DashBaseTestCase):
151+class DashAppsEmulatorTestCase(tests.DashBaseTestCase):
163
152
164 available_applications = [
153 available_applications = [
165 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
154 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
tests/autopilot/unity8/shell/tests/test_lock_screen.py+7−47
@@ -51,7 +51,7 @@ class TestLockscreen(UnityTestCase):
51 if greeter.narrowMode:
51 if greeter.narrowMode:
52 unlock_unity(unity_proxy)
52 unlock_unity(unity_proxy)
53 lockscreen = self._wait_for_lockscreen()
53 lockscreen = self._wait_for_lockscreen()
54− self._enter_pincode("1234")
54+ self.main_window.enter_pin_code("1234")
55 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
55 self.assertThat(lockscreen.shown, Eventually(Equals(False)))
56 else:
56 else:
57 self._enter_prompt_passphrase("1234")
57 self._enter_prompt_passphrase("1234")
@@ -81,7 +81,7 @@ class TestLockscreen(UnityTestCase):
81 if greeter.narrowMode:
81 if greeter.narrowMode:
82 unlock_unity(unity_proxy)
82 unlock_unity(unity_proxy)
83 lockscreen = self._wait_for_lockscreen()
83 lockscreen = self._wait_for_lockscreen()
84− self._enter_pincode("4321")
84+ self.main_window.enter_pin_code("4321")
85 pinentryField = self.main_window.get_pinentryField()
85 pinentryField = self.main_window.get_pinentryField()
86 self.assertThat(pinentryField.text, Eventually(Equals("")))
86 self.assertThat(pinentryField.text, Eventually(Equals("")))
87 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
87 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
@@ -118,28 +118,6 @@ class TestLockscreen(UnityTestCase):
118 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
118 self.assertThat(lockscreen.shown, Eventually(Equals(True)))
119 return lockscreen
119 return lockscreen
120
120
121− def _enter_pincode(self, code):
122− """Enter code 'code' into the single-pin lightdm pincode entry
123− screen.
124−
125− :param code: must be a string of numeric characters.
126− :raises: TypeError if code is not a string.
127− :raises: ValueError if code contains non-numeric characters.
128−
129− """
130−
131− if not isinstance(code, basestring):
132− raise TypeError(
133− "'code' parameter must be a string, not %r."
134− % type(code)
135− )
136− for num in code:
137− if not num.isdigit():
138− raise ValueError(
139− "'code' parameter contains non-numeric characters."
140− )
141− self.touch.tap_object(self.main_window.get_pinPadButton(int(num)))
142−
143 def _enter_pin_passphrase(self, passphrase):
121 def _enter_pin_passphrase(self, passphrase):
144 """Enter the password specified in 'passphrase' into the password entry
122 """Enter the password specified in 'passphrase' into the password entry
145 field of the pin lock screen.
123 field of the pin lock screen.
@@ -148,18 +126,15 @@ class TestLockscreen(UnityTestCase):
148 :raises: TypeError if passphrase is not a string.
126 :raises: TypeError if passphrase is not a string.
149
127
150 """
128 """
151− if not isinstance(passphrase, basestring):
129+ if not isinstance(passphrase, str):
152 raise TypeError(
130 raise TypeError(
153 "'passphrase' parameter must be a string, not %r."
131 "'passphrase' parameter must be a string, not %r."
154 % type(passphrase)
132 % type(passphrase)
155 )
133 )
156
134
157− pinentryField = self.main_window.get_pinentryField()
135+ pin_entry_field = self.main_window.get_pinentryField()
158− self.touch.tap_object(pinentryField)
136+ pin_entry_field.write(passphrase)
159− self.assertThat(pinentryField.activeFocus, Eventually(Equals(True)))
160− for character in passphrase:
161− self._type_character(character, pinentryField)
162− logger.debug("Typed passphrase: %s", pinentryField.text)
137+ logger.debug("Typed passphrase: %s", pin_entry_field.text)
163 self.keyboard.type("\n")
138 self.keyboard.type("\n")
164
139
165 def _enter_prompt_passphrase(self, passphrase):
140 def _enter_prompt_passphrase(self, passphrase):
@@ -177,21 +152,6 @@ class TestLockscreen(UnityTestCase):
177 )
152 )
178
153
179 prompt = self.main_window.get_greeter().get_prompt()
154 prompt = self.main_window.get_greeter().get_prompt()
180− self.touch.tap_object(prompt)
181− self.assertThat(prompt.activeFocus, Eventually(Equals(True)))
182− for character in passphrase:
155+ prompt.write(passphrase)
183− self._type_character(character, prompt)
184 logger.debug("Typed passphrase: %s", prompt.text)
156 logger.debug("Typed passphrase: %s", prompt.text)
185 self.keyboard.type("\n")
157 self.keyboard.type("\n")
186−
187− def _type_character(self, character, prompt, retries=5):
188− current_text = prompt.text
189− self.keyboard.type(character)
190− try:
191− self.assertThat(
192− prompt.text, Eventually(Equals(current_text + character)))
193− except AssertionError:
194− if retries > 0:
195− self._type_character(character, prompt, retries-1)
196− else:
197− raise
tests/autopilot/unity8/shell/tests/test_notifications.py+12−7
@@ -154,7 +154,7 @@ class InteractiveNotificationBase(NotificationsBase):
154 'Notification', objectName='notification1')
154 'Notification', objectName='notification1')
155 notification = get_notification()
155 notification = get_notification()
156
156
157− self.touch.tap_object(
157+ notification.pointing_device.click_object(
158 notification.select_single(objectName="interactiveArea")
158 notification.select_single(objectName="interactiveArea")
159 )
159 )
160
160
@@ -201,11 +201,14 @@ class InteractiveNotificationBase(NotificationsBase):
201 'Notification', objectName='notification1')
201 'Notification', objectName='notification1')
202 notification = get_notification()
202 notification = get_notification()
203 self._assert_notification(notification, summary, body, True, True, 1.0)
203 self._assert_notification(notification, summary, body, True, True, 1.0)
204− initial_height = notification.height
204+ notification.pointing_device.click_object(
205− self.touch.tap_object(notification.select_single(objectName="combobutton_dropdown"))
205+ notification.select_single(objectName="combobutton_dropdown"))
206+ self.assertThat(
206− self.assertThat(notification.select_single(objectName="button2").expanded, Eventually(Equals(True)))
207+ notification.select_single(objectName="button2").expanded,
208+ Eventually(Equals(True)))
207 time.sleep(2)
209 time.sleep(2)
210+ notification.pointing_device.click_object(
208− self.touch.tap_object(notification.select_single(objectName="button4"))
211+ notification.select_single(objectName="button4"))
209 self.assert_notification_action_id_was_called("action_decline_4")
212 self.assert_notification_action_id_was_called("action_decline_4")
210
213
211 def test_modal_sd_without_greeter(self):
214 def test_modal_sd_without_greeter(self):
@@ -249,7 +252,8 @@ class InteractiveNotificationBase(NotificationsBase):
249 notification = get_notification()
252 notification = get_notification()
250 self._assert_notification(
253 self._assert_notification(
251 notification, summary, body, True, False, 1.0)
254 notification, summary, body, True, False, 1.0)
255+ notification.pointing_device.click_object(
252− self.touch.tap_object(notification.select_single(objectName="button0"))
256+ notification.select_single(objectName="button0"))
253 self.assert_notification_action_id_was_called("action_accept")
257 self.assert_notification_action_id_was_called("action_accept")
254
258
255 def test_modal_sd_with_greeter(self):
259 def test_modal_sd_with_greeter(self):
@@ -291,7 +295,8 @@ class InteractiveNotificationBase(NotificationsBase):
291 notification = get_notification()
295 notification = get_notification()
292 self._assert_notification(
296 self._assert_notification(
293 notification, summary, body, True, False, 1.0)
297 notification, summary, body, True, False, 1.0)
298+ notification.pointing_device.click_object(
294− self.touch.tap_object(notification.select_single(objectName="button0"))
299+ notification.select_single(objectName="button0"))
295 self.assert_notification_action_id_was_called("action_accept")
300 self.assert_notification_action_id_was_called("action_accept")
296
301
297 def _create_interactive_notification(
302 def _create_interactive_notification(
tests/autopilot/unity8/shell/tests/test_upstart.py+2−2
@@ -119,7 +119,7 @@ class UpstartIntegrationTests(UnityTestCase):
119 self._set_proxy()
119 self._set_proxy()
120
120
121 logger.debug("Unity started, waiting for it to be ready.")
121 logger.debug("Unity started, waiting for it to be ready.")
122− self.assertUnityReady()
122+ self.wait_for_unity()
123 logger.debug("Unity loaded and ready.")
123 logger.debug("Unity loaded and ready.")
124
124
125 def test_expect_sigstop(self):
125 def test_expect_sigstop(self):
@@ -137,5 +137,5 @@ class UpstartIntegrationTests(UnityTestCase):
137
137
138 logger.debug("Unity started, waiting for it to be ready.")
138 logger.debug("Unity started, waiting for it to be ready.")
139 self._set_proxy()
139 self._set_proxy()
140− self.assertUnityReady()
140+ self.wait_for_unity()
141 logger.debug("Unity loaded and ready.")
141 logger.debug("Unity loaded and ready.")