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
69 def _get_device_emulation_scenarios(devices='All'):
70 nexus4 = (
'Desktop Nexus 4',
71 dict(app_width=768, app_height=1280, grid_unit_px=18))
72 nexus10 = (
'Desktop Nexus 10',
73 dict(app_width=2560, app_height=1600, grid_unit_px=20))
74 native = (
'Native Device',
75 dict(app_width=0, app_height=0, grid_unit_px=0))
77 if model() ==
'Desktop':
79 return [nexus4, nexus10]
80 elif devices ==
'Nexus4':
82 elif devices ==
'Nexus10':
86 'Unrecognized device-option "%s" passed.' % devices
92 def is_unity7_running():
93 """Return True if Unity7 is running. Otherwise, return False."""
96 UNITYSHELL_GSETTINGS_SCHEMA
in
97 Gio.Settings.list_relocatable_schemas()
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'))
107 qml_import_path =
':'.join(qml_import_path)
108 logger.info(
"New QML2 import path: %s", qml_import_path)
109 return qml_import_path
114 """A test case base class for the Unity shell tests."""
119 output = subprocess.check_output(
120 [
"/sbin/initctl",
"status",
"unity8"],
121 stderr=subprocess.STDOUT,
122 universal_newlines=
True,
124 except subprocess.CalledProcessError
as e:
126 "Error: `initctl status unity8` failed, most probably the "
127 "unity8 session could not be found:\n\n"
129 "Please install unity8 or copy data/unity8.conf to "
132 os.path.join(os.getenv(
"XDG_CONFIG_HOME",
133 os.path.join(os.getenv(
"HOME"),
141 if "start/" in output:
143 "Error: Unity is currently running, these tests require it to "
145 "Please run this command before running these tests: \n"
146 "initctl stop unity8\n"
151 super(UnityTestCase, self).setUp()
152 if is_unity7_running():
153 self.useFixture(toolkit_fixtures.HideUnity7Launcher())
162 if model() !=
"Desktop":
163 from autopilot.input
import _uinput
164 _uinput._touch_device = _uinput.create_touch_device()
165 self.addCleanup(_uinput._touch_device.close)
167 self.
touch = Touch.create()
170 def _setup_display_details(self):
174 def _determine_geometry(self):
175 """Use the geometry that may be supplied or use the default."""
176 width = getattr(self,
'app_width', 0)
177 height = getattr(self,
'app_height', 0)
180 if width > 0
and height > 0:
183 width = width / scale_divisor
184 height = height / scale_divisor
186 "Geometry larger than display, scaled down to: %dx%d",
190 geo_string =
"%dx%d" % (width, height)
199 def _setup_grid_size(self, scale_divisor):
200 """Use the grid size that may be supplied or use the default."""
201 if getattr(self,
'grid_unit_px', 0) == 0:
202 self.
grid_size = int(os.getenv(
'GRID_UNIT_PX'))
204 self.
grid_size = int(self.grid_unit_px / scale_divisor)
208 self.patch_environment(
"GRID_UNIT_PX", str(self.
grid_size))
210 def _geo_larger_than_display(self, width, height):
211 should_scale = getattr(self,
'scale_geo',
True)
213 screen = Display.create()
214 screen_width = screen.get_screen_width()
215 screen_height = screen.get_screen_height()
216 return (width > screen_width)
or (height > screen_height)
220 def _get_scaled_down_geo(self, width, height):
223 divisor = divisor * 2
226 def _patch_environment(self, key, value):
227 """Wrapper for patching env for upstart environment."""
229 current_value = subprocess.check_output(
230 [
"/sbin/initctl",
"get-env",
"--global", key],
231 stderr=subprocess.STDOUT,
232 universal_newlines=
True,
234 except subprocess.CalledProcessError:
241 "%s=%s" % (key, value)
242 ], stderr=subprocess.STDOUT)
245 def _upstart_reset_env(self, key, value):
246 logger.info(
"Resetting upstart env %s to %s", key, value)
249 [
"/sbin/initctl",
"unset-env", key],
250 stderr=subprocess.STDOUT,
257 "%s=%s" % (key, value)
258 ], stderr=subprocess.STDOUT)
261 """Launch the unity shell, return a proxy object for it."""
262 binary_path = get_binary_path()
263 lib_path = get_lib_path()
266 "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")
305 logger.debug(
"Unity started, waiting for it to be ready.")
307 logger.debug(
"Unity loaded and ready.")
309 if model() ==
'Desktop':
312 process_helpers.stop_job(
'unity8-dash')
316 def _launch_unity_with_upstart(self, binary_path, args):
317 logger.info(
"Starting unity")
320 binary_arg =
"BINARY=%s" % binary_path
321 extra_args =
"ARGS=%s" %
" ".join(args)
322 env_args = [
"%s=%s" % (k, v)
for k, v
in self._environment.items()]
323 all_args = [binary_arg, extra_args] + env_args
327 return process_helpers.restart_unity_with_testability(*all_args)
329 def _cleanup_launching_upstart_unity(self):
330 logger.info(
"Stopping unity")
332 subprocess.check_output(
333 [
"/sbin/initctl",
"stop",
"unity8"],
334 stderr=subprocess.STDOUT
336 except subprocess.CalledProcessError:
337 logger.warning(
"Appears unity was already stopped!")
339 def _patch_data_dirs(self):
341 if data_dirs
is not None:
344 def patch_lightdm_mock(self, mock_type='single'):
346 logger.info(
"Setting up LightDM mock type '%s'", mock_type)
347 new_ld_library_path = [
348 get_default_extra_mock_libraries(),
351 if os.getenv(
'LD_LIBRARY_PATH')
is not None:
352 new_ld_library_path.append(os.getenv(
'LD_LIBRARY_PATH'))
354 new_ld_library_path =
':'.join(new_ld_library_path)
355 logger.info(
"New library path: %s", new_ld_library_path)
357 self.
_environment[
'LD_LIBRARY_PATH'] = new_ld_library_path
359 def _get_lightdm_mock_path(self, mock_type):
360 lib_path = get_mocks_library_path()
361 lightdm_mock_path = os.path.abspath(
362 os.path.join(lib_path,
"LightDM", mock_type)
365 if not os.path.exists(lightdm_mock_path):
367 "LightDM mock '%s' does not exist at path '%s'."
368 % (mock_type, lightdm_mock_path)
370 return lightdm_mock_path
372 def _set_proxy(self, proxy):
373 """Keep a copy of the proxy object, so we can use it to get common
374 parts of the shell later on.
380 def _clear_proxy(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)
389 pid = process_helpers.get_job_pid(
'unity8-dash')
390 dash_proxy = introspection.get_proxy_object_for_existing_process(
394 dash_app = dash_helpers.DashApp(dash_proxy)
398 def main_window(self):
399 return self._proxy.select_single(main_window_emulator.QQuickView)
402 class DashBaseTestCase(AutopilotTestCase):
404 scenarios = ubuntu_scenarios.get_device_simulation_scenarios()
405 qml_mock_enabled =
True
409 super(DashBaseTestCase, self).setUp()
411 if is_unity7_running():
412 self.useFixture(toolkit_fixtures.HideUnity7Launcher())
414 if model() !=
'Desktop':
416 self.addCleanup(process_helpers.stop_job,
'unity8')
417 process_helpers.restart_unity_with_testability()
418 process_helpers.unlock_unity()
420 self.ensure_dash_not_running()
422 if self.qml_mock_enabled:
423 self.environment[
'QML2_IMPORT_PATH'] = (
424 get_qml_import_path_with_mock()
427 if self.should_simulate_device():
430 self.simulate_device()
432 binary_path = get_binary_path(
'unity8-dash')
433 dash_proxy = self.launch_dash(binary_path, self.environment)
435 if self.should_simulate_device():
441 self.dash_app = dash_helpers.DashApp(dash_proxy)
442 self.dash = self.dash_app.dash
445 def ensure_dash_not_running(self):
446 if process_helpers.is_job_running(
'unity8-dash'):
447 process_helpers.stop_job(
'unity8-dash')
449 def launch_dash(self, binary_path, variables):
451 binary_path, variables)
452 self.useFixture(launch_dash_app_fixture)
453 return launch_dash_app_fixture.application_proxy
455 def wait_for_dash(self):
456 home_scope = self.dash.get_scope(
'clickscope')
461 Eventually(Equals(
True), timeout=60)
463 self.assertThat(home_scope.isCurrent, Eventually(Equals(
True)))
465 def should_simulate_device(self):
466 return (hasattr(self,
'app_width')
and hasattr(self,
'app_height')
and
467 hasattr(self,
'grid_unit_px'))
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
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)
481 def get_window_size():
482 _, _, window_width, window_height = window.geometry
483 return window_width, window_height
487 Eventually(Equals((self.app_width, self.app_height))))
def _cleanup_launching_upstart_unity
def _get_lightdm_mock_path
def _launch_unity_with_upstart
def _setup_display_details
def _geo_larger_than_display