Merge lp:~autopilot/unity8/autopilot-test-refactoring into lp:unity8

Proposed by Christopher Lee
Status: Merged
Approved by: Michael Zanetti
Approved revision: 168
Merged at revision: 128
Proposed branch: lp:~autopilot/unity8/autopilot-test-refactoring
Merge into: lp:unity8
Diff against target: 1746 lines (+934/-560)
20 files modified
Dash/DashContent.qml (+5/-0)
cmake/modules/autopilot.cmake (+2/-1)
tests/autopilot/setup.py (+18/-7)
tests/autopilot/unity8/__init__.py (+92/-7)
tests/autopilot/unity8/indicators_client/__init__.py (+1/-1)
tests/autopilot/unity8/indicators_client/tests/__init__.py (+13/-9)
tests/autopilot/unity8/indicators_client/tests/test_battery.py (+4/-1)
tests/autopilot/unity8/shell/__init__.py (+63/-7)
tests/autopilot/unity8/shell/emulators/__init__.py (+24/-5)
tests/autopilot/unity8/shell/emulators/dash.py (+52/-0)
tests/autopilot/unity8/shell/emulators/greeter.py (+40/-0)
tests/autopilot/unity8/shell/emulators/hud.py (+83/-0)
tests/autopilot/unity8/shell/emulators/launcher.py (+38/-0)
tests/autopilot/unity8/shell/emulators/main_window.py (+44/-13)
tests/autopilot/unity8/shell/tests/__init__.py (+178/-72)
tests/autopilot/unity8/shell/tests/helpers.py (+0/-161)
tests/autopilot/unity8/shell/tests/test_hud.py (+144/-133)
tests/autopilot/unity8/shell/tests/test_lock_screen.py (+133/-0)
tests/autopilot/unity8/shell/tests/testbigscreen.py (+0/-25)
tests/autopilot/unity8/shell/tests/testlockscreen.py (+0/-118)
To merge this branch: bzr merge lp:~autopilot/unity8/autopilot-test-refactoring
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Michael Zanetti (community) Approve
Thomi Richards (community) Approve
Michał Sawicz Needs Fixing
Review via email: mp+175452@code.launchpad.net

This proposal supersedes a proposal from 2013-07-17.

Commit message

Refactoring and cleanup of the Unity8 Autopilot tests.

Description of the change

Refactoring and cleanup of the Unity8 Autopilot tests.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

test_lock_screen.py: multiple new lines at end of file

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Hey, the common failures are:

Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/unity8/shell/__init__.py", line 42, in wrapper
    return fn(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/unity8/shell/tests/test_lock_screen.py", line 56, in test_can_unlock_passphrase_screen
    greeter.unlock()
  File "/usr/lib/python2.7/dist-packages/unity8/shell/emulators/greeter.py", line 48, in unlock
    self.created.wait_for(False)
  File "/usr/lib/python2.7/dist-packages/autopilot/introspection/dbus.py", line 204, in wait_for
    failure_msg))
