@@ -1,81 +1,187 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
4−# This program is free software: you can redistribute it and/or modify it
6+# This program is free software: you can redistribute it and/or modify
5−# under the terms of the GNU General Public License version 3, as published
7+# it under the terms of the GNU General Public License as published by
6−# by the Free Software Foundation.
8+# the Free Software Foundation, either version 3 of the License, or
7−
9+# (at your option) any later version.
8−"""unity8 autopilot tests."""
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.
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/>.
10−import os.path
20+"""unity autopilot tests."""
22+from autopilot.platform import model
13from autopilot.testcase import AutopilotTestCase
23from autopilot.testcase import AutopilotTestCase
14from autopilot.matchers import Eventually
24from autopilot.matchers import Eventually
15−from autopilot.platform import model
25+from autopilot.input import Touch
26+from autopilot.display import Display
16−from testtools.matchers import Equals
29+from testtools.matchers import Equals, NotEquals
31+from unity8 import get_lib_path, get_binary_path, get_mocks_library_path
32+from unity8.shell.emulators import UnityEmulatorBase
33+from unity8.shell.emulators.dash import Dash
18from unity8.shell.emulators.main_window import MainWindow
34from unity8.shell.emulators.main_window import MainWindow
20−class FormFactors(object):
21− Phone, Tablet, Desktop = range(3)
23−class ShellTestCase(AutopilotTestCase):
37+logger = logging.getLogger(__name__)
25− """A common test case class that provides several useful methods for shell tests."""
27− libdir = "/usr/lib/{0}/unity8".format(sysconfig.get_config_var('MULTIARCH'))
40+def _get_device_emulation_scenarios():
28− lightdm_mock = "full"
41+ if model() == 'Desktop':
45+ dict(app_width=768, app_height=1280, grid_unit_px=18)
49+ dict(app_width=2560, app_height=1600, grid_unit_px=20)
56+ dict(app_width=0, app_height=0, grid_unit_px=0)
61+class UnityTestCase(AutopilotTestCase):
63+ """A test case base class for the Unity shell tests."""
30− def setUp(self, geometry, grid_size):
65+ def setUp(self):
31− super(ShellTestCase, self).setUp()
66+ super(UnityTestCase, self).setUp()
32− # Lets assume we are installed system wide if this file is somewhere in /usr
67+ self._proxy = None
33− if grid_size != "0":
68+ self.touch = Touch.create()
34− os.environ['GRID_UNIT_PX'] = grid_size
69+ self._setup_display_details()
35− self.grid_size = int(grid_size)
70+
36− else:
71+ def _setup_display_details(self):
37− self.grid_size = int(os.environ['GRID_UNIT_PX'])
72+ scale_divisor = self._determine_geometry()
38− if os.path.realpath(__file__).startswith("/usr/"):
73+ self._setup_grid_size(scale_divisor)
39− self.launch_test_installed(geometry)
74+
75+ def _determine_geometry(self):
76+ """Use the geometry that may be supplied or use the default."""
77+ width = getattr(self, 'app_width', 0)
78+ height = getattr(self, 'app_height', 0)
80+ if width == 0 and width == 0:
81+ self.unity_geometry_args = ['-fullscreen']
41− self.launch_test_local(geometry)
83+ if self._geo_larger_than_display(width, height):
42−
84+ scale_divisor = self._get_scaled_down_geo(width, height)
43− def launch_test_local(self, geometry):
85+ width = width / scale_divisor
44− os.environ['LD_LIBRARY_PATH'] = "../../builddir/tests/mocks/libusermetrics:../../builddir/tests/mocks/LightDM" + self.lightdm_mock
86+ height = height / scale_divisor
45− os.environ['QML2_IMPORT_PATH'] = "../../builddir/tests/mocks"
87+ logger.info(
46− if geometry != "0x0":
88+ "Geometry larger than display, scaled down to: %dx%d",
47− self.app = self.launch_test_application(
89+ width,
48− "../../builddir/unity8", "-geometry", geometry, "-frameless", app_type='qt')
90+ height
92+ geo_string = "%dx%d" % (width, height)
93+ self.unity_geometry_args = [
101+ def _setup_grid_size(self, scale_divisor):
102+ """Use the grid size that may be supplied or use the default."""
103+ if getattr(self, 'grid_unit_px', 0) == 0:
104+ self.grid_size = int(os.getenv('GRID_UNIT_PX'))
50− self.app = self.launch_test_application(
106+ self.grid_size = int(self.grid_unit_px / scale_divisor)
51− "../../builddir/unity8", "-fullscreen", app_type='qt')
107+ self.patch_environment("GRID_UNIT_PX", str(self.grid_size))
53− def launch_test_installed(self, geometry):
109+ def _geo_larger_than_display(self, width, height):
54− os.environ['LD_LIBRARY_PATH'] = "{0}/qml/mocks/libusermetrics:{0}/qml/mocks/LightDM/{1}".format(self.libdir, self.lightdm_mock)
110+ should_scale = getattr(self, 'scale_geo', True)
55− os.environ['QML2_IMPORT_PATH'] = "{0}/qml/mocks".format(self.libdir)
111+ if should_scale:
56− if model() == 'Desktop' and geometry != "0x0":
112+ screen = Display.create()
57− self.app = self.launch_test_application(
113+ screen_width = screen.get_screen_width()
58− "unity8", "-geometry", geometry, "-frameless", app_type='qt')
114+ screen_height = screen.get_screen_height()
115+ return (width > screen_width) or (height > screen_height)
119+ def _get_scaled_down_geo(self, width, height):
121+ while self._geo_larger_than_display(width / divisor, height / divisor):
122+ divisor = divisor * 2
125+ def launch_unity(self):
126+ """Launch the unity shell, return a proxy object for it."""
127+ binary_path = get_binary_path()
128+ lib_path = get_lib_path()
131+ "Lib path is '%s', binary path is '%s'",
136+ self._setup_extra_mock_environment_patch()
60− self.app = self.launch_test_application(
138+ app_proxy = self.launch_test_application(
140+ *self.unity_geometry_args,
61− "unity8", "-fullscreen", app_type='qt')
141+ app_type='qt',
142+ emulator_base=UnityEmulatorBase
144+ self._set_proxy(app_proxy)
146+ # Ensure that the dash is visible before we return:
147+ logger.debug("Unity started, waiting for it to be ready.")
148+ self.assertUnityReady()
149+ logger.debug("Unity loaded and ready.")
153+ def _setup_extra_mock_environment_patch(self):
154+ mocks_library_path = get_mocks_library_path()
155+ self.patch_environment('QML2_IMPORT_PATH', mocks_library_path)
157+ def _set_proxy(self, proxy):
158+ """Keep a copy of the proxy object, so we can use it to get common
159+ parts of the shell later on.
163+ self.addCleanup(self._clear_proxy)
165+ def _clear_proxy(self):
63− def skipWrapper(*args, **kwargs):
168+ def assertUnityReady(self):
64− pass
169+ dash = self.get_dash()
170+ home_scope = dash.get_scope('home')
66− def form_factor(self):
172+ # FIXME! There is a huge timeout here for when we're doing CI on
67− return FormFactors.Desktop
173+ # VMs. See lp:1203715
175+ home_scope.isLoaded,
176+ Eventually(Equals(True), timeout=60)
178+ self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
69− def __getattribute__(self, attr_name):
180+ def get_dash(self):
70− attr = object.__getattribute__(self, attr_name);
181+ dash = self._proxy.select_single(Dash)
71− if attr_name.startswith("test_"):
182+ self.assertThat(dash, NotEquals(None))
73− if self.form_factor() in attr.blacklist:
74− return self.skipWrapper
77− return attr
183+ return dash
79 @property
185 @property
80 def main_window(self):
186 def main_window(self):
81− return MainWindow(self.app)
187+ return MainWindow(self._proxy)