on xenial help sign in
Updated the dash tests to work with the dash app.
commit8eb7df6abccdd7107695b391b6465e2b8c74029e authorLeo Arias <leo.arias@canonical.com> dateTue 29 Jul 2014, 13:49 (12 years ago) parent75eea9a
5 files changed+273−74
tests/autopilot/unity8/fixture_setup.py+68 tests/autopilot/unity8/process_helpers.py+79−20 tests/autopilot/unity8/shell/emulators/dash.py+21−8 tests/autopilot/unity8/shell/tests/__init__.py+102−32 tests/autopilot/unity8/shell/tests/test_emulators.py+3−14
tests/autopilot/unity8/fixture_setup.pynew file+68
@@ -0,0 +1,68 @@
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+from ubuntuuitoolkit import fixture_setup as toolkit_fixtures
23+
24+from unity8 import process_helpers
25+from unity8.shell import emulators
26+
27+
28+class LaunchDashApp(fixtures.Fixture):
29+
30+ """Fixture to launch the Dashh app."""
31+
32+ def __init__(self, binary_path, variables):
33+ """Initialize an instance.
34+
35+ :param str binary_path: The path to the Dash app binary.
36+ :param variables: The variables to use when launching the app.
37+ :type variables: A dictionary.
38+
39+ """
40+ super(LaunchDashApp, self).__init__()
41+ self.binary_path = binary_path
42+ self.variables = variables
43+
44+ def setUp(self):
45+ """Launch the dash app when the fixture is used."""
46+ super(LaunchDashApp, self).setUp()
47+ self.addCleanup(self.stop_application)
48+ self.application_proxy = self.launch_application()
49+
50+ def launch_application(self):
51+ self.useFixture(
52+ toolkit_fixtures.InitctlEnvironmentVariable(
53+ QT_LOAD_TESTABILITY='1'))
54+
55+ binary_arg = 'BINARY={}'.format(self.binary_path)
56+ env_args = [
57+ '{}={}'.format(key, value) for key, value in self.variables.items()
58+ ]
59+ all_args = [binary_arg] + env_args
60+
61+ pid = process_helpers.start_job('unity8-dash', *all_args)
62+ return introspection.get_proxy_object_for_existing_process(
63+ pid=pid,
64+ emulator_base=emulators.UnityEmulatorBase,
65+ )
66+
67+ def stop_application(self):
68+ process_helpers.stop_job('unity8-dash')
tests/autopilot/unity8/process_helpers.py+79−20
@@ -36,6 +36,10 @@ from unity8.shell.emulators import main_window as main_window_emulator
3636logger = logging.getLogger(__name__)
3737
3838
39+class JobError(Exception):
40+ pass
41+
42+
3943class CannotAccessUnity(Exception):
4044 pass
4145
@@ -134,48 +138,103 @@ def restart_unity(*args):
134138 """
135139 status = _get_unity_status()
136140 if "start/" in status:
137− try:
138− output = subprocess.check_output(
139− ['/sbin/initctl', 'stop', 'unity8'])
140− logger.info(output)
141− except subprocess.CalledProcessError as e:
142− e.args += (
143− "Failed to stop running instance of unity8: %s" % e.output,
144− )
145− raise
141+ stop_job('unity8')
142+
143+ pid = start_job('unity8', *args)
144+ return _get_unity_proxy_object(pid)
146145
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)
147158 try:
148− command = ['/sbin/initctl', 'start', 'unity8'] + list(args)
149159 output = subprocess.check_output(
150160 command,
151161 stderr=subprocess.STDOUT,
152162 universal_newlines=True,
153163 )
154164 logger.info(output)
155− pid = _get_unity_pid()
165+ pid = _get_job_pid(name)
156166 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))
158168 raise
159169 else:
160− return _get_unity_proxy_object(pid)
170+ return pid
161171
162172
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+ """
164193 try:
165194 return subprocess.check_output([
166195 '/sbin/initctl',
167196 'status',
168− 'unity8'
197+ name
169198 ], 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)
170221 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 _get_unity_status():
227+ try:
228+ return get_job_status('unity8')
229+ except JobError as error:
230+ raise CannotAccessUnity(str(error))
172231
173232
174233def _get_unity_pid():
175− status = _get_unity_status()
176− if "start/" not in status:
177− raise CannotAccessUnity("Unity is not in the running state.")
178− return int(status.split()[-1])
234+ try:
235+ return _get_job_pid('unity8')
236+ except JobError as error:
237+ raise CannotAccessUnity(str(error))
179238
180239
181240def _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
3131logger = logging.getLogger(__name__)
3232
3333
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+
3445class Dash(emulators.UnityEmulatorBase):
3546 """An emulator that understands the Dash."""
3647
@@ -109,20 +120,22 @@ class Dash(emulators.UnityEmulatorBase):
109120 @autopilot_logging.log_action(logger.info)
110121 def _scroll_to_left_scope(self):
111122 original_index = self.dash_content_list.currentIndex
112− dashContent = self.select_single(objectName="dashContent")
113− start_x = dashContent.width / 3
114− stop_x = dashContent.width / 3 * 2
115− start_y = stop_y = dashContent.globalRect.y + 1
123+ dash_content = self.select_single(objectName="dashContent")
124+ x, y, width, height = dash_content.globalRect
125+ start_x = x + width / 3
126+ stop_x = x + width / 3 * 2
127+ start_y = stop_y = y + 1
116128 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
117129 self.dash_content_list.currentIndex.wait_for(original_index - 1)
118130
119131 @autopilot_logging.log_action(logger.info)
120132 def _scroll_to_right_scope(self):
121133 original_index = self.dash_content_list.currentIndex
122− dashContent = self.select_single(objectName="dashContent")
123− start_x = dashContent.width / 3 * 2
124− stop_x = dashContent.width / 3
125− start_y = stop_y = dashContent.globalRect.y + 1
134+ dash_content = self.select_single(objectName="dashContent")
135+ x, y, width, height = dash_content.globalRect
136+ start_x = x + width / 3 * 2
137+ stop_x = x + width / 3
138+ start_y = stop_y = y + 1
126139 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
127140 self.dash_content_list.currentIndex.wait_for(original_index + 1)
128141
tests/autopilot/unity8/shell/tests/__init__.py+102−32
@@ -34,6 +34,7 @@ import os.path
3434import subprocess
3535import sys
3636from testtools.matchers import Equals
37+from ubuntuuitoolkit import fixture_setup as toolkit_fixtures
3738
3839from unity8 import (
3940 get_lib_path,
@@ -42,9 +43,14 @@ from unity8 import (
4243 get_default_extra_mock_libraries,
4344 get_data_dirs
4445)
45−from unity8.process_helpers import restart_unity_with_testability
46−from unity8.shell.emulators import main_window as main_window_emulator
47−from unity8.shell.emulators.dash import Dash
46+from unity8 import (
47+ fixture_setup,
48+ process_helpers
49+)
50+from unity8.shell.emulators import (
51+ dash as dash_helpers,
52+ main_window as main_window_emulator,
53+)
4854
4955
5056logger = logging.getLogger(__name__)
@@ -78,6 +84,26 @@ def _get_device_emulation_scenarios(devices='All'):
7884 return [native]
7985
8086
87+def is_unity7_running():
88+ """Return True if Unity7 is running. Otherwise, return False."""
89+ return (
90+ Gio is not None and
91+ UNITYSHELL_GSETTINGS_SCHEMA in
92+ Gio.Settings.list_relocatable_schemas()
93+ )
94+
95+
96+def get_qml_import_path_with_mock():
97+ """Return the QML2_IMPORT_PATH value with the mock path preppended."""
98+ qml_import_path = [get_mocks_library_path()]
99+ if os.getenv('QML2_IMPORT_PATH') is not None:
100+ qml_import_path.append(os.getenv('QML2_IMPORT_PATH'))
101+
102+ qml_import_path = ':'.join(qml_import_path)
103+ logger.info("New QML2 import path: %s", qml_import_path)
104+ return qml_import_path
105+
106+
81107class UnityTestCase(AutopilotTestCase):
82108
83109 """A test case base class for the Unity shell tests."""
@@ -118,23 +144,8 @@ class UnityTestCase(AutopilotTestCase):
118144
119145 def setUp(self):
120146 super(UnityTestCase, self).setUp()
121− if (Gio is not None and
122− UNITYSHELL_GSETTINGS_SCHEMA in
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)
147+ if is_unity7_running():
148+ self.useFixture(toolkit_fixtures.HideUnity7Launcher())
138149
139150 self._proxy = None
140151 self._lightdm_mock_type = None
@@ -263,7 +274,9 @@ class UnityTestCase(AutopilotTestCase):
263274 self.patch_lightdm_mock()
264275
265276 if self._qml_mock_enabled:
266− self._setup_extra_mock_environment_patch()
277+ self._environment['QML2_IMPORT_PATH'] = (
278+ get_qml_import_path_with_mock()
279+ )
267280
268281 if self._data_dirs_mock_enabled:
269282 self._patch_data_dirs()
@@ -308,7 +321,7 @@ class UnityTestCase(AutopilotTestCase):
308321
309322 self.addCleanup(self._cleanup_launching_upstart_unity)
310323
311− return restart_unity_with_testability(*all_args)
324+ return process_helpers.restart_unity_with_testability(*all_args)
312325
313326 def _cleanup_launching_upstart_unity(self):
314327 logger.info("Stopping unity")
@@ -353,15 +366,6 @@ class UnityTestCase(AutopilotTestCase):
353366 )
354367 return lightdm_mock_path
355368
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−
365369 def _set_proxy(self, proxy):
366370 """Keep a copy of the proxy object, so we can use it to get common
367371 parts of the shell later on.
@@ -385,10 +389,76 @@ class UnityTestCase(AutopilotTestCase):
385389 )
386390 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
387391
392+
388393 def get_dash(self):
389− dash = self._proxy.wait_select_single(Dash)
394+ dash = self._proxy.wait_select_single(dash_helpers.Dash)
390395 return dash
391396
392397 @property
393398 def main_window(self):
394399 return self._proxy.select_single(main_window_emulator.QQuickView)
400+
401+
402+class DashBaseTestCase(AutopilotTestCase):
403+
404+ scenarios = _get_device_emulation_scenarios()
405+ qml_mock_enabled = True
406+ environment = {}
407+
408+ def setUp(self):
409+ if model() != 'Desktop':
410+ process_helpers.restart_unity()
411+
412+ super(DashBaseTestCase, self).setUp()
413+
414+ if self.qml_mock_enabled:
415+ self.environment['QML2_IMPORT_PATH'] = (
416+ get_qml_import_path_with_mock()
417+ )
418+
419+ if self.should_simulate_device():
420+ # This sets the grid units, so it should be called before launching
421+ # the app.
422+ self.simulate_device()
423+
424+ binary_path = get_binary_path('unity8-dash')
425+ dash_proxy = self.launch_dash(binary_path, self.environment)
426+
427+ if self.should_simulate_device():
428+ # XXX Currently we have no way to launch the application with a
429+ # specific size, so we must resize it after it's launched.
430+ # --elopio - 2014-06-25
431+ self.resize_window()
432+
433+ self.dash_app = dash_helpers.DashApp(dash_proxy)
434+ self.dash = self.dash_app.dash
435+
436+ def should_simulate_device(self):
437+ return (hasattr(self, 'app_width') and hasattr(self, 'app_height') and
438+ hasattr(self, 'grid_unit_px'))
439+
440+ def simulate_device(self):
441+ simulate_device_fixture = self.useFixture(
442+ toolkit_fixtures.SimulateDevice(
443+ self.app_width, self.app_height, self.grid_unit_px))
444+ self.app_width = simulate_device_fixture.app_width
445+ self.app_height = simulate_device_fixture.app_height
446+
447+ def resize_window(self):
448+ application = self.process_manager.get_running_applications()[0]
449+ window = application.get_windows()[0]
450+ window.resize(self.app_width, self.app_height)
451+
452+ def get_window_size():
453+ _, _, window_width, window_height = window.geometry
454+ return window_width, window_height
455+
456+ self.assertThat(
457+ get_window_size,
458+ Eventually(Equals((self.app_width, self.app_height))))
459+
460+ def launch_dash(self, binary_path, variables):
461+ launch_dash_app_fixture = fixture_setup.LaunchDashApp(
462+ binary_path, variables)
463+ self.useFixture(launch_dash_app_fixture)
464+ return launch_dash_app_fixture.application_proxy
tests/autopilot/unity8/shell/tests/test_emulators.py+3−14
@@ -53,18 +53,7 @@ class MainWindowTestCase(tests.UnityTestCase):
5353 self.assertEqual(text_field.text, 'Test')
5454
5555
56−class DashBaseTestCase(tests.UnityTestCase):
57−
58− scenarios = tests._get_device_emulation_scenarios()
59−
60− def setUp(self):
61− super(DashBaseTestCase, self).setUp()
62− unity_proxy = self.launch_unity()
63− process_helpers.unlock_unity(unity_proxy)
64− self.dash = self.main_window.get_dash()
65−
66−
67−class DashEmulatorTestCase(DashBaseTestCase):
56+class DashEmulatorTestCase(tests.DashBaseTestCase):
6857
6958 def test_open_unexisting_scope(self):
7059 scope_name = 'unexisting'
@@ -145,7 +134,7 @@ class DashEmulatorTestCase(DashBaseTestCase):
145134 self.assertIsInstance(scope, dash_emulators.GenericScopeView)
146135
147136
148−class GenericScopeViewEmulatorTestCase(DashBaseTestCase):
137+class GenericScopeViewEmulatorTestCase(tests.DashBaseTestCase):
149138
150139 def setUp(self):
151140 # Set up the fake scopes before launching unity.
@@ -159,7 +148,7 @@ class GenericScopeViewEmulatorTestCase(DashBaseTestCase):
159148 self.assertTrue(preview.isCurrent)
160149
161150
162−class DashAppsEmulatorTestCase(DashBaseTestCase):
151+class DashAppsEmulatorTestCase(tests.DashBaseTestCase):
163152
164153 available_applications = [
165154 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',