20 """unity autopilot tests."""
23 from gi.repository
import Gio
27 from autopilot
import introspection
28 from autopilot.platform
import model
29 from autopilot.testcase
import AutopilotTestCase
30 from autopilot.matchers
import Eventually
31 from autopilot.input
import Touch
32 from autopilot.display
import Display
37 from testtools.matchers
import Equals
38 from ubuntuuitoolkit
import (
39 fixture_setup
as toolkit_fixtures,
46 get_mocks_library_path,
47 get_default_extra_mock_libraries,
57 main_window
as main_window_emulator,
61 logger = logging.getLogger(__name__)
63 UNITYSHELL_GSETTINGS_SCHEMA =
"org.compiz.unityshell"
64 UNITYSHELL_GSETTINGS_PATH =
"/org/compiz/profiles/unity/plugins/unityshell/"
65 UNITYSHELL_LAUNCHER_KEY =
"launcher-hide-mode"
66 UNITYSHELL_LAUNCHER_MODE = 1
68 def _get_device_emulation_scenarios(devices='All'):
69 nexus4 = (
'Desktop Nexus 4',
70 dict(app_width=768, app_height=1280, grid_unit_px=18))
71 nexus10 = (
'Desktop Nexus 10',
72 dict(app_width=2560, app_height=1600, grid_unit_px=20))
73 native = (
'Native Device',
74 dict(app_width=0, app_height=0, grid_unit_px=0))
76 if model() ==
'Desktop':
78 return [nexus4, nexus10]
79 elif devices ==
'Nexus4':
81 elif devices ==
'Nexus10':
85 'Unrecognized device-option "%s" passed.' % devices
91 def is_unity7_running():
92 """Return True if Unity7 is running. Otherwise, return False."""
95 UNITYSHELL_GSETTINGS_SCHEMA
in
96 Gio.Settings.list_relocatable_schemas()
100 def get_qml_import_path_with_mock():
101 """Return the QML2_IMPORT_PATH value with the mock path prepended."""
102 qml_import_path = [get_mocks_library_path()]
103 if os.getenv(
'QML2_IMPORT_PATH')
is not None:
104 qml_import_path.append(os.getenv(
'QML2_IMPORT_PATH'))
106 qml_import_path =
':'.join(qml_import_path)
107 logger.info(
"New QML2 import path: %s", qml_import_path)
108 return qml_import_path
113 """A test case base class for the Unity shell tests."""
118 output = subprocess.check_output(
119 [
"/sbin/initctl",
"status",
"unity8"],
120 stderr=subprocess.STDOUT,
121 universal_newlines=
True,
123 except subprocess.CalledProcessError
as e:
125 "Error: `initctl status unity8` failed, most probably the "
126 "unity8 session could not be found:\n\n"
128 "Please install unity8 or copy data/unity8.conf to "
131 os.path.join(os.getenv(
"XDG_CONFIG_HOME",
132 os.path.join(os.getenv(
"HOME"),
140 if "start/" in output:
142 "Error: Unity is currently running, these tests require it to "
144 "Please run this command before running these tests: \n"
145 "initctl stop unity8\n"
151 if is_unity7_running():
152 self.useFixture(toolkit_fixtures.HideUnity7Launcher())
160 if model() !=
"Desktop":
161 from autopilot.input
import _uinput
162 _uinput._touch_device = _uinput.create_touch_device()
163 self.addCleanup(_uinput._touch_device.close)
165 self.
touch = Touch.create()
168 def _setup_display_details(self):
172 def _determine_geometry(self):
173 """Use the geometry that may be supplied or use the default."""
174 width = getattr(self,
'app_width', 0)
175 height = getattr(self,
'app_height', 0)
178 if width > 0
and height > 0:
181 width = width / scale_divisor
182 height = height / scale_divisor
184 "Geometry larger than display, scaled down to: %dx%d",
188 geo_string =
"%dx%d" % (width, height)
197 def _setup_grid_size(self, scale_divisor):
198 """Use the grid size that may be supplied or use the default."""
199 if getattr(self,
'grid_unit_px', 0) == 0:
200 self.
grid_size = int(os.getenv(
'GRID_UNIT_PX'))
202 self.
grid_size = int(self.grid_unit_px / scale_divisor)
205 def _geo_larger_than_display(self, width, height):
206 should_scale = getattr(self,
'scale_geo',
True)
208 screen = Display.create()
209 screen_width = screen.get_screen_width()
210 screen_height = screen.get_screen_height()
211 return (width > screen_width)
or (height > screen_height)
215 def _get_scaled_down_geo(self, width, height):
218 divisor = divisor * 2
221 def _patch_environment(self, key, value):
222 """Wrapper for patching env for upstart environment."""
224 current_value = subprocess.check_output(
225 [
"/sbin/initctl",
"get-env",
"--global", key],
226 stderr=subprocess.STDOUT,
227 universal_newlines=
True,
229 except subprocess.CalledProcessError:
236 "%s=%s" % (key, value)
237 ], stderr=subprocess.STDOUT)
240 def _upstart_reset_env(self, key, value):
241 logger.info(
"Resetting upstart env %s to %s", key, value)
244 [
"/sbin/initctl",
"unset-env", key],
245 stderr=subprocess.STDOUT,
252 "%s=%s" % (key, value)
253 ], stderr=subprocess.STDOUT)
257 Launch the unity shell, return a proxy object for it.
259 :param str mode: The type of greeter/shell mode to use
260 :param args: A list of aguments to pass to unity8
263 binary_path = get_binary_path()
264 lib_path = get_lib_path()
267 "Lib path is '%s', binary path is '%s'",
276 get_qml_import_path_with_mock()
287 os.getenv(
'MIR_SOCKET',
288 os.path.join(os.getenv(
'XDG_RUNTIME_DIR',
"/tmp"),
293 os.unlink(
"/tmp/mir_socket")
297 unity8_cli_args_list = [
"--mode={}".format(mode)]
299 unity8_cli_args_list += args
309 logger.debug(
"Unity started, waiting for it to be ready.")
311 logger.debug(
"Unity loaded and ready.")
313 if model() ==
'Desktop':
316 process_helpers.stop_job(
'unity8-dash')
320 def _launch_unity_with_upstart(self, binary_path, args):
321 logger.info(
"Starting unity")
324 binary_arg =
"BINARY=%s" % binary_path
325 extra_args =
"ARGS=%s" %
" ".join(args)
326 env_args = [
"%s=%s" % (k, v)
for k, v
in self._environment.items()]
327 all_args = [binary_arg, extra_args] + env_args
331 return process_helpers.restart_unity_with_testability(*all_args)
333 def _cleanup_launching_upstart_unity(self):
334 logger.info(
"Stopping unity")
336 subprocess.check_output(
337 [
"/sbin/initctl",
"stop",
"unity8"],
338 stderr=subprocess.STDOUT
340 except subprocess.CalledProcessError:
341 logger.warning(
"Appears unity was already stopped!")
343 def _patch_data_dirs(self):
345 if data_dirs
is not None:
348 def patch_lightdm_mock(self):
349 logger.info(
"Setting up LightDM mock lib")
350 new_ld_library_path = [
351 get_default_extra_mock_libraries(),
354 if os.getenv(
'LD_LIBRARY_PATH')
is not None:
355 new_ld_library_path.append(os.getenv(
'LD_LIBRARY_PATH'))
357 new_ld_library_path =
':'.join(new_ld_library_path)
358 logger.info(
"New library path: %s", new_ld_library_path)
360 self.
_environment[
'LD_LIBRARY_PATH'] = new_ld_library_path
362 def _get_lightdm_mock_path(self):
363 lib_path = get_mocks_library_path()
364 lightdm_mock_path = os.path.abspath(
365 os.path.join(lib_path,
"LightDM",
"liblightdm")
368 if not os.path.exists(lightdm_mock_path):
370 "LightDM mock does not exist at path '%s'."
371 % (lightdm_mock_path)
373 return lightdm_mock_path
375 def _set_proxy(self, proxy):
376 """Keep a copy of the proxy object, so we can use it to get common
377 parts of the shell later on.
383 def _clear_proxy(self):
386 def wait_for_unity(self):
387 greeter = self.main_window.wait_select_single(objectName=
'greeter')
388 greeter.waiting.wait_for(
False)
391 pid = process_helpers.get_job_pid(
'unity8-dash')
392 dash_proxy = introspection.get_proxy_object_for_existing_process(
396 dash_app = dash_helpers.DashApp(dash_proxy)
400 def main_window(self):
401 return self._proxy.select_single(main_window_emulator.QQuickView)
404 class DashBaseTestCase(AutopilotTestCase):
406 scenarios = ubuntu_scenarios.get_device_simulation_scenarios()
407 qml_mock_enabled =
True
413 if is_unity7_running():
414 self.useFixture(toolkit_fixtures.HideUnity7Launcher())
416 if model() !=
'Desktop':
418 self.addCleanup(process_helpers.stop_job,
'unity8')
419 process_helpers.restart_unity_with_testability()
420 process_helpers.unlock_unity()
422 self.ensure_dash_not_running()
424 if self.qml_mock_enabled:
425 self.environment[
'QML2_IMPORT_PATH'] = (
426 get_qml_import_path_with_mock()
429 if self.should_simulate_device():
432 self.simulate_device()
434 binary_path = get_binary_path(
'unity8-dash')
435 dash_proxy = self.launch_dash(binary_path, self.environment)
437 self.dash_app = dash_helpers.DashApp(dash_proxy)
438 self.dash = self.dash_app.dash
441 def ensure_dash_not_running(self):
442 if process_helpers.is_job_running(
'unity8-dash'):
443 process_helpers.stop_job(
'unity8-dash')
445 def launch_dash(self, binary_path, variables):
447 binary_path, variables)
448 self.useFixture(launch_dash_app_fixture)
449 return launch_dash_app_fixture.application_proxy
451 def wait_for_dash(self):
452 home_scope = self.dash.get_scope_by_index(0)
457 Eventually(Equals(
True), timeout=60)
459 self.assertThat(home_scope.isCurrent, Eventually(Equals(
True)))
461 def should_simulate_device(self):
462 return (hasattr(self,
'app_width')
and hasattr(self,
'app_height')
and
463 hasattr(self,
'grid_unit_px'))
465 def simulate_device(self):
466 simulate_device_fixture = self.useFixture(
467 toolkit_fixtures.SimulateDevice(
468 self.app_width, self.app_height, self.grid_unit_px))
469 self.environment[
'GRID_UNIT_PX'] = simulate_device_fixture.grid_unit_px
470 self.environment[
'ARGS'] =
'-windowgeometry {0}x{1}'\
471 .format(simulate_device_fixture.app_width,
472 simulate_device_fixture.app_height)
def launch_unity(self, mode="full-greeter", args)
def _patch_data_dirs(self)
def _set_proxy(self, proxy)
def _geo_larger_than_display(self, width, height)
def _cleanup_launching_upstart_unity(self)
def patch_lightdm_mock(self)
def _setup_grid_size(self, scale_divisor)
def _get_lightdm_mock_path(self)
def _setup_display_details(self)
def _patch_environment(self, key, value)
def _upstart_reset_env(self, key, value)
def _determine_geometry(self)
def _launch_unity_with_upstart(self, binary_path, args)
def _get_scaled_down_geo(self, width, height)