@@ -24,6 +24,7 @@ try:
2424except ImportError:
2525 Gio = None
2626
27+from autopilot import introspection
2728from autopilot.platform import model
2829from autopilot.testcase import AutopilotTestCase
2930from autopilot.matchers import Eventually
@@ -34,6 +35,10 @@ import os.path
3435import subprocess
3536import sys
3637from testtools.matchers import Equals
38+from ubuntuuitoolkit import (
39+ fixture_setup as toolkit_fixtures,
40+ ubuntu_scenarios
41+)
3742
3843from unity8 import (
3944 get_lib_path,
@@ -42,9 +47,15 @@ from unity8 import (
4247 get_default_extra_mock_libraries,
4348 get_data_dirs
4449)
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
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,
57+ main_window as main_window_emulator,
58+)
4859
4960
5061logger = logging.getLogger(__name__)
@@ -78,6 +89,26 @@ def _get_device_emulation_scenarios(devices='All'):
7889 return [native]
7990
8091
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+
81112class UnityTestCase(AutopilotTestCase):
82113
83114 """A test case base class for the Unity shell tests."""
@@ -118,23 +149,8 @@ class UnityTestCase(AutopilotTestCase):
118149
119150 def setUp(self):
120151 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)
152+ if is_unity7_running():
153+ self.useFixture(toolkit_fixtures.HideUnity7Launcher())
138154
139155 self._proxy = None
140156 self._lightdm_mock_type = None
@@ -151,13 +167,6 @@ class UnityTestCase(AutopilotTestCase):
151167 self.touch = Touch.create()
152168 self._setup_display_details()
153169
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−
161170 def _setup_display_details(self):
162171 scale_divisor = self._determine_geometry()
163172 self._setup_grid_size(scale_divisor)
@@ -263,7 +272,9 @@ class UnityTestCase(AutopilotTestCase):
263272 self.patch_lightdm_mock()
264273
265274 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+ )
267278
268279 if self._data_dirs_mock_enabled:
269280 self._patch_data_dirs()
@@ -292,9 +303,14 @@ class UnityTestCase(AutopilotTestCase):
292303
293304 # Ensure that the dash is visible before we return:
294305 logger.debug("Unity started, waiting for it to be ready.")
295− self.assertUnityReady()
306+ self.wait_for_unity()
296307 logger.debug("Unity loaded and ready.")
297308
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+
298314 return app_proxy
299315
300316 def _launch_unity_with_upstart(self, binary_path, args):
@@ -308,7 +324,7 @@ class UnityTestCase(AutopilotTestCase):
308324
309325 self.addCleanup(self._cleanup_launching_upstart_unity)
310326
311− return restart_unity_with_testability(*all_args)
327+ return process_helpers.restart_unity_with_testability(*all_args)
312328
313329 def _cleanup_launching_upstart_unity(self):
314330 logger.info("Stopping unity")
@@ -353,15 +369,6 @@ class UnityTestCase(AutopilotTestCase):
353369 )
354370 return lightdm_mock_path
355371
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−
365372 def _set_proxy(self, proxy):
366373 """Keep a copy of the proxy object, so we can use it to get common
367374 parts of the shell later on.
@@ -373,10 +380,80 @@ class UnityTestCase(AutopilotTestCase):
373380 def _clear_proxy(self):
374381 self._proxy = None
375382
376− def assertUnityReady(self):
377− dash = self.get_dash()
378− home_scope = dash.get_scope('clickscope')
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+
388+ def get_dash(self):
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)
379400
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')
380457 # FIXME! There is a huge timeout here for when we're doing CI on
381458 # VMs. See lp:1203715
382459 self.assertThat(
@@ -385,10 +462,26 @@ class UnityTestCase(AutopilotTestCase):
385462 )
386463 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
387464
388− def get_dash(self):
389− dash = self._proxy.wait_select_single(Dash)
390− return dash
465+ def should_simulate_device(self):
466+ return (hasattr(self, 'app_width') and hasattr(self, 'app_height') and
467+ hasattr(self, 'grid_unit_px'))
391468
392− @property
393− def main_window(self):
394− return self._proxy.select_single(main_window_emulator.QQuickView)
469+ def simulate_device(self):
470+ simulate_device_fixture = self.useFixture(
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))))