AssertionError: After 10.0 seconds test on Greeter.created failed: False != dbus.Boolean(True, variant_level=1)

Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/unity8/shell/__init__.py", line 42, in wrapper
    return fn(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/unity8/shell/tests/test_lock_screen.py", line 54, in test_can_unlock_passphrase_screen
    self.launch_unity()
  File "/usr/lib/python2.7/dist-packages/unity8/shell/tests/__init__.py", line 152, in launch_unity
    Eventually(Equals(""))
MismatchError: After 10.0 seconds test on Dash.showScopeOnLoaded failed: '' != dbus.String(u'home.scope', variant_level=1)

The latter generally means that the home scope didn't show up in time. But on the videos you can see it is, in fact, there... It might be that the timeout is just too low - it takes a few good seconds for the shell to start and settle down.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Hey, with the latest fix in trunk, on device, here's the results:

Ran 11 tests in 191.004s
FAILED (failures=4)

FAIL: unity8.indicators_client.tests.test_battery.TestDisplayMenus.test_auto_bright_switch(with touch)
FAIL: unity8.indicators_client.tests.test_battery.TestDisplayMenus.test_brightness_slider(with touch)
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/unity8/indicators_client/tests/test_battery.py", line 29, in setUp
    self.assertThat(fn_loader, Eventually(NotEquals(None)));
MismatchError: After 10.0 seconds test failed: None == None

ERROR: unity8.shell.tests.test_hud.TestHud.test_hide_hud_dragging(Native Device)
ERROR: unity8.shell.tests.test_hud.TestHud.test_hide_hud_click(Native Device)
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/unity8/shell/__init__.py", line 42, in wrapper
    return fn(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/unity8/shell/tests/test_hud.py", line 111, in test_hide_hud_dragging
    start_x, start_y = hud.get_close_button_coords()
  File "/usr/lib/python2.7/dist-packages/unity8/shell/emulators/hud.py", line 67, in get_close_button_coords
    y = rect[1] + get_grid_size()
TypeError: unsupported operand type(s) for +: 'dbus.Int32' and 'NoneType'

review: Needs Fixing
Revision history for this message
Michał Sawicz (saviq) wrote :

Looking at the videos from mediumtests, all Nexus4 scenarios would work if the above would work, but GRID_UNIT_PX isn't exported by default, hence, I think, the NoneType. It should default to 8.

None of the Nexus10 scenarios ever unlock the greeter, though.

review: Needs Fixing
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

LGTM

review: Approve
150. By Christopher Lee

Removed old unused code.

151. By Christopher Lee

pep8 compliance

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

14 +# Unity8 Autopilot Test Suite

Are we sure we want to have the 8 in there? I mean, at some point it'll be some greater version. The 8 right now is just to make it distinguishable from the current released Unity.

152. By Christopher Lee

Made launch_unity have a huge timeout for testing on infrastructure VMs (see lp bug: 1203715)

153. By Christopher Lee

Update indicator_client tests so it doesn't overwrite GRID_UNIT_PX

154. By Christopher Lee

Update i_c so it's not setting the grid_unit_px on the device.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
155. By Michał Sawicz

Skip slider due to bug #1203808 and add change skip reason for passphrase entry - bug #1203788

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
156. By Michał Sawicz

Use the helper to find indicators-client binary path.

157. By Michał Sawicz

Tweak the CMake autopilot module.

158. By Michał Sawicz

Run autopilot under C locale.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
159. By Michał Sawicz

Use ubuntu-mobile icon theme in autopilot targets.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
160. By Christopher Lee

First changes to check for dash/home scope loaded.

161. By Christopher Lee

Cleanup of new dash home scope checking

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
162. By Christopher Lee

Added extra logging to deal with VM CI

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
163. By Michał Sawicz

Some more logging and a cry-for-help timeout bump.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
164. By Michał Sawicz

Clean up debug logging.

165. By Michał Sawicz

Drop "8" from all the docstrings and copyright.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

160 +def get_grid_size():
161 + grid_size = os.getenv('GRID_UNIT_PX')
162 + if grid_size is None:
163 + raise RuntimeError(
164 + "Environment variable GRID_UNIT_PX has not been set."
165 + )
166 + return int(grid_size)

Grid units have a fallback of 8 so this isn't necessarily needed. OTOH, it might makes sense to have this check to make sure we're always testing with something we've set ourselves?

235 + super(TestDisplayMenus, self).setUp("400x800", self.grid_unit)

Humm... 400x800 and a variable grid unit size? that can have nasty side effects in certain circumstances, I'd assume.

451 + # TODO: Is this ever called? Find out, and maybe remove this branch:

This doesn't really make sense to me... Would make the whole emulator file useless...

496 + # check if it's availble before even attempting.

Typo... Also, is this TODO really needed? If someone calls this in a wrong situation the test will fail anyways and I guess the resulting error message is informative enough already.

519 + def dismiss(self):
520 + """Closes the open Hud."""
521 + # Ensure that the Hud is actually open
522 + self.shown.wait_for(True)
523 + touch = Touch.create()
524 + x, y = self.get_close_button_coords()
525 + touch.tap(x, y)

Would it make sense to wait for hidden too?

1402 + # TODO: perhaps move this to the Hud emulator?

Imho something that should either be done or not. But not worth a TODO that will never be fixed.

Not sure if all those are related to this branch, but there are some pyflakes issues.

indicators_client/emulators/__init__.py:12: 'sleep' imported but unused
indicators_client/emulators/__init__.py:14: 'IntrospectableObjectMetaclass' imported but unused
indicators_client/emulators/__init__.py:31: undefined name 'IndicatorsTestCase'
indicators_client/tests/__init__.py:14: 'Eventually' imported but unused
indicators_client/tests/__init__.py:16: 'Equals' imported but unused
indicators_client/tests/__init__.py:21: 'sys' imported but unused
indicators_client/tests/__init__.py:22: 'sleep' imported but unused
indicators_client/tests/test_battery.py:15: 'sleep' imported but unused
indicators_client/tests/test_battery.py:17: 'math' imported but unused

review: Needs Fixing (code)
Revision history for this message
Michał Sawicz (saviq) wrote :

W dniu 23.07.2013 12:20, Michael Zanetti pisze:
> Review: Needs Fixing code
>
> 160 +def get_grid_size():
> 161 + grid_size = os.getenv('GRID_UNIT_PX')
> 162 + if grid_size is None:
> 163 + raise RuntimeError(
> 164 + "Environment variable GRID_UNIT_PX has not been set."
> 165 + )
> 166 + return int(grid_size)
>
> Grid units have a fallback of 8 so this isn't necessarily needed. OTOH, it might makes sense to have this check to make sure we're always testing with something we've set ourselves?

Yeah, on the one hand we should make sure we're running at a certain GU,
on the other our tests should pass regardless of GU... I'm not sold on
either ;)

> 235 + super(TestDisplayMenus, self).setUp("400x800", self.grid_unit)
>
> Humm... 400x800 and a variable grid unit size? that can have nasty side effects in certain circumstances, I'd assume.

Fixed.

> 451 + # TODO: Is this ever called? Find out, and maybe remove this branch:
>
> This doesn't really make sense to me... Would make the whole emulator file useless...

Yeah, looks spurious.

> 496 + # check if it's availble before even attempting.
>
> Typo... Also, is this TODO really needed? If someone calls this in a wrong situation the test will fail anyways and I guess the resulting error message is informative enough already.

Dropped.

> 519 + def dismiss(self):
> 520 + """Closes the open Hud."""
> 521 + # Ensure that the Hud is actually open
> 522 + self.shown.wait_for(True)
> 523 + touch = Touch.create()
> 524 + x, y = self.get_close_button_coords()
> 525 + touch.tap(x, y)
>
> Would it make sense to wait for hidden too?

Done.

> 1402 + # TODO: perhaps move this to the Hud emulator?
>
> Imho something that should either be done or not. But not worth a TODO that will never be fixed.
>
> Not sure if all those are related to this branch, but there are some pyflakes issues.
>
> indicators_client/emulators/__init__.py:12: 'sleep' imported but unused
> indicators_client/emulators/__init__.py:14: 'IntrospectableObjectMetaclass' imported but unused
> indicators_client/emulators/__init__.py:31: undefined name 'IndicatorsTestCase'
> indicators_client/tests/__init__.py:14: 'Eventually' imported but unused
> indicators_client/tests/__init__.py:16: 'Equals' imported but unused
> indicators_client/tests/__init__.py:21: 'sys' imported but unused
> indicators_client/tests/__init__.py:22: 'sleep' imported but unused
> indicators_client/tests/test_battery.py:15: 'sleep' imported but unused
> indicators_client/tests/test_battery.py:17: 'math' imported but unused

We'll get to those in a second run.
--
Michał (Saviq) Sawicz <email address hidden>
Canonical Services Ltd.

166. By Michał Sawicz

Fix indicators_client geometry.

167. By Michał Sawicz

Clean spurious TODOs and move _get_hud_button_swipe_coords to the hud emulator.

168. By Michał Sawicz

Drop newline.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

lgtm now

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Dash/DashContent.qml'
2--- Dash/DashContent.qml 2013-07-19 16:22:50 +0000
3+++ Dash/DashContent.qml 2013-07-23 12:13:30 +0000
4@@ -115,6 +115,11 @@
5 asynchronous: true
6 source: scopeMapper.map(scope.id)
7
8+ // these are needed for autopilot tests
9+ readonly property string scopeId: scope.id
10+ readonly property bool isCurrent: ListView.isCurrentItem
11+ readonly property bool isLoaded: status == Loader.Ready
12+
13 onLoaded: {
14 item.scope = Qt.binding(function() { return scope })
15 item.isCurrent = Qt.binding(function() { return ListView.isCurrentItem })
16
17=== modified file 'cmake/modules/autopilot.cmake'
18--- cmake/modules/autopilot.cmake 2013-07-10 15:31:37 +0000
19+++ cmake/modules/autopilot.cmake 2013-07-23 12:13:30 +0000
20@@ -2,8 +2,9 @@
21
22 function(declare_autopilot_test TEST_NAME TEST_SUITE WORKING_DIR)
23 add_custom_target(autopilot-${TEST_NAME}
24- COMMAND autopilot run ${TEST_SUITE}
25+ COMMAND LANG=C UBUNTU_ICON_THEME=ubuntu-mobile QML2_IMPORT_PATH=${SHELL_PRIVATE_LIBDIR}/qml/mocks autopilot run ${TEST_SUITE}
26 WORKING_DIRECTORY ${WORKING_DIR}
27+ DEPENDS install
28 )
29
30 add_dependencies(autopilot autopilot-${TEST_NAME})
31
32=== modified file 'tests/autopilot/setup.py'
33--- tests/autopilot/setup.py 2013-06-28 08:18:52 +0000
34+++ tests/autopilot/setup.py 2013-07-23 12:13:30 +0000
35@@ -1,11 +1,22 @@
36 #!/usr/bin/python
37-
38 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
39-# Copyright 2013 Canonical
40-#
41-# This program is free software: you can redistribute it and/or modify it
42-# under the terms of the GNU General Public License version 3, as published
43-# by the Free Software Foundation.
44+#
45+# Unity Autopilot Test Suite
46+# Copyright (C) 2012-2013 Canonical
47+#
48+# This program is free software: you can redistribute it and/or modify
49+# it under the terms of the GNU General Public License as published by
50+# the Free Software Foundation, either version 3 of the License, or
51+# (at your option) any later version.
52+#
53+# This program is distributed in the hope that it will be useful,
54+# but WITHOUT ANY WARRANTY; without even the implied warranty of
55+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
56+# GNU General Public License for more details.
57+#
58+# You should have received a copy of the GNU General Public License
59+# along with this program. If not, see <http://www.gnu.org/licenses/>.
60+#
61
62
63 from distutils.core import setup
64@@ -14,7 +25,7 @@
65 setup(
66 name='unity',
67 version='8.0',
68- description='Unity 8 autopilot tests.',
69+ description='Unity autopilot tests.',
70 url='https://launchpad.net/unity',
71 license='GPLv3',
72 packages=find_packages(),
73
74=== modified file 'tests/autopilot/unity8/__init__.py'
75--- tests/autopilot/unity8/__init__.py 2013-07-10 22:42:35 +0000
76+++ tests/autopilot/unity8/__init__.py 2013-07-23 12:13:30 +0000
77@@ -1,8 +1,93 @@
78 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
79-# Copyright 2013 Canonical
80-#
81-# This program is free software: you can redistribute it and/or modify it
82-# under the terms of the GNU General Public License version 3, as published
83-# by the Free Software Foundation.
84-
85-"""unity8 autopilot tests and emulators - top level package."""
86+#
87+# Unity Autopilot Test Suite
88+# Copyright (C) 2012-2013 Canonical
89+#
90+# This program is free software: you can redistribute it and/or modify
91+# it under the terms of the GNU General Public License as published by
92+# the Free Software Foundation, either version 3 of the License, or
93+# (at your option) any later version.
94+#
95+# This program is distributed in the hope that it will be useful,
96+# but WITHOUT ANY WARRANTY; without even the implied warranty of
97+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98+# GNU General Public License for more details.
99+#
100+# You should have received a copy of the GNU General Public License
101+# along with this program. If not, see <http://www.gnu.org/licenses/>.
102+#
103+
104+"""unity autopilot tests and emulators - top level package."""
105+import os
106+import os.path
107+import subprocess
108+import sysconfig
109+
110+
111+def running_installed_tests():
112+ binary_path = get_binary_path()
113+ return binary_path.startswith('/usr')
114+
115+
116+def get_lib_path():
117+ """Return the library path to use in this test run."""
118+ if running_installed_tests():
119+ lib_path = os.path.join(
120+ "/usr/lib/",
121+ sysconfig.get_config_var('MULTIARCH'),
122+ "unity8"
123+ )
124+ else:
125+ binary_path = get_binary_path()
126+ lib_path = os.path.dirname(binary_path)
127+ return lib_path
128+
129+
130+def get_default_extra_mock_libraries():
131+ mocks_path = get_mocks_library_path()
132+ return os.path.join(mocks_path, 'libusermetrics')
133+
134+
135+def get_mocks_library_path():
136+ if running_installed_tests():
137+ mock_path = "qml/mocks/"
138+ else:
139+ mock_path = "../lib/x86_64-linux-gnu/unity8/qml/mocks/"
140+ lib_path = get_lib_path()
141+ ld_library_path = os.path.abspath(
142+ os.path.join(
143+ lib_path,
144+ mock_path,
145+ )
146+ )
147+
148+ if not os.path.exists(ld_library_path):
149+ raise RuntimeError(
150+ "Expected library path does not exists: %s." % (ld_library_path)
151+ )
152+ return ld_library_path
153+
154+
155+def get_binary_path(binary="unity8"):
156+ """Return the path to the specified binary."""
157+ binary_path = os.path.abspath(
158+ os.path.join(
159+ os.path.dirname(__file__),
160+ "../../../builddir/install/bin/%s" % binary
161+ )
162+ )
163+ if not os.path.exists(binary_path):
164+ try:
165+ binary_path = subprocess.check_output(['which', binary]).strip()
166+ except subprocess.CalledProcessError as e:
167+ raise RuntimeError("Unable to locate %s binary: %r" % (binary, e))
168+ return binary_path
169+
170+
171+def get_grid_size():
172+ grid_size = os.getenv('GRID_UNIT_PX')
173+ if grid_size is None:
174+ raise RuntimeError(
175+ "Environment variable GRID_UNIT_PX has not been set."
176+ )
177+ return int(grid_size)
178
179=== modified file 'tests/autopilot/unity8/indicators_client/__init__.py'
180--- tests/autopilot/unity8/indicators_client/__init__.py 2013-07-10 15:31:37 +0000
181+++ tests/autopilot/unity8/indicators_client/__init__.py 2013-07-23 12:13:30 +0000
182@@ -5,4 +5,4 @@
183 # under the terms of the GNU General Public License version 3, as published
184 # by the Free Software Foundation.
185
186-"""unity8 indicators-client autopilot tests and emulators - sub level package."""
187+"""unity indicators-client autopilot tests and emulators - sub level package."""
188
189=== modified file 'tests/autopilot/unity8/indicators_client/tests/__init__.py'
190--- tests/autopilot/unity8/indicators_client/tests/__init__.py 2013-07-10 15:31:37 +0000
191+++ tests/autopilot/unity8/indicators_client/tests/__init__.py 2013-07-23 12:13:30 +0000
192@@ -5,7 +5,7 @@
193 # under the terms of the GNU General Public License version 3, as published
194 # by the Free Software Foundation.
195
196-"""qml-phone-shell autopilot tests."""
197+"""indicators-client autopilot tests."""
198
199 import os.path
200
201@@ -15,6 +15,7 @@
202 from autopilot.platform import model
203 from testtools.matchers import Equals
204
205+from unity8 import get_binary_path
206 from unity8.indicators_client.emulators.main_window import MainWindow
207 from logging import getLogger
208 import sys
209@@ -29,9 +30,12 @@
210
211 """A common test case class that provides several useful methods for indicator tests."""
212
213+ geometry = None
214+ grid_unit = None
215+
216 if model() == 'Desktop':
217 scenarios = [
218- ('with mouse', dict(input_device_class=Mouse)),
219+ ('with mouse', dict(input_device_class=Mouse, geometry="400x800", grid_unit="12")),
220 ]
221 else:
222 scenarios = [
223@@ -41,11 +45,11 @@
224 def setUp(self, geometry, grid_size):
225 self.pointing_device = Pointer(self.input_device_class.create())
226 super(IndicatorsTestCase, self).setUp()
227- if grid_size != "0":
228- os.environ['GRID_UNIT_PX'] = grid_size
229+ if grid_size is not None:
230+ self.patch_environment("GRID_UNIT_PX", str(grid_size))
231 self.grid_size = int(grid_size)
232 else:
233- self.grid_size = int(os.environ['GRID_UNIT_PX'])
234+ self.grid_size = int(os.getenv('GRID_UNIT_PX'))
235
236 if os.path.realpath(__file__).startswith("/usr/"):
237 self.launch_test_installed(geometry)
238@@ -53,15 +57,15 @@
239 self.launch_test_local(geometry)
240
241 def launch_test_local(self, geometry):
242- if geometry != "0x0":
243- self.app = self.launch_test_application("../../builddir/src/Panel/Indicators/client/indicators-client",
244+ if geometry is None:
245+ self.app = self.launch_test_application(get_binary_path("indicators-client"),
246 "-geometry", geometry, app_type='qt')
247 else:
248- self.app = self.launch_test_application("../../builddir/src/Panel/Indicators/client/indicators-client",
249+ self.app = self.launch_test_application(get_binary_path("indicators-client"),
250 app_type='qt')
251
252 def launch_test_installed(self, geometry):
253- if geometry != "0x0":
254+ if geometry is not None:
255 self.app = self.launch_test_application("indicators-client", "-geometry", geometry, app_type='qt')
256 else:
257 self.app = self.launch_test_application("indicators-client", app_type='qt')
258
259=== modified file 'tests/autopilot/unity8/indicators_client/tests/test_battery.py'
260--- tests/autopilot/unity8/indicators_client/tests/test_battery.py 2013-07-10 15:31:37 +0000
261+++ tests/autopilot/unity8/indicators_client/tests/test_battery.py 2013-07-23 12:13:30 +0000
262@@ -8,6 +8,7 @@
263 """Add tests here if you want to ensure the behaviour of the power indicator menus are correct"""
264
265 from testtools.matchers import Equals, NotEquals
266+from autopilot.input import Touch
267 from autopilot.matchers import Eventually
268
269 from unity8.indicators_client.tests import IndicatorsTestCase
270@@ -17,7 +18,7 @@
271
272 class TestDisplayMenus(IndicatorsTestCase):
273 def setUp(self):
274- super(TestDisplayMenus, self).setUp("400x800", "12")
275+ super(TestDisplayMenus, self).setUp(self.geometry, self.grid_unit)
276
277 # This opens the messaging menu so you don't have to do that in
278 # every test case
279@@ -82,6 +83,8 @@
280 def test_brightness_slider(self):
281 """Test the auto-bright switch"""
282
283+ if self.input_device_class is Touch:
284+ self.skipTest("Dragging is broken with Touch input (LP: #1203808).")
285 fn_brightness_menu = lambda: self.app.select_single("SliderMenuItem", objectName="brightness");
286 self.assertThat(fn_brightness_menu, Eventually(NotEquals(None)));
287 brightness_menu = fn_brightness_menu();
288
289=== modified file 'tests/autopilot/unity8/shell/__init__.py'
290--- tests/autopilot/unity8/shell/__init__.py 2013-07-10 15:31:37 +0000
291+++ tests/autopilot/unity8/shell/__init__.py 2013-07-23 12:13:30 +0000
292@@ -1,8 +1,64 @@
293 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
294-# Copyright 2013 Canonical
295-#
296-# This program is free software: you can redistribute it and/or modify it
297-# under the terms of the GNU General Public License version 3, as published
298-# by the Free Software Foundation.
299-
300-"""unity8 shell autopilot tests and emulators - sub level package."""
301+#
302+# Unity Autopilot Test Suite
303+# Copyright (C) 2012-2013 Canonical
304+#
305+# This program is free software: you can redistribute it and/or modify
306+# it under the terms of the GNU General Public License as published by
307+# the Free Software Foundation, either version 3 of the License, or
308+# (at your option) any later version.
309+#
310+# This program is distributed in the hope that it will be useful,
311+# but WITHOUT ANY WARRANTY; without even the implied warranty of
312+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
313+# GNU General Public License for more details.
314+#
315+# You should have received a copy of the GNU General Public License
316+# along with this program. If not, see <http://www.gnu.org/licenses/>.
317+#
318+
319+"""unity shell autopilot tests and emulators - sub level package."""
320+
321+from functools import wraps
322+import logging
323+import os.path
324+
325+from unity8 import get_mocks_library_path, get_default_extra_mock_libraries
326+
327+
328+logger = logging.getLogger(__name__)
329+
330+
331+def with_lightdm_mock(mock_type):
332+ """A simple decorator that sets up the LightDM mock for a single test."""
333+ def with_lightdm_mock_internal(fn):
334+ @wraps(fn)
335+ def wrapper(*args, **kwargs):
336+ logger.info("Setting up LightDM mock type '%s'", mock_type)
337+ new_ld_library_path = "%s:%s" % (
338+ get_default_extra_mock_libraries(),
339+ _get_ld_library_path(mock_type)
340+ )
341+ logger.info("New library path: %s", new_ld_library_path)
342+ tests_self = args[0]
343+ tests_self.patch_environment(
344+ 'LD_LIBRARY_PATH',
345+ new_ld_library_path
346+ )
347+ return fn(*args, **kwargs)
348+ return wrapper
349+ return with_lightdm_mock_internal
350+
351+
352+def _get_ld_library_path(mock_type):
353+ lib_path = get_mocks_library_path()
354+ new_ld_library_path = os.path.abspath(
355+ os.path.join(lib_path, "LightDM", mock_type)
356+ )
357+
358+ if not os.path.exists(new_ld_library_path):
359+ raise RuntimeError(
360+ "LightDM mock '%s' does not exist at path '%s'."
361+ % (mock_type, new_ld_library_path)
362+ )
363+ return new_ld_library_path
364
365=== modified file 'tests/autopilot/unity8/shell/emulators/__init__.py'
366--- tests/autopilot/unity8/shell/emulators/__init__.py 2013-06-05 22:03:08 +0000
367+++ tests/autopilot/unity8/shell/emulators/__init__.py 2013-07-23 12:13:30 +0000
368@@ -1,6 +1,25 @@
369 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
370-# Copyright 2013 Canonical
371-#
372-# This program is free software: you can redistribute it and/or modify it
373-# under the terms of the GNU General Public License version 3, as published
374-# by the Free Software Foundation.
375+#
376+# Unity Autopilot Test Suite
377+# Copyright (C) 2012-2013 Canonical
378+#
379+# This program is free software: you can redistribute it and/or modify
380+# it under the terms of the GNU General Public License as published by
381+# the Free Software Foundation, either version 3 of the License, or
382+# (at your option) any later version.
383+#
384+# This program is distributed in the hope that it will be useful,
385+# but WITHOUT ANY WARRANTY; without even the implied warranty of
386+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
387+# GNU General Public License for more details.
388+#
389+# You should have received a copy of the GNU General Public License
390+# along with this program. If not, see <http://www.gnu.org/licenses/>.
391+#
392+
393+
394+from autopilot.introspection import CustomEmulatorBase
395+
396+
397+class UnityEmulatorBase(CustomEmulatorBase):
398+ """A base class for all unity emulators."""
399
400=== added file 'tests/autopilot/unity8/shell/emulators/dash.py'
401--- tests/autopilot/unity8/shell/emulators/dash.py 1970-01-01 00:00:00 +0000
402+++ tests/autopilot/unity8/shell/emulators/dash.py 2013-07-23 12:13:30 +0000
403@@ -0,0 +1,52 @@
404+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
405+#
406+# Unity Autopilot Test Suite
407+# Copyright (C) 2012-2013 Canonical
408+#
409+# This program is free software: you can redistribute it and/or modify
410+# it under the terms of the GNU General Public License as published by
411+# the Free Software Foundation, either version 3 of the License, or
412+# (at your option) any later version.
413+#
414+# This program is distributed in the hope that it will be useful,
415+# but WITHOUT ANY WARRANTY; without even the implied warranty of
416+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
417+# GNU General Public License for more details.
418+#
419+# You should have received a copy of the GNU General Public License
420+# along with this program. If not, see <http://www.gnu.org/licenses/>.
421+#
422+
423+from unity8.shell.emulators import UnityEmulatorBase
424+
425+
426+class Dash(UnityEmulatorBase):
427+
428+ """An emulator that understands the Dash."""
429+
430+ def get_home_applications_grid(self):
431+ return self.select_single(
432+ "ApplicationsFilterGrid",
433+ objectName="dashHomeApplicationsGrid"
434+ )
435+
436+ def get_application_icon(self, text):
437+ """Returns a 'Tile' icon that has the text 'text' from the application
438+ grid.
439+
440+ Will return None if the icon isn't found.
441+
442+ :param text: String containing the text of the icon to search for.
443+
444+ """
445+ app_grid = self.get_home_applications_grid()
446+ resp_grid = app_grid.select_single('ResponsiveGridView')
447+ return resp_grid.select_single('Tile', text=text)
448+
449+ def get_scope(self, scope_name='home'):
450+ dash_content = self.select_single(
451+ 'QQuickListView',
452+ objectName='dashContentList'
453+ )
454+ scope_id = "%s.scope" % scope_name
455+ return dash_content.select_single('QQuickLoader', scopeId=scope_id)
456
457=== added file 'tests/autopilot/unity8/shell/emulators/greeter.py'
458--- tests/autopilot/unity8/shell/emulators/greeter.py 1970-01-01 00:00:00 +0000
459+++ tests/autopilot/unity8/shell/emulators/greeter.py 2013-07-23 12:13:30 +0000
460@@ -0,0 +1,40 @@
461+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
462+#
463+# Unity Autopilot Test Suite
464+# Copyright (C) 2012-2013 Canonical
465+#
466+# This program is free software: you can redistribute it and/or modify
467+# it under the terms of the GNU General Public License as published by
468+# the Free Software Foundation, either version 3 of the License, or
469+# (at your option) any later version.
470+#
471+# This program is distributed in the hope that it will be useful,
472+# but WITHOUT ANY WARRANTY; without even the implied warranty of
473+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
474+# GNU General Public License for more details.
475+#
476+# You should have received a copy of the GNU General Public License
477+# along with this program. If not, see <http://www.gnu.org/licenses/>.
478+#
479+
480+from unity8.shell.emulators import UnityEmulatorBase
481+from autopilot.input import Touch
482+
483+
484+class Greeter(UnityEmulatorBase):
485+
486+ """An emulator that understands the greeter screen."""
487+
488+ def unlock(self):
489+ """Swipe the greeter screen away."""
490+ self.created.wait_for(True)
491+ touch = Touch.create()
492+
493+ rect = self.globalRect
494+ start_x = rect[0] + rect[2] - 3
495+ start_y = int(rect[1] + rect[3] / 2)
496+ stop_x = int(rect[0] + rect[2] * 0.2)
497+ stop_y = start_y
498+ touch.drag(start_x, start_y, stop_x, stop_y)
499+
500+ self.created.wait_for(False)
501
502=== added file 'tests/autopilot/unity8/shell/emulators/hud.py'
503--- tests/autopilot/unity8/shell/emulators/hud.py 1970-01-01 00:00:00 +0000
504+++ tests/autopilot/unity8/shell/emulators/hud.py 2013-07-23 12:13:30 +0000
505@@ -0,0 +1,83 @@
506+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
507+#
508+# Unity Autopilot Test Suite
509+# Copyright (C) 2012-2013 Canonical
510+#
511+# This program is free software: you can redistribute it and/or modify
512+# it under the terms of the GNU General Public License as published by
513+# the Free Software Foundation, either version 3 of the License, or
514+# (at your option) any later version.
515+#
516+# This program is distributed in the hope that it will be useful,
517+# but WITHOUT ANY WARRANTY; without even the implied warranty of
518+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
519+# GNU General Public License for more details.
520+#
521+# You should have received a copy of the GNU General Public License
522+# along with this program. If not, see <http://www.gnu.org/licenses/>.
523+#
524+
525+from collections import namedtuple
526+
527+from unity8 import get_grid_size
528+from unity8.shell.emulators import UnityEmulatorBase
529+from autopilot.input import Touch
530+
531+
532+SwipeCoords = namedtuple('SwipeCoords', 'start_x end_x start_y end_y')
533+
534+
535+class Hud(UnityEmulatorBase):
536+
537+ """An emulator that understands the Hud."""
538+
539+ def show(self):
540+ """Swipes open the Hud."""
541+ touch = Touch.create()
542+
543+ window = self.get_root_instance().select_single('QQuickView')
544+ hud_show_button = window.select_single("HudButton")
545+
546+ start_x = int(window.x + (window.width / 2))
547+ end_x = start_x
548+ start_y = window.y + window.height
549+ end_y = int(hud_show_button.y + (hud_show_button.height/2))
550+
551+ touch.press(start_x, start_y)
552+ touch._finger_move(end_x, end_y)
553+ try:
554+ hud_show_button.opacity.wait_for(1.0)
555+ touch.release()
556+ self.shown.wait_for(True)
557+ except AssertionError:
558+ raise
559+ finally:
560+ if touch._touch_finger is not None:
561+ touch.release()
562+
563+ def dismiss(self):
564+ """Closes the open Hud."""
565+ # Ensure that the Hud is actually open
566+ self.shown.wait_for(True)
567+ touch = Touch.create()
568+ x, y = self.get_close_button_coords()
569+ touch.tap(x, y)
570+ self.y.wait_for(self.height)
571+
572+ def get_close_button_coords(self):
573+ """Returns the coordinates of the Huds close button bar."""
574+ rect = self.globalRect
575+ x = int(rect[0] + rect[2] / 2)
576+ y = rect[1] + get_grid_size()
577+ return x, y
578+
579+ def get_button_swipe_coords(self, main_view, hud_show_button):
580+ """Returns the coords both start and end x,y for swiping to make the
581+ 'hud show' button appear.
582+ """
583+ start_x = int(main_view.x + (main_view.width / 2))
584+ end_x = start_x
585+ start_y = main_view.y + (main_view.height - 3)
586+ end_y = int(hud_show_button.y + (hud_show_button.height/2))
587+
588+ return SwipeCoords(start_x, end_x, start_y, end_y)
589
590=== added file 'tests/autopilot/unity8/shell/emulators/launcher.py'
591--- tests/autopilot/unity8/shell/emulators/launcher.py 1970-01-01 00:00:00 +0000
592+++ tests/autopilot/unity8/shell/emulators/launcher.py 2013-07-23 12:13:30 +0000
593@@ -0,0 +1,38 @@
594+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
595+#
596+# Unity Autopilot Test Suite
597+# Copyright (C) 2012-2013 Canonical
598+#
599+# This program is free software: you can redistribute it and/or modify
600+# it under the terms of the GNU General Public License as published by
601+# the Free Software Foundation, either version 3 of the License, or
602+# (at your option) any later version.
603+#
604+# This program is distributed in the hope that it will be useful,
605+# but WITHOUT ANY WARRANTY; without even the implied warranty of
606+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
607+# GNU General Public License for more details.
608+#
609+# You should have received a copy of the GNU General Public License
610+# along with this program. If not, see <http://www.gnu.org/licenses/>.
611+#
612+
613+from unity8.shell.emulators import UnityEmulatorBase
614+from autopilot.input import Touch
615+
616+
617+class Launcher(UnityEmulatorBase):
618+
619+ """An emulator that understands the Launcher."""
620+
621+ def show(self):
622+ """Swipes open the launcher."""
623+ touch = Touch.create()
624+
625+ view = self.get_root_instance().select_single('QQuickView')
626+ start_x = view.x + 1
627+ start_y = view.y + view.height / 2
628+ stop_x = start_x + self.panelWidth + 1
629+ stop_y = start_y
630+ touch.drag(start_x, start_y, stop_x, stop_y)
631+ self.shown.wait_for(True)
632
633=== modified file 'tests/autopilot/unity8/shell/emulators/main_window.py'
634--- tests/autopilot/unity8/shell/emulators/main_window.py 2013-06-11 15:45:45 +0000
635+++ tests/autopilot/unity8/shell/emulators/main_window.py 2013-07-23 12:13:30 +0000
636@@ -1,9 +1,28 @@
637 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
638-# Copyright 2013 Canonical
639-#
640-# This program is free software: you can redistribute it and/or modify it
641-# under the terms of the GNU General Public License version 3, as published
642-# by the Free Software Foundation.
643+#
644+# Unity Autopilot Test Suite
645+# Copyright (C) 2012-2013 Canonical
646+#
647+# This program is free software: you can redistribute it and/or modify
648+# it under the terms of the GNU General Public License as published by
649+# the Free Software Foundation, either version 3 of the License, or
650+# (at your option) any later version.
651+#
652+# This program is distributed in the hope that it will be useful,
653+# but WITHOUT ANY WARRANTY; without even the implied warranty of
654+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
655+# GNU General Public License for more details.
656+#
657+# You should have received a copy of the GNU General Public License
658+# along with this program. If not, see <http://www.gnu.org/licenses/>.
659+#
660+
661+
662+from unity8.shell.emulators.greeter import Greeter
663+from unity8.shell.emulators.hud import Hud
664+from unity8.shell.emulators.dash import Dash
665+from unity8.shell.emulators.launcher import Launcher
666+
667
668 class MainWindow(object):
669 """An emulator class that makes it easy to interact with the shell"""
670@@ -16,10 +35,13 @@
671 return self.app.select_single("QQuickView")
672
673 def get_greeter(self):
674- return self.app.select_single("Greeter")
675+ return self.app.select_single(Greeter)
676
677 def get_greeter_content_loader(self):
678- return self.app.select_single("QQuickLoader", objectName="greeterContentLoader")
679+ return self.app.select_single(
680+ "QQuickLoader",
681+ objectName="greeterContentLoader"
682+ )
683
684 def get_login_loader(self):
685 return self.app.select_single("QQuickLoader", objectName="loginLoader")
686@@ -28,7 +50,7 @@
687 return self.app.select_single("LoginList")
688
689 def get_hud(self):
690- return self.app.select_single("Hud")
691+ return self.app.select_single(Hud)
692
693 def get_hud_showable(self):
694 return self.app.select_single("Showable", objectName="hudShowable")
695@@ -37,22 +59,31 @@
696 return self.app.select_single("HudButton")
697
698 def get_dash(self):
699- return self.app.select_single("Dash")
700+ return self.app.select_single(Dash)
701
702 def get_dash_home_applications_grid(self):
703- return self.app.select_single("ApplicationsFilterGrid", objectName="dashHomeApplicationsGrid")
704+ return self.app.select_single(
705+ "ApplicationsFilterGrid",
706+ objectName="dashHomeApplicationsGrid"
707+ )
708
709 def get_bottombar(self):
710 return self.app.select_single("Bottombar")
711
712 def get_launcher(self):
713- return self.app.select_single("Launcher")
714+ return self.app.select_single(Launcher)
715
716 def get_pinPadLoader(self):
717- return self.app.select_single("QQuickLoader", objectName="pinPadLoader")
718+ return self.app.select_single(
719+ "QQuickLoader",
720+ objectName="pinPadLoader"
721+ )
722
723 def get_pinPadButton(self, buttonId):
724- return self.app.select_single("PinPadButton", objectName="pinPadButton%i" % buttonId)
725+ return self.app.select_single(
726+ "PinPadButton",
727+ objectName="pinPadButton%i" % buttonId
728+ )
729
730 def get_lockscreen(self):
731 return self.app.select_single("Lockscreen")
732
733=== modified file 'tests/autopilot/unity8/shell/tests/__init__.py'
734--- tests/autopilot/unity8/shell/tests/__init__.py 2013-07-10 15:31:37 +0000
735+++ tests/autopilot/unity8/shell/tests/__init__.py 2013-07-23 12:13:30 +0000
736@@ -1,81 +1,187 @@
737 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
738-# Copyright 2013 Canonical
739-#
740-# This program is free software: you can redistribute it and/or modify it
741-# under the terms of the GNU General Public License version 3, as published
742-# by the Free Software Foundation.
743-
744-"""unity8 autopilot tests."""
745-
746-import os.path
747-import sysconfig
748-
749+#
750+# Unity Autopilot Test Suite
751+# Copyright (C) 2012-2013 Canonical
752+#
753+# This program is free software: you can redistribute it and/or modify
754+# it under the terms of the GNU General Public License as published by
755+# the Free Software Foundation, either version 3 of the License, or
756+# (at your option) any later version.
757+#
758+# This program is distributed in the hope that it will be useful,
759+# but WITHOUT ANY WARRANTY; without even the implied warranty of
760+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
761+# GNU General Public License for more details.
762+#
763+# You should have received a copy of the GNU General Public License
764+# along with this program. If not, see <http://www.gnu.org/licenses/>.
765+#
766+
767+"""unity autopilot tests."""
768+
769+from autopilot.platform import model
770 from autopilot.testcase import AutopilotTestCase
771 from autopilot.matchers import Eventually
772-from autopilot.platform import model
773-from testtools.matchers import Equals
774+from autopilot.input import Touch
775+from autopilot.display import Display
776+import logging
777+import os.path
778+from testtools.matchers import Equals, NotEquals
779
780+from unity8 import get_lib_path, get_binary_path, get_mocks_library_path
781+from unity8.shell.emulators import UnityEmulatorBase
782+from unity8.shell.emulators.dash import Dash
783 from unity8.shell.emulators.main_window import MainWindow
784
785-class FormFactors(object):
786- Phone, Tablet, Desktop = range(3)
787-
788-class ShellTestCase(AutopilotTestCase):
789-
790- """A common test case class that provides several useful methods for shell tests."""
791-
792- libdir = "/usr/lib/{0}/unity8".format(sysconfig.get_config_var('MULTIARCH'))
793- lightdm_mock = "full"
794-
795- def setUp(self, geometry, grid_size):
796- super(ShellTestCase, self).setUp()
797- # Lets assume we are installed system wide if this file is somewhere in /usr
798- if grid_size != "0":
799- os.environ['GRID_UNIT_PX'] = grid_size
800- self.grid_size = int(grid_size)
801- else:
802- self.grid_size = int(os.environ['GRID_UNIT_PX'])
803- if os.path.realpath(__file__).startswith("/usr/"):
804- self.launch_test_installed(geometry)
805- else:
806- self.launch_test_local(geometry)
807-
808- def launch_test_local(self, geometry):
809- os.environ['LD_LIBRARY_PATH'] = "../../builddir/tests/mocks/libusermetrics:../../builddir/tests/mocks/LightDM" + self.lightdm_mock
810- os.environ['QML2_IMPORT_PATH'] = "../../builddir/tests/mocks"
811- if geometry != "0x0":
812- self.app = self.launch_test_application(
813- "../../builddir/unity8", "-geometry", geometry, "-frameless", app_type='qt')
814- else:
815- self.app = self.launch_test_application(
816- "../../builddir/unity8", "-fullscreen", app_type='qt')
817-
818- def launch_test_installed(self, geometry):
819- os.environ['LD_LIBRARY_PATH'] = "{0}/qml/mocks/libusermetrics:{0}/qml/mocks/LightDM/{1}".format(self.libdir, self.lightdm_mock)
820- os.environ['QML2_IMPORT_PATH'] = "{0}/qml/mocks".format(self.libdir)
821- if model() == 'Desktop' and geometry != "0x0":
822- self.app = self.launch_test_application(
823- "unity8", "-geometry", geometry, "-frameless", app_type='qt')
824- else:
825- self.app = self.launch_test_application(
826- "unity8", "-fullscreen", app_type='qt')
827-
828- def skipWrapper(*args, **kwargs):
829- pass
830-
831- def form_factor(self):
832- return FormFactors.Desktop
833-
834- def __getattribute__(self, attr_name):
835- attr = object.__getattribute__(self, attr_name);
836- if attr_name.startswith("test_"):
837- try:
838- if self.form_factor() in attr.blacklist:
839- return self.skipWrapper
840- except:
841- pass
842- return attr
843+
844+logger = logging.getLogger(__name__)
845+
846+
847+def _get_device_emulation_scenarios():
848+ if model() == 'Desktop':
849+ return [
850+ (
851+ 'Desktop Nexus 4',
852+ dict(app_width=768, app_height=1280, grid_unit_px=18)
853+ ),
854+ (
855+ 'Desktop Nexus 10',
856+ dict(app_width=2560, app_height=1600, grid_unit_px=20)
857+ ),
858+ ]
859+ else:
860+ return [
861+ (
862+ 'Native Device',
863+ dict(app_width=0, app_height=0, grid_unit_px=0)
864+ )
865+ ]
866+
867+
868+class UnityTestCase(AutopilotTestCase):
869+
870+ """A test case base class for the Unity shell tests."""
871+
872+ def setUp(self):
873+ super(UnityTestCase, self).setUp()
874+ self._proxy = None
875+ self.touch = Touch.create()
876+ self._setup_display_details()
877+
878+ def _setup_display_details(self):
879+ scale_divisor = self._determine_geometry()
880+ self._setup_grid_size(scale_divisor)
881+
882+ def _determine_geometry(self):
883+ """Use the geometry that may be supplied or use the default."""
884+ width = getattr(self, 'app_width', 0)
885+ height = getattr(self, 'app_height', 0)
886+ scale_divisor = 1
887+ if width == 0 and width == 0:
888+ self.unity_geometry_args = ['-fullscreen']
889+ else:
890+ if self._geo_larger_than_display(width, height):
891+ scale_divisor = self._get_scaled_down_geo(width, height)
892+ width = width / scale_divisor
893+ height = height / scale_divisor
894+ logger.info(
895+ "Geometry larger than display, scaled down to: %dx%d",
896+ width,
897+ height
898+ )
899+ geo_string = "%dx%d" % (width, height)
900+ self.unity_geometry_args = [
901+ '-geometry',
902+ geo_string,
903+ '-frameless',
904+ '-mousetouch'
905+ ]
906+ return scale_divisor
907+
908+ def _setup_grid_size(self, scale_divisor):
909+ """Use the grid size that may be supplied or use the default."""
910+ if getattr(self, 'grid_unit_px', 0) == 0:
911+ self.grid_size = int(os.getenv('GRID_UNIT_PX'))
912+ else:
913+ self.grid_size = int(self.grid_unit_px / scale_divisor)
914+ self.patch_environment("GRID_UNIT_PX", str(self.grid_size))
915+
916+ def _geo_larger_than_display(self, width, height):
917+ should_scale = getattr(self, 'scale_geo', True)
918+ if should_scale:
919+ screen = Display.create()
920+ screen_width = screen.get_screen_width()
921+ screen_height = screen.get_screen_height()
922+ return (width > screen_width) or (height > screen_height)
923+ else:
924+ return False
925+
926+ def _get_scaled_down_geo(self, width, height):
927+ divisor = 1
928+ while self._geo_larger_than_display(width / divisor, height / divisor):
929+ divisor = divisor * 2
930+ return divisor
931+
932+ def launch_unity(self):
933+ """Launch the unity shell, return a proxy object for it."""
934+ binary_path = get_binary_path()
935+ lib_path = get_lib_path()
936+
937+ logger.info(
938+ "Lib path is '%s', binary path is '%s'",
939+ lib_path,
940+ binary_path
941+ )
942+
943+ self._setup_extra_mock_environment_patch()
944+
945+ app_proxy = self.launch_test_application(
946+ binary_path,
947+ *self.unity_geometry_args,
948+ app_type='qt',
949+ emulator_base=UnityEmulatorBase
950+ )
951+ self._set_proxy(app_proxy)
952+
953+ # Ensure that the dash is visible before we return:
954+ logger.debug("Unity started, waiting for it to be ready.")
955+ self.assertUnityReady()
956+ logger.debug("Unity loaded and ready.")
957+
958+ return app_proxy
959+
960+ def _setup_extra_mock_environment_patch(self):
961+ mocks_library_path = get_mocks_library_path()
962+ self.patch_environment('QML2_IMPORT_PATH', mocks_library_path)
963+
964+ def _set_proxy(self, proxy):
965+ """Keep a copy of the proxy object, so we can use it to get common
966+ parts of the shell later on.
967+
968+ """
969+ self._proxy = proxy
970+ self.addCleanup(self._clear_proxy)
971+
972+ def _clear_proxy(self):
973+ self._proxy = None
974+
975+ def assertUnityReady(self):
976+ dash = self.get_dash()
977+ home_scope = dash.get_scope('home')
978+
979+ # FIXME! There is a huge timeout here for when we're doing CI on
980+ # VMs. See lp:1203715
981+ self.assertThat(
982+ home_scope.isLoaded,
983+ Eventually(Equals(True), timeout=60)
984+ )
985+ self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
986+
987+ def get_dash(self):
988+ dash = self._proxy.select_single(Dash)
989+ self.assertThat(dash, NotEquals(None))
990+ return dash
991
992 @property
993 def main_window(self):
994- return MainWindow(self.app)
995+ return MainWindow(self._proxy)
996
997=== removed file 'tests/autopilot/unity8/shell/tests/helpers.py'
998--- tests/autopilot/unity8/shell/tests/helpers.py 2013-06-20 15:24:23 +0000
999+++ tests/autopilot/unity8/shell/tests/helpers.py 1970-01-01 00:00:00 +0000
1000@@ -1,161 +0,0 @@
1001-# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1002-# Copyright 2013 Canonical
1003-#
1004-# This program is free software: you can redistribute it and/or modify it
1005-# under the terms of the GNU General Public License version 3, as published
1006-# by the Free Software Foundation.
1007-
1008-from testtools.matchers import Equals, NotEquals
1009-from autopilot.matchers import Eventually
1010-
1011-import logging
1012-
1013-logger = logging.getLogger(__name__)
1014-
1015-class TestShellHelpers(object):
1016- """Helpers for testing the Shell"""
1017-
1018- def select_greeter_user(self, username):
1019- greeter = self.main_window.get_greeter()
1020- self.assertThat(greeter.created, Eventually(Equals(True)))
1021- self.assertThat(greeter.multiUser, Eventually(Equals(True)))
1022-
1023- login_loader = self.main_window.get_login_loader()
1024- self.assertThat(login_loader.progress, Eventually(Equals(1)))
1025-
1026- login_list = self.main_window.get_login_list()
1027- list_view = login_list.get_children_by_type("QQuickListView")[0]
1028-
1029- try_count = 0
1030- max_tries = 50 # just in case we go off rails
1031- while try_count < max_tries:
1032- users = list_view.get_children_by_type("QQuickItem")[0].get_children_by_type("QQuickItem")
1033- target_user = None
1034- for user in users:
1035- try:
1036- user_label = user.get_children_by_type("Label")[0]
1037- if user.opacity < 0.1:
1038- continue # off-screen item
1039- if user_label.text == username:
1040- target_user = user
1041- break
1042- elif target_user is None or user.y > target_user.y:
1043- target_user = user
1044- except Exception:
1045- pass
1046- if target_user is None:
1047- break
1048- user_label = target_user.get_children_by_type("Label")[0]
1049- self.touch.tap_object(user_label)
1050- self.assertThat(list_view.movingInternally, Eventually(Equals(False)))
1051- if user_label.text == username:
1052- return login_list.get_children_by_type("TextField")[0]
1053- try_count = try_count + 1
1054- self.fail() # We didn't find it
1055-
1056- def unlock_greeter(self, retries=2):
1057- greeter = self.main_window.get_greeter()
1058- self.assertThat(greeter.created, Eventually(Equals(True)))
1059-
1060- if greeter.multiUser:
1061- password_field = self.select_greeter_user("No Password")
1062- self.assertThat(password_field.opacity, Eventually(Equals(1)))
1063- self.touch.tap_object(password_field)
1064-
1065- else:
1066- rect = greeter.globalRect
1067- start_x = rect[0] + rect[2] - 3
1068- start_y = int(rect[1] + rect[3] / 2)
1069- stop_x = int(rect[0] + rect[2] * 0.2)
1070- stop_y = start_y
1071- self.touch.drag(start_x, start_y, stop_x, stop_y)
1072-
1073- # Because the shell loads up lots of stuff, unlocking the greeter can
1074- # be a bit stuttery while scopes are still consuming all resources.
1075- # Give it another (max retries) chance
1076- try:
1077- self.assertThat(greeter.created, Eventually(Equals(False)))
1078- except:
1079- if retries > 0:
1080- logger.warning("Failed to unlock greeter. Retrying...")
1081- self.unlock_greeter(retries-1)
1082- else:
1083- logger.warning("Failed to unlock greeter. Giving up. Tests may fail...")
1084-
1085-
1086- def open_first_dash_home_app(self, retries=2):
1087- self.assertThat(lambda: self.main_window.get_dash_home_applications_grid(), Eventually(NotEquals(None)))
1088- app_grid = self.main_window.get_dash_home_applications_grid()
1089- # Wait for the grids to be expanded
1090- self.assertThat(app_grid.get_children()[0].totalContentHeight, Eventually(NotEquals(0)))
1091- self.assertThat(app_grid.get_children()[0].height, Eventually(Equals(app_grid.get_children()[0].totalContentHeight)))
1092- first_app = app_grid.get_children()[0].get_children()[0].get_children()[0].get_children()[0]
1093- self.touch.tap_object(first_app)
1094- bottombar = self.main_window.get_bottombar()
1095-
1096- # if we have huge amounts of pixels (e.g. Nexus10), but slow video (e.g. VM) it might take a little
1097- # until the dash is fully rendered after sliding away the greeter/lockscreen and the click might
1098- # go to the void for the first time because there's no real way to know what the display has
1099- # painted already. Give it another (max retries) chance.
1100- try:
1101- self.assertThat(lambda: getattr(bottombar, "applicationIsOnForeground"),
1102- Eventually(Equals(True)))
1103- except:
1104- if retries > 0:
1105- logger.warning("Failed to launch app. Retrying...")
1106- self.open_first_dash_home_app(retries-1)
1107- else:
1108- logger.warning("Failed to launch app. Giving up. Tests may fail...")
1109-
1110-
1111- def show_hud(self, retries=2):
1112- self.open_first_dash_home_app()
1113-
1114- hud_show_button = self.main_window.get_hud_show_button()
1115- hud = self.main_window.get_hud()
1116- window = self.main_window.get_qml_view()
1117- start_x = int(window.x + window.width / 2)
1118- start_y = window.y + window.height - 3
1119- self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
1120- self.touch.press(start_x, start_y)
1121- self.touch._finger_move(start_x, start_y - self.grid_size)
1122- self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
1123- self.touch._finger_move(start_x, start_y - self.grid_size * 2)
1124- self.touch._finger_move(start_x, start_y - self.grid_size * 3)
1125- self.touch._finger_move(start_x, start_y - self.grid_size * 4)
1126- try:
1127- self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
1128- except:
1129- if retries > 0:
1130- logger.warning("Failed to get hud button to show. Retrying...")
1131- self.touch.release()
1132- self.show_hud(retries-1)
1133- return
1134- else:
1135- logger.warning("Failed to get hud button to show. Giving up. Tests may fail...")
1136- self.assertThat(hud_show_button.mouseOver, Eventually(Equals(False)))
1137- self.touch._finger_move(start_x, start_y - self.grid_size * 34)
1138- self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
1139- self.assertThat(hud_show_button.mouseOver, Eventually(Equals(True)))
1140- self.touch.release()
1141- self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
1142- self.assertThat(hud.shown, Eventually(Equals(True)))
1143-
1144- def close_hud_click(self):
1145- hud = self.main_window.get_hud()
1146- self.assertThat(hud.shown, Eventually(Equals(True)))
1147- rect = hud.globalRect
1148- x = int(rect[0] + rect[2] / 2)
1149- y = rect[1] + self.grid_size
1150- self.touch.tap(x, y)
1151- self.assertThat(hud.shown, Eventually(Equals(False)))
1152-
1153- def show_launcher(self):
1154- launcher = self.main_window.get_launcher()
1155- view = self.main_window.get_qml_view()
1156- start_x = view.x + 1
1157- start_y = view.y + view.height / 2
1158- stop_x = start_x + launcher.panelWidth + 1
1159- stop_y = start_y
1160- self.touch.drag(start_x, start_y, stop_x, stop_y)
1161- self.assertThat(launcher.shown, Eventually(Equals(True)))
1162
1163=== renamed file 'tests/autopilot/unity8/shell/tests/testhud.py' => 'tests/autopilot/unity8/shell/tests/test_hud.py'
1164--- tests/autopilot/unity8/shell/tests/testhud.py 2013-07-10 15:31:37 +0000
1165+++ tests/autopilot/unity8/shell/tests/test_hud.py 2013-07-23 12:13:30 +0000
1166@@ -1,145 +1,156 @@
1167 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1168-# Copyright 2013 Canonical
1169-#
1170-# This program is free software: you can redistribute it and/or modify it
1171-# under the terms of the GNU General Public License version 3, as published
1172-# by the Free Software Foundation.
1173-
1174-
1175-# This file contains general purpose test cases for Unity.
1176-# Each test written in this file will be executed for a variety of
1177-# configurations, such as Phone, Tablet or Desktop form factors.
1178-#
1179-# Sometimes there is the need to disable a certain test for a particular
1180-# configuration. To do so, add this in a new line directly below your test:
1181-#
1182-# test_testname.blacklist = (FormFactors.Tablet, FormFactors.Desktop,)
1183-#
1184-# Available form factors are:
1185-# FormFactors.Phone
1186-# FormFactors.Tablet
1187-# FormFactors.Desktop
1188-
1189-
1190-"""Tests for the Shell"""
1191+#
1192+# Unity Autopilot Test Suite
1193+# Copyright (C) 2012-2013 Canonical
1194+#
1195+# This program is free software: you can redistribute it and/or modify
1196+# it under the terms of the GNU General Public License as published by
1197+# the Free Software Foundation, either version 3 of the License, or
1198+# (at your option) any later version.
1199+#
1200+# This program is distributed in the hope that it will be useful,
1201+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1202+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1203+# GNU General Public License for more details.
1204+#
1205+# You should have received a copy of the GNU General Public License
1206+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1207+#
1208
1209 from __future__ import absolute_import
1210
1211-from unity8.shell.tests import ShellTestCase, FormFactors
1212-from unity8.shell.tests.helpers import TestShellHelpers
1213+from unity8.shell import with_lightdm_mock
1214+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
1215
1216-from autopilot.input import Mouse, Touch, Pointer
1217-from testtools.matchers import Equals, NotEquals, GreaterThan, MismatchError
1218+from testtools.matchers import Equals
1219 from autopilot.matchers import Eventually
1220-from autopilot.display import Display
1221-from autopilot.platform import model
1222-
1223-import unittest
1224-import time
1225-import os
1226-from os import path
1227-
1228-
1229-class TestHud(ShellTestCase, TestShellHelpers):
1230-
1231- """Tests the Shell"""
1232-
1233- # Scenarios:
1234- # Fill in the scenarios to run the whole test suite with multiple configurations.
1235- # Use app_width, app_height and grid_unit_px to set the apps geometry.
1236- # Set app_width and app_height to 0 to use fullscreen.
1237- # Set grid_unit_px to 0 to use the current system environment.
1238-
1239- if model() == 'Desktop':
1240- scenarios = [
1241- ('Nexus 4', dict(app_width=768, app_height=1280, grid_unit_px=18, lightdm_mock="single")),
1242- ('Nexus 10', dict(app_width=2560, app_height=1600, grid_unit_px=20, lightdm_mock="full")),
1243-# TODO: don't run fullscreen tests just yet as the VM is performing too badly for that. Enable this once
1244-# Autopilot tests are running on bear metal.
1245-# ('Fullscreen', dict(app_width=0, app_height=0, grid_unit_px=10, lightdm_mock="full")),
1246- ]
1247- else:
1248- scenarios = [
1249- ('Fullscreen', dict(app_width=0, app_height=0, grid_unit_px=0, lightdm_mock="single")),
1250- ]
1251-
1252- def setUp(self):
1253- self.touch = Touch.create()
1254-
1255- sg = Display().create()
1256- divisor = 1
1257- while (sg.get_screen_width() < self.app_width / divisor or sg.get_screen_height() < self.app_height / divisor):
1258- divisor = divisor * 2
1259- super(TestHud, self).setUp("%sx%s" % (self.app_width / divisor, self.app_height / divisor), "%s" % (self.grid_unit_px / divisor))
1260-
1261- dash = self.main_window.get_dash()
1262- self.assertThat(dash.showScopeOnLoaded, Eventually(Equals(""), timeout=30))
1263-
1264- def test_show_hud(self):
1265- hud = self.main_window.get_hud()
1266- self.unlock_greeter()
1267- self.show_hud()
1268+
1269+
1270+class TestHud(UnityTestCase):
1271+
1272+ """Tests the Shell HUD."""
1273+
1274+ scenarios = _get_device_emulation_scenarios()
1275+
1276+ @with_lightdm_mock("single")
1277+ def test_show_hud_button_appears(self):
1278+ """Swiping up while an app is active must show the 'show hud' button.
1279+
1280+ """
1281+ self.launch_unity()
1282+ self.main_window.get_greeter().unlock()
1283+ window = self.main_window.get_qml_view()
1284+ hud_show_button = self.main_window.get_hud_show_button()
1285+ hud = self.main_window.get_hud()
1286+
1287+ self._launch_test_app_from_app_screen()
1288+
1289+ swipe_coords = hud.get_button_swipe_coords(
1290+ window,
1291+ hud_show_button
1292+ )
1293+ self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
1294+ self.addCleanup(self.touch.release)
1295+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
1296+ self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
1297+
1298+ @with_lightdm_mock("single")
1299+ def test_show_hud_appears(self):
1300+ """Releasing the touch on the 'show hud' button must display the hud.
1301+
1302+ """
1303+ self.launch_unity()
1304+ self.main_window.get_greeter().unlock()
1305+ window = self.main_window.get_qml_view()
1306+ hud_show_button = self.main_window.get_hud_show_button()
1307+ hud = self.main_window.get_hud()
1308+
1309+ self._launch_test_app_from_app_screen()
1310+
1311+ swipe_coords = hud.get_button_swipe_coords(
1312+ window,
1313+ hud_show_button
1314+ )
1315+ self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
1316+ self.addCleanup(self._maybe_release_finger)
1317+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
1318+
1319+ self.assertThat(hud.shown, Eventually(Equals(False)))
1320+ self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
1321+ self.touch.release()
1322 self.assertThat(hud.shown, Eventually(Equals(True)))
1323
1324- def test_show_hud_button_dont_open(self):
1325- self.unlock_greeter()
1326- self.open_first_dash_home_app()
1327- hud_show_button = self.main_window.get_hud_show_button()
1328- hud = self.main_window.get_hud()
1329- window = self.main_window.get_qml_view()
1330- start_x = int(window.x + window.width / 2)
1331- start_y = window.y + window.height - 2
1332- self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
1333- self.touch.press(start_x, start_y)
1334- self.touch._finger_move(start_x, start_y - self.grid_size)
1335- self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
1336- self.touch._finger_move(start_x, start_y - self.grid_size * 2)
1337- self.touch._finger_move(start_x, start_y - self.grid_size * 3)
1338- self.touch._finger_move(start_x, start_y - self.grid_size * 4)
1339- self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
1340- self.assertThat(hud_show_button.mouseOver, Eventually(Equals(False)))
1341- self.touch._finger_move(start_x, start_y - self.grid_size * 34)
1342- self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
1343- self.assertThat(hud_show_button.mouseOver, Eventually(Equals(True)))
1344- self.touch._finger_move(start_x, start_y - self.grid_size)
1345- self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
1346- self.assertThat(hud_show_button.mouseOver, Eventually(Equals(False)))
1347- self.touch.release()
1348- self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
1349- self.assertThat(hud.shown, Eventually(Equals(False)))
1350-
1351+ @with_lightdm_mock("single")
1352 def test_hide_hud_click(self):
1353- hud = self.main_window.get_hud()
1354- self.unlock_greeter()
1355- self.show_hud()
1356- self.close_hud_click()
1357- self.assertThat(hud.shown, Eventually(Equals(False)))
1358-
1359- def test_hide_hud_click_outside_handle(self):
1360- hud = self.main_window.get_hud()
1361- self.unlock_greeter()
1362- self.show_hud()
1363- rect = hud.globalRect
1364- x = int(rect[0] + rect[2] / 2)
1365- y = rect[1] + hud.handleHeight + 1
1366+ """Tapping the close button of the Hud must dismiss it."""
1367+ self.launch_unity()
1368+ self.main_window.get_greeter().unlock()
1369+ hud = self.main_window.get_hud()
1370+
1371+ self._launch_test_app_from_app_screen()
1372+ hud.show()
1373+
1374+ x, y = hud.get_close_button_coords()
1375 self.touch.tap(x, y)
1376- self.assertRaises(MismatchError, lambda: self.assertThat(hud.shown, Eventually(Equals(False), timeout=3)))
1377+ self.assertThat(hud.shown, Eventually(Equals(False)))
1378
1379+ @with_lightdm_mock("single")
1380 def test_hide_hud_dragging(self):
1381- hud = self.main_window.get_hud()
1382- self.unlock_greeter()
1383- self.show_hud()
1384- rect = hud.globalRect
1385- start_x = rect[0] + (rect[2] - rect[0]) / 2
1386- start_y = rect[1] + 1
1387- stop_x = start_x
1388- stop_y = start_y + (rect[3] - rect[1]) / 2
1389- self.touch.drag(start_x, start_y, stop_x, stop_y)
1390- self.assertThat(hud.shown, Eventually(Equals(False)))
1391-
1392- def test_hide_hud_launcher(self):
1393- hud = self.main_window.get_hud()
1394- self.unlock_greeter()
1395- self.show_hud()
1396- self.show_launcher()
1397- self.assertThat(hud.shown, Eventually(Equals(False)))
1398+ """Once open the Hud must close if the upper bar is dragged and
1399+ released downward.
1400+
1401+ """
1402+ self.launch_unity()
1403+ self.main_window.get_greeter().unlock()
1404+ hud = self.main_window.get_hud()
1405+ window = self.main_window.get_qml_view()
1406+
1407+ self._launch_test_app_from_app_screen()
1408+ hud.show()
1409+
1410+ start_x, start_y = hud.get_close_button_coords()
1411+ end_x = start_x
1412+ end_y = int(window.height / 2)
1413+
1414+ self.touch.drag(start_x, start_y, end_x, end_y)
1415+ self.assertThat(hud.shown, Eventually(Equals(False)))
1416+
1417+ @with_lightdm_mock("single")
1418+ def test_launcher_hides_hud(self):
1419+ """Opening the Launcher while the Hud is active must close the Hud."""
1420+ self.launch_unity()
1421+ self.main_window.get_greeter().unlock()
1422+ hud = self.main_window.get_hud()
1423+ launcher = self.main_window.get_launcher()
1424+
1425+ self._launch_test_app_from_app_screen()
1426+
1427+ hud.show()
1428+ launcher.show()
1429+
1430+ self.assertThat(hud.shown, Eventually(Equals(False)))
1431+
1432+ def _launch_test_app_from_app_screen(self):
1433+ """Launches the camera app using the Dash UI.
1434+
1435+ Because when testing on the desktop running
1436+ self.launch_application() will launch the application on the desktop
1437+ itself and not within the Unity UI.
1438+
1439+ """
1440+ dash = self.main_window.get_dash()
1441+ icon = dash.get_application_icon('Camera')
1442+ self.touch.tap_object(icon)
1443+
1444+ # Ensure application is open
1445+ bottombar = self.main_window.get_bottombar()
1446+ self.assertThat(bottombar.applicationIsOnForeground,
1447+ Eventually(Equals(True)))
1448+
1449+ # Because some tests are manually manipulating the finger, we want to
1450+ # cleanup if the test fails, but we don't want to fail with an exception if
1451+ # we don't.
1452+ def _maybe_release_finger(self):
1453+ """Only release the finger if it is in fact down."""
1454+ if self.touch._touch_finger is not None:
1455+ self.touch.release()
1456
1457=== added file 'tests/autopilot/unity8/shell/tests/test_lock_screen.py'
1458--- tests/autopilot/unity8/shell/tests/test_lock_screen.py 1970-01-01 00:00:00 +0000
1459+++ tests/autopilot/unity8/shell/tests/test_lock_screen.py 2013-07-23 12:13:30 +0000
1460@@ -0,0 +1,133 @@
1461+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1462+#
1463+# Unity Autopilot Test Suite
1464+# Copyright (C) 2012-2013 Canonical
1465+#
1466+# This program is free software: you can redistribute it and/or modify
1467+# it under the terms of the GNU General Public License as published by
1468+# the Free Software Foundation, either version 3 of the License, or
1469+# (at your option) any later version.
1470+#
1471+# This program is distributed in the hope that it will be useful,
1472+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1473+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1474+# GNU General Public License for more details.
1475+#
1476+# You should have received a copy of the GNU General Public License
1477+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1478+#
1479+
1480+
1481+from __future__ import absolute_import
1482+
1483+from unity8.shell import with_lightdm_mock
1484+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
1485+
1486+from autopilot.matchers import Eventually
1487+from autopilot.platform import model
1488+from testtools import skipUnless
1489+from testtools.matchers import Equals
1490+
1491+
1492+class TestLockscreen(UnityTestCase):
1493+
1494+ """Tests for the lock screen."""
1495+
1496+ scenarios = _get_device_emulation_scenarios()
1497+
1498+ @with_lightdm_mock("single-pin")
1499+ def test_can_unlock_pin_screen(self):
1500+ """Must be able to unlock the PIN entry lock screen."""
1501+ self.launch_unity()
1502+ greeter = self.main_window.get_greeter()
1503+ greeter.unlock()
1504+
1505+ lockscreen = self._wait_for_lockscreen()
1506+ self._enter_pincode("1234")
1507+
1508+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
1509+
1510+ @skipUnless(model() == 'Desktop', "Broken passphrase entry on UInput (LP: #1203788).")
1511+ @with_lightdm_mock("single-passphrase")
1512+ def test_can_unlock_passphrase_screen(self):
1513+ """Must be able to unlock the passphrase entry screen."""
1514+ self.launch_unity()
1515+ greeter = self.main_window.get_greeter()
1516+ greeter.unlock()
1517+
1518+ lockscreen = self._wait_for_lockscreen()
1519+ self._enter_passphrase("password")
1520+
1521+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
1522+
1523+ @with_lightdm_mock("single-pin")
1524+ def test_pin_screen_wrong_code(self):
1525+ """Entering the wrong pin code must not dismiss the lock screen."""
1526+ self.launch_unity()
1527+ greeter = self.main_window.get_greeter()
1528+ greeter.unlock()
1529+
1530+ lockscreen = self._wait_for_lockscreen()
1531+ self._enter_pincode("4321")
1532+
1533+ pinentryField = self.main_window.get_pinentryField()
1534+ self.assertThat(pinentryField.text, Eventually(Equals("")))
1535+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
1536+
1537+ @skipUnless(model() == 'Desktop', "Broken passphrase entry on UInput (LP: #1203788).")
1538+ @with_lightdm_mock("single-passphrase")
1539+ def test_passphrase_screen_wrong_password(self):
1540+ """Entering the wrong password must not dismiss the lock screen."""
1541+ self.launch_unity()
1542+ greeter = self.main_window.get_greeter()
1543+ greeter.unlock()
1544+
1545+ lockscreen = self._wait_for_lockscreen()
1546+ self._enter_passphrase("foobar")
1547+
1548+ pinentryField = self.main_window.get_pinentryField()
1549+ self.assertThat(pinentryField.text, Eventually(Equals("")))
1550+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
1551+
1552+ def _wait_for_lockscreen(self):
1553+ """Wait for the lock screen to load, and return it."""
1554+ pinPadLoader = self.main_window.get_pinPadLoader()
1555+ self.assertThat(pinPadLoader.progress, Eventually(Equals(1)))
1556+ lockscreen = self.main_window.get_lockscreen()
1557+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
1558+ return lockscreen
1559+
1560+ def _enter_pincode(self, code):
1561+ """Enter code 'code' into the single-pin lightdm pincode entry
1562+ screen.
1563+
1564+ :param code: must be a string of numeric characters.
1565+ :raises: TypeError if code is not a string.
1566+ :raises: ValueError if code contains non-numeric characters.
1567+
1568+ """
1569+
1570+ if not isinstance(code, basestring):
1571+ raise TypeError("'code' parameter must be a string.")
1572+ for num in code:
1573+ if not num.isdigit():
1574+ raise ValueError(
1575+ "'code' parameter contains non-numeric characters."
1576+ )
1577+ self.touch.tap_object(self.main_window.get_pinPadButton(int(num)))
1578+
1579+ def _enter_passphrase(self, passphrase):
1580+ """Enter the password specified in 'passphrase' into the password entry
1581+ field.
1582+
1583+ :param passphrase: The string you want to enter.
1584+ :raises: TypeError if passphrase is not a string.
1585+
1586+ """
1587+ if not isinstance(passphrase, basestring):
1588+ raise TypeError("'passphrase' parameter must be a string.")
1589+
1590+ pinentryField = self.main_window.get_pinentryField()
1591+ self.touch.tap_object(pinentryField)
1592+ self.keyboard.type(passphrase)
1593+ self.keyboard.type("\n")
1594
1595=== removed file 'tests/autopilot/unity8/shell/tests/testbigscreen.py'
1596--- tests/autopilot/unity8/shell/tests/testbigscreen.py 2013-07-10 15:31:37 +0000
1597+++ tests/autopilot/unity8/shell/tests/testbigscreen.py 1970-01-01 00:00:00 +0000
1598@@ -1,25 +0,0 @@
1599-# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1600-# Copyright 2013 Canonical
1601-#
1602-# This program is free software: you can redistribute it and/or modify it
1603-# under the terms of the GNU General Public License version 3, as published
1604-# by the Free Software Foundation.
1605-
1606-"""Add tests here if you want to ensure everything is aligned correctly on huge screens. Because this test does not fit on most screens, you should not use input devices here or your tests are likely to fail"""
1607-
1608-from testtools.matchers import Equals
1609-from autopilot.matchers import Eventually
1610-
1611-from unity8.shell.tests import ShellTestCase
1612-
1613-class TestBig(ShellTestCase):
1614- def setUp(self):
1615- super(TestBig, self).setUp("2560x1600", "20")
1616- self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True)))
1617-
1618- def tearDown(self):
1619- super(TestBig, self).tearDown()
1620-
1621- def test_hud_not_shown_greeter(self):
1622- hud_showable = self.main_window.get_hud_showable()
1623- self.assertThat(hud_showable.y, Eventually(Equals(1600)))
1624
1625=== removed file 'tests/autopilot/unity8/shell/tests/testlockscreen.py'
1626--- tests/autopilot/unity8/shell/tests/testlockscreen.py 2013-07-10 15:31:37 +0000
1627+++ tests/autopilot/unity8/shell/tests/testlockscreen.py 1970-01-01 00:00:00 +0000
1628@@ -1,118 +0,0 @@
1629-# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1630-# Copyright 2013 Canonical
1631-#
1632-# This program is free software: you can redistribute it and/or modify it
1633-# under the terms of the GNU General Public License version 3, as published
1634-# by the Free Software Foundation.
1635-
1636-
1637-# This file contains general purpose test cases for Unity.
1638-# Each test written in this file will be executed for a variety of
1639-# configurations, such as Phone, Tablet or Desktop form factors.
1640-#
1641-# Sometimes there is the need to disable a certain test for a particular
1642-# configuration. To do so, add this in a new line directly below your test:
1643-#
1644-# test_testname.blacklist = (FormFactors.Tablet, FormFactors.Desktop,)
1645-#
1646-# Available form factors are:
1647-# FormFactors.Phone
1648-# FormFactors.Tablet
1649-# FormFactors.Desktop
1650-
1651-
1652-"""Tests for the Shell"""
1653-
1654-from __future__ import absolute_import
1655-
1656-from unity8.shell.tests import ShellTestCase, FormFactors
1657-from unity8.shell.tests.helpers import TestShellHelpers
1658-
1659-from autopilot.input import Mouse, Touch, Pointer
1660-from testtools.matchers import Equals, NotEquals, GreaterThan, MismatchError
1661-from autopilot.matchers import Eventually
1662-from autopilot.display import Display
1663-from autopilot.platform import model
1664-
1665-import unittest
1666-import time
1667-import os
1668-from os import path
1669-
1670-
1671-class TestLockscreens(ShellTestCase, TestShellHelpers):
1672-
1673- """Tests the Lockscreens"""
1674-
1675- # Scenarios:
1676- # Fill in the scenarios to run the whole test suite with multiple configurations.
1677- # Use app_width, app_height and grid_unit_px to set the apps geometry.
1678- # Set app_width and app_height to 0 to use fullscreen.
1679- # Set grid_unit_px to 0 to use the current system environment.
1680-
1681- if model() == 'Desktop':
1682- scenarios = [
1683- ('Pinlock', dict(app_width=768, app_height=1280, grid_unit_px=18, lightdm_mock="single-pin")),
1684- ('Keylock', dict(app_width=768, app_height=1280, grid_unit_px=18, lightdm_mock="single-passphrase")),
1685- ]
1686- else:
1687- scenarios = [
1688- ('Pinlock', dict(app_width=0, app_height=0, grid_unit_px=0, lightdm_mock="single-pin")),
1689- ('Keylock', dict(app_width=0, app_height=0, grid_unit_px=0, lightdm_mock="single-key")),
1690- ]
1691-
1692- def setUp(self):
1693- self.touch = Touch.create()
1694-
1695- sg = Display().create()
1696- divisor = 1
1697- while (sg.get_screen_width() < self.app_width / divisor or sg.get_screen_height() < self.app_height / divisor):
1698- divisor = divisor * 2
1699- super(TestLockscreens, self).setUp("%sx%s" % (self.app_width / divisor, self.app_height / divisor), "%s" % (self.grid_unit_px / divisor))
1700-
1701- dash = self.main_window.get_dash()
1702- self.assertThat(dash.showScopeOnLoaded, Eventually(Equals(""), timeout=30))
1703-
1704- def test_unlock(self):
1705- self.unlock_greeter()
1706-
1707- pinPadLoader = self.main_window.get_pinPadLoader();
1708- self.assertThat(pinPadLoader.progress, Eventually(Equals(1)))
1709- lockscreen = self.main_window.get_lockscreen();
1710- self.assertThat(lockscreen.shown, Eventually(Equals(True)))
1711-
1712- if self.lightdm_mock == "single-pin":
1713- self.touch.tap_object(self.main_window.get_pinPadButton(1))
1714- self.touch.tap_object(self.main_window.get_pinPadButton(2))
1715- self.touch.tap_object(self.main_window.get_pinPadButton(3))
1716- self.touch.tap_object(self.main_window.get_pinPadButton(4))
1717- self.assertThat(lockscreen.shown, Eventually(Equals(False)))
1718- else:
1719- pinentryField = self.main_window.get_pinentryField()
1720- self.touch.tap_object(pinentryField)
1721- self.keyboard.type("password\n")
1722- self.assertThat(lockscreen.shown, Eventually(Equals(False)))
1723-
1724- def test_unlock_wrong(self):
1725- self.unlock_greeter()
1726-
1727- pinPadLoader = self.main_window.get_pinPadLoader();
1728- self.assertThat(pinPadLoader.progress, Eventually(Equals(1)))
1729- lockscreen = self.main_window.get_lockscreen();
1730- self.assertThat(lockscreen.shown, Eventually(Equals(True)))
1731- pinentryField = self.main_window.get_pinentryField()
1732-
1733- if self.lightdm_mock == "single-pin":
1734- self.touch.tap_object(self.main_window.get_pinPadButton(4))
1735- self.touch.tap_object(self.main_window.get_pinPadButton(3))
1736- self.touch.tap_object(self.main_window.get_pinPadButton(2))
1737- self.assertThat(pinentryField.text, Eventually(Equals("432")))
1738- self.touch.tap_object(self.main_window.get_pinPadButton(1))
1739-
1740- self.assertThat(pinentryField.text, Eventually(Equals("")))
1741- self.assertThat(lockscreen.shown, Eventually(Equals(True)))
1742- else:
1743- self.touch.tap_object(pinentryField)
1744- self.keyboard.type("foobar\n")
1745- self.assertThat(pinentryField.text, Eventually(Equals("")))
1746- self.assertThat(lockscreen.shown, Eventually(Equals(True)))

Subscribers

People subscribed via source and target branches