20 """unity autopilot tests."""
23 from gi.repository
import Gio
27 from autopilot.platform
import model
28 from autopilot.testcase
import AutopilotTestCase
29 from autopilot.matchers
import Eventually
30 from autopilot.input
import Touch
31 from autopilot.display
import Display
36 from testtools.matchers
import Equals
41 get_mocks_library_path,
42 get_default_extra_mock_libraries,
50 logger = logging.getLogger(__name__)
52 UNITYSHELL_GSETTINGS_SCHEMA =
"org.compiz.unityshell"
53 UNITYSHELL_GSETTINGS_PATH =
"/org/compiz/profiles/unity/plugins/unityshell/"
54 UNITYSHELL_LAUNCHER_KEY =
"launcher-hide-mode"
55 UNITYSHELL_LAUNCHER_MODE = 1
58 def _get_device_emulation_scenarios(devices='All'):
59 nexus4 = (
'Desktop Nexus 4',
60 dict(app_width=768, app_height=1280, grid_unit_px=18))
61 nexus10 = (
'Desktop Nexus 10',
62 dict(app_width=2560, app_height=1600, grid_unit_px=20))
63 native = (
'Native Device',
64 dict(app_width=0, app_height=0, grid_unit_px=0))
66 if model() ==
'Desktop':
68 return [nexus4, nexus10]
69 elif devices ==
'Nexus4':
71 elif devices ==
'Nexus10':
75 'Unrecognized device-option "%s" passed.' % devices
83 """A test case base class for the Unity shell tests."""
88 output = subprocess.check_output(
89 [
"/sbin/initctl",
"status",
"unity8"],
90 stderr=subprocess.STDOUT,
91 universal_newlines=
True,
93 except subprocess.CalledProcessError
as e:
95 "Error: `initctl status unity8` failed, most probably the "
96 "unity8 session could not be found:\n\n"
98 "Please install unity8 or copy data/unity8.conf to "
101 os.path.join(os.getenv(
"XDG_CONFIG_HOME",
102 os.path.join(os.getenv(
"HOME"),
110 if "start/" in output:
112 "Error: Unity is currently running, these tests require it to "
114 "Please run this command before running these tests: \n"
115 "initctl stop unity8\n"
120 super(UnityTestCase, self).setUp()
121 if (Gio
is not None and
122 UNITYSHELL_GSETTINGS_SCHEMA
in
123 Gio.Settings.list_relocatable_schemas()):
127 UNITYSHELL_GSETTINGS_SCHEMA,
128 UNITYSHELL_GSETTINGS_PATH,
131 UNITYSHELL_LAUNCHER_KEY,
133 self._unityshell_schema.set_int(
134 UNITYSHELL_LAUNCHER_KEY,
135 UNITYSHELL_LAUNCHER_MODE,
146 if model() !=
"Desktop":
147 from autopilot.input
import _uinput
148 _uinput._touch_device = _uinput.create_touch_device()
149 self.addCleanup(_uinput._touch_device.close)
151 self.
touch = Touch.create()
154 def _reset_launcher(self):
155 """Reset Unity launcher hide mode"""
156 self._unityshell_schema.set_int(
157 UNITYSHELL_LAUNCHER_KEY,
161 def _setup_display_details(self):
165 def _determine_geometry(self):
166 """Use the geometry that may be supplied or use the default."""
167 width = getattr(self,
'app_width', 0)
168 height = getattr(self,
'app_height', 0)
171 if width > 0
and height > 0:
174 width = width / scale_divisor
175 height = height / scale_divisor
177 "Geometry larger than display, scaled down to: %dx%d",
181 geo_string =
"%dx%d" % (width, height)
190 def _setup_grid_size(self, scale_divisor):
191 """Use the grid size that may be supplied or use the default."""
192 if getattr(self,
'grid_unit_px', 0) == 0:
193 self.
grid_size = int(os.getenv(
'GRID_UNIT_PX'))
195 self.
grid_size = int(self.grid_unit_px / scale_divisor)
199 self.patch_environment(
"GRID_UNIT_PX", str(self.
grid_size))
201 def _geo_larger_than_display(self, width, height):
202 should_scale = getattr(self,
'scale_geo',
True)
204 screen = Display.create()
205 screen_width = screen.get_screen_width()
206 screen_height = screen.get_screen_height()
207 return (width > screen_width)
or (height > screen_height)
211 def _get_scaled_down_geo(self, width, height):
214 divisor = divisor * 2
217 def _patch_environment(self, key, value):
218 """Wrapper for patching env for upstart environment."""
220 current_value = subprocess.check_output(
221 [
"/sbin/initctl",
"get-env",
"--global", key],
222 stderr=subprocess.STDOUT,
223 universal_newlines=
True,
225 except subprocess.CalledProcessError:
232 "%s=%s" % (key, value)
233 ], stderr=subprocess.STDOUT)
236 def _upstart_reset_env(self, key, value):
237 logger.info(
"Resetting upstart env %s to %s", key, value)
240 [
"/sbin/initctl",
"unset-env", key],
241 stderr=subprocess.STDOUT,
248 "%s=%s" % (key, value)
249 ], stderr=subprocess.STDOUT)
252 """Launch the unity shell, return a proxy object for it."""
253 binary_path = get_binary_path()
254 lib_path = get_lib_path()
257 "Lib path is '%s', binary path is '%s'",
276 os.getenv(
'MIR_SOCKET',
277 os.path.join(os.getenv(
'XDG_RUNTIME_DIR',
"/tmp"),
282 os.unlink(
"/tmp/mir_socket")
294 logger.debug(
"Unity started, waiting for it to be ready.")
296 logger.debug(
"Unity loaded and ready.")
300 def _launch_unity_with_upstart(self, binary_path, args):
301 logger.info(
"Starting unity")
304 binary_arg =
"BINARY=%s" % binary_path
305 extra_args =
"ARGS=%s" %
" ".join(args)
306 env_args = [
"%s=%s" % (k, v)
for k, v
in self._environment.items()]
307 all_args = [binary_arg, extra_args] + env_args
311 return restart_unity_with_testability(*all_args)
313 def _cleanup_launching_upstart_unity(self):
314 logger.info(
"Stopping unity")
316 subprocess.check_output(
317 [
"/sbin/initctl",
"stop",
"unity8"],
318 stderr=subprocess.STDOUT
320 except subprocess.CalledProcessError:
321 logger.warning(
"Appears unity was already stopped!")
323 def _patch_data_dirs(self):
325 if data_dirs
is not None:
328 def patch_lightdm_mock(self, mock_type='single'):
330 logger.info(
"Setting up LightDM mock type '%s'", mock_type)
331 new_ld_library_path = [
332 get_default_extra_mock_libraries(),
335 if os.getenv(
'LD_LIBRARY_PATH')
is not None:
336 new_ld_library_path.append(os.getenv(
'LD_LIBRARY_PATH'))
338 new_ld_library_path =
':'.join(new_ld_library_path)
339 logger.info(
"New library path: %s", new_ld_library_path)
341 self.
_environment[
'LD_LIBRARY_PATH'] = new_ld_library_path
343 def _get_lightdm_mock_path(self, mock_type):
344 lib_path = get_mocks_library_path()
345 lightdm_mock_path = os.path.abspath(
346 os.path.join(lib_path,
"LightDM", mock_type)
349 if not os.path.exists(lightdm_mock_path):
351 "LightDM mock '%s' does not exist at path '%s'."
352 % (mock_type, lightdm_mock_path)
354 return lightdm_mock_path
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'))
361 qml_import_path =
':'.join(qml_import_path)
362 logger.info(
"New QML2 import path: %s", qml_import_path)
365 def _set_proxy(self, proxy):
366 """Keep a copy of the proxy object, so we can use it to get common
367 parts of the shell later on.
373 def _clear_proxy(self):
376 def assertUnityReady(self):
378 home_scope = dash.get_scope(
'clickscope')
384 Eventually(Equals(
True), timeout=60)
386 self.assertThat(home_scope.isCurrent, Eventually(Equals(
True)))
389 dash = self._proxy.wait_select_single(Dash)
393 def main_window(self):
394 return self._proxy.select_single(main_window_emulator.QQuickView)
def _cleanup_launching_upstart_unity
def _get_lightdm_mock_path
def _launch_unity_with_upstart
def _setup_extra_mock_environment_patch
def _setup_display_details
def _geo_larger_than_display