on xenial help sign in
Merge in ~elopio/unity8/use_fake_instead_of_messaging
commit295ab579bbabdc7d52eb970ba686dff2f159aa71 authorMichael Terry <michael.terry@canonical.com> dateMon 14 Apr 2014, 15:45 (13 years ago) parent9da964946e08ae
23 files changed+368−211
debian/changelog+44 debian/unity8-autopilot.install+1 po/gl.po+1−1 qml/Components/FilterGrid.qml+1 qml/Components/ResponsiveGridView.qml+1 qml/Dash/CardFilterGrid.qml+1 qml/Dash/DashContent.qml+10−18 qml/Dash/DashRenderer.qml+2 qml/Dash/GenericScopeView.qml+8−8 qml/Notifications/NotificationMenuItemFactory.qml+2−1 tests/autopilot/unity8/application_lifecycle/tests/__init__.py+49 tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+42−121 tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+8−39 tests/autopilot/unity8/indicators/tests/__init__.py+17 tests/autopilot/unity8/indicators/tests/test_indicators.py+69−13 tests/autopilot/unity8/process_helpers.py+2−1 tests/autopilot/unity8/shell/emulators/__init__.py+2−6 tests/autopilot/unity8/shell/emulators/dash.py+15 tests/autopilot/unity8/shell/emulators/main_window.py+32−2 tests/autopilot/unity8/shell/tests/test_emulators.py+16 tests/autopilot/unity8/shell/tests/test_system_integration.py+1−1 tools/CMakeLists.txt+2 tools/unlock-device+42
debian/changelog+44
@@ -1,3 +1,47 @@
1+unity8 (7.85+14.04.20140410.1-0ubuntu1) trusty; urgency=medium
2+
3+ [ Didier Roche ]
4+ * Resync trunk with previous revert upload
5+
6+ [ Michał Sawicz ]
7+ * Set the Qt.ImhNoPredictiveText flag on wifi password field, fixes
8+ lp:1291575 (LP: #1291575)
9+
10+ [ Albert Astals ]
11+ * Take into account the originY when specifying the delegate ranges
12+ Fixes bug #1300302 (LP: #1300302)
13+
14+ [ CI bot ]
15+ * Resync trunk
16+
17+ [ Allan LeSage ]
18+ * Swiping open an indicator must show its correct title--protect
19+ against lp:1253804 . (LP: #1253804)
20+
21+ [ Alexander Sack ]
22+ * Fix TypeError: issue seen in system_integration autopilot test on
23+ image 279. (LP: #1303685)
24+
25+ [ Bill Filler ]
26+ * Set the Qt.ImhNoPredictiveText flag on wifi password field, fixes
27+ lp:1291575 (LP: #1291575)
28+
29+ [ Leo Arias ]
30+ * Added a search autopilot helper.
31+
32+ [ Michael Terry ]
33+ * Provide a all-in-one script for getting a device to an unlocked
34+ state.
35+
36+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 10 Apr 2014 10:03:31 +0000
37+
38+unity8 (7.85+14.04.20140404.is.7.85+14.04.20140403.1-0ubuntu1) trusty; urgency=medium
39+
40+ * Revert to previous version as it's linked to latest sdk change which
41+ is making gallery-app AP tests failing on the CI dashboard
42+
43+ -- Didier Roche <didrocks@ubuntu.com> Tue, 08 Apr 2014 13:53:47 +0200
44+
145unity8 (7.85+14.04.20140404-0ubuntu1) trusty; urgency=low
246
347 [ Albert Astals ]
debian/unity8-autopilot.install+1
@@ -1 +1,2 @@
11usr/lib/python*/*/unity*
2+usr/share/unity8/unlock-device
po/gl.po+1−1
@@ -14,7 +14,7 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-04-08 07:13+0000\n"
17+"X-Launchpad-Export-Date: 2014-04-09 07:31+0000\n"
1818"X-Generator: Launchpad (build 16976)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
qml/Components/FilterGrid.qml+1
@@ -59,6 +59,7 @@ Item {
5959 property alias cellHeight: iconTileGrid.cellHeight
6060 property alias delegateCreationBegin: iconTileGrid.delegateCreationBegin
6161 property alias delegateCreationEnd: iconTileGrid.delegateCreationEnd
62+ readonly property alias originY: iconTileGrid.originY
6263 readonly property alias flicking: iconTileGrid.flicking
6364 readonly property alias moving: iconTileGrid.moving
6465 readonly property alias pressDelay: iconTileGrid.pressDelay
qml/Components/ResponsiveGridView.qml+1
@@ -40,6 +40,7 @@ Item {
4040 readonly property alias flicking: gridView.flicking
4141 readonly property alias moving: gridView.moving
4242 readonly property alias pressDelay: gridView.pressDelay
43+ readonly property alias originY: gridView.originY
4344 property alias delegateCreationBegin: gridView.delegateCreationBegin
4445 property alias delegateCreationEnd: gridView.delegateCreationEnd
4546 property alias highlightIndex: gridView.highlightIndex
qml/Dash/CardFilterGrid.qml+1
@@ -24,6 +24,7 @@ DashRenderer {
2424 collapsedHeight: filterGrid.collapsedHeight
2525 margins: filterGrid.margins
2626 uncollapsedHeight: filterGrid.uncollapsedHeight
27+ originY: filterGrid.originY
2728 verticalSpacing: units.gu(1)
2829 currentItem: filterGrid.currentItem
2930 height: filterGrid.height
qml/Dash/DashContent.qml+10−18
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Unity 0.2
20−import Utils 0.1
2120import "../Components"
2221
2322Item {
@@ -189,30 +188,23 @@ Item {
189188 width: parent.width
190189 style: DashContentTabBarStyle {}
191190
192− SortFilterProxyModel {
193− id: tabBarModel
191+ model: dashContentList.model
194192
195− model: dashContentList.model
196−
197− property int selectedIndex: -1
198− onSelectedIndexChanged: {
199− if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
200− // TODO This together with the Timer below
201− // are a workaround for the first tab sometimes not showing the text.
202− // But Tabs are going away in the future so not sure if makes
203− // sense invetigating what's the problem at this stage
204− selectionModeTimer.restart();
205− }
206− dashContentList.currentIndex = selectedIndex;
193+ onSelectedIndexChanged: {
194+ if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
195+ // TODO This together with the Timer below
196+ // are a workaround for the first tab sometimes not showing the text.
197+ // But Tabs are going away in the future so not sure if makes
198+ // sense invetigating what's the problem at this stage
199+ selectionModeTimer.restart();
207200 }
201+ dashContentList.currentIndex = selectedIndex;
208202 }
209203
210− model: tabBarModel.count > 0 ? tabBarModel : null
211−
212204 Connections {
213205 target: dashContentList
214206 onCurrentIndexChanged: {
215− tabBarModel.selectedIndex = dashContentList.currentIndex
207+ tabBar.selectedIndex = dashContentList.currentIndex
216208 }
217209 }
218210
qml/Dash/DashRenderer.qml+2
@@ -33,6 +33,8 @@ Item {
3333
3434 property var delegateCreationEnd: undefined
3535
36+ property real originY: 0
37+
3638 property real verticalSpacing: 0
3739
3840 // The current item of the renderer
qml/Dash/GenericScopeView.qml+8−8
@@ -247,16 +247,16 @@ FocusScope {
247247
248248 if (item && item.hasOwnProperty("delegateCreationBegin")) {
249249 if (baseItem.y + baseItem.height <= 0) {
250− // Not visible (item at top of the list)
251− item.delegateCreationBegin = baseItem.height
252− item.delegateCreationEnd = baseItem.height
250+ // Not visible (item at top of the list viewport)
251+ item.delegateCreationBegin = item.originY + baseItem.height
252+ item.delegateCreationEnd = item.originY + baseItem.height
253253 } else if (baseItem.y >= categoryView.height) {
254− // Not visible (item at bottom of the list)
255− item.delegateCreationBegin = 0
256− item.delegateCreationEnd = 0
254+ // Not visible (item at bottom of the list viewport)
255+ item.delegateCreationBegin = item.originY
256+ item.delegateCreationEnd = item.originY
257257 } else {
258− item.delegateCreationBegin = Math.max(-baseItem.y, 0)
259− item.delegateCreationEnd = Math.min(categoryView.height + item.delegateCreationBegin, baseItem.height)
258+ item.delegateCreationBegin = item.originY + Math.max(-baseItem.y, 0)
259+ item.delegateCreationEnd = item.originY + Math.min(categoryView.height + item.delegateCreationBegin, baseItem.height)
260260 }
261261 }
262262 }
qml/Notifications/NotificationMenuItemFactory.qml+2−1
@@ -66,7 +66,8 @@ Loader {
6666 TextField {
6767 id: textfield
6868
69− inputMethodHints: Qt.ImhNoAutoUppercase
69+ // TODO using Qt.ImhNoPredictiveText here until lp #1291575 is fixed for ubuntu-ui-toolkit
70+ inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
7071 anchors.left: parent.left; anchors.right: parent.right
7172 echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
7273 height: units.gu(5)
tests/autopilot/unity8/application_lifecycle/tests/__init__.py+49
@@ -0,0 +1,49 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
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.
15+#
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/>.
18+#
19+
20+from autopilot.matchers import Eventually
21+from testtools.matchers import Equals
22+from ubuntuuitoolkit import fixture_setup
23+
24+from unity8 import process_helpers
25+from unity8.shell import tests
26+
27+
28+class ApplicationLifeCycleTestCase(tests.UnityTestCase):
29+
30+ def setUp(self):
31+ super(ApplicationLifeCycleTestCase, self).setUp()
32+ self._qml_mock_enabled = False
33+ self._data_dirs_mock_enabled = False
34+ unity_proxy = self.launch_unity()
35+ process_helpers.unlock_unity(unity_proxy)
36+
37+ def create_test_application(self):
38+ desktop_file_dict = fixture_setup.DEFAULT_DESKTOP_FILE_DICT
39+ desktop_file_dict.update({'X-Ubuntu-Single-Instance': 'true'})
40+ fake_application = fixture_setup.FakeApplication(
41+ desktop_file_dict=desktop_file_dict)
42+ self.useFixture(fake_application)
43+ return (
44+ fake_application.qml_file_path, fake_application.desktop_file_path)
45+
46+ def assert_current_focused_application(self, application_name):
47+ self.assertThat(
48+ self.main_window.get_current_focused_app_id,
49+ Eventually(Equals(application_name)))
tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+42−121
@@ -21,28 +21,26 @@
2121
2222from __future__ import absolute_import
2323
24−from unity8.process_helpers import lock_unity, unlock_unity
25−from unity8.shell import disable_qml_mocking
26−from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
24+import logging
25+import os
2726
2827from autopilot.matchers import Eventually
2928from autopilot.platform import model
30−from testtools.matchers import Equals, NotEquals
29+from testtools.matchers import Equals
3130
32−import logging
33−import subprocess
31+from unity8 import process_helpers
32+from unity8.application_lifecycle import tests
3433
35−logger = logging.getLogger(__name__)
3634
35+logger = logging.getLogger(__name__)
3736
38−class ApplicationLifecycleTests(UnityTestCase):
3937
40− scenarios = _get_device_emulation_scenarios()
38+class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
4139
4240 def setUp(self):
41+ if model() == 'Desktop':
42+ self.skipTest('Test cannot be run on the desktop.')
4343 super(ApplicationLifecycleTests, self).setUp()
44− if model() == "Desktop":
45− self.skipTest("Test cannot be run on the desktop.")
4644
4745 def swipe_screen_from_right(self):
4846 width = self.main_window.width
@@ -55,142 +53,65 @@ class ApplicationLifecycleTests(UnityTestCase):
5553 logger.info("Swiping screen from the right edge")
5654 self.touch.drag(start_x, start_y, end_x, end_y)
5755
58− def swipe_screen_from_left(self):
59− width = self.main_window.width
60− height = self.main_window.height
61− start_x = 0
62− start_y = int(height/2)
63− end_x = width
64− end_y = start_y
65−
66− logger.info("Swiping screen from the left edge")
67− self.touch.drag(start_x, start_y, end_x, end_y)
68−
69− def _launch_app_directly(self, app_name):
70− """Launches the application *app_name*
71−
72− Assumes that the desktop file resides at:
73− /usr/share/applications/{app_name}.desktop
56+ def launch_fake_app(self):
57+ _, desktop_file_path = self.create_test_application()
58+ desktop_file_name = os.path.basename(desktop_file_path)
59+ application_name, _ = os.path.splitext(desktop_file_name)
60+ self.launch_upstart_application(application_name)
61+ return application_name
7462
75− """
76− desktop_file = "--desktop_file_hint="\
77− "/usr/share/applications/{app_name}.desktop".format(
78− app_name=app_name
79− )
80− return self.launch_test_application(
81− app_name,
82− desktop_file,
83− "--stage_hint=main_stage",
84− app_type='qt'
85− )
86−
87− def _launch_app(self, app_name):
88− """Launches the application *app_name* via upstart."""
89− command = ['initctl', '--quiet', 'start', 'application',
90− 'APP_ID=%s' % app_name]
91− subprocess.check_call(command)
92−
93− command = ['pkill', '-f', '-9', app_name]
94− self.addCleanup(subprocess.call, command)
95−
96− @disable_qml_mocking
9763 def test_can_launch_application(self):
9864 """Must be able to launch an application."""
99− unity_proxy = self.launch_unity()
100− unlock_unity(unity_proxy)
65+ application_name = self.launch_fake_app()
66+ self.assert_current_focused_application(application_name)
10167
102− self._launch_app("messaging-app")
103− self.assertThat(
104− self.main_window.get_current_focused_app_id(),
105− Eventually(Equals("messaging-app"))
106− )
107−
108− @disable_qml_mocking
10968 def test_can_launch_multiple_applications(self):
11069 """A second application launched must be focused."""
111− unity_proxy = self.launch_unity()
112− unlock_unity(unity_proxy)
113−
114− self._launch_app("messaging-app")
115− self.assertThat(
116− self.main_window.get_current_focused_app_id(),
117− Eventually(Equals("messaging-app"))
118− )
119−
120− self._launch_app("address-book-app")
121− self.assertThat(
122− self.main_window.get_current_focused_app_id(),
123− Eventually(Equals("address-book-app"))
124− )
125−
126− @disable_qml_mocking
70+ application1_name = self.launch_fake_app()
71+ self.assert_current_focused_application(application1_name)
72+
73+ application2_name = self.launch_fake_app()
74+ self.assertFalse(application1_name == application2_name)
75+ self.assert_current_focused_application(application2_name)
76+
12777 def test_app_moves_from_unfocused_to_focused(self):
12878 """An application that is in the unfocused state must be able to be
12979 brought back to the focused state.
13080
13181 """
132− unity_proxy = self.launch_unity()
133− unlock_unity(unity_proxy)
134−
135− self._launch_app("messaging-app")
136− self.assertThat(
137− self.main_window.get_current_focused_app_id(),
138− Eventually(Equals("messaging-app"))
139− )
140−
141− # FIXME: this should be able to launch via upstart. Bug #1273844
142− self._launch_app_directly("address-book-app")
143− self.assertThat(
144− self.main_window.get_current_focused_app_id(),
145− Eventually(Equals("address-book-app"))
146− )
82+ application1_name = self.launch_fake_app()
83+ self.assert_current_focused_application(application1_name)
84+
85+ application2_name = self.launch_fake_app()
86+ self.assertFalse(application1_name == application2_name)
87+ self.assert_current_focused_application(application2_name)
14788
14889 self.swipe_screen_from_right()
14990
150− self.assertThat(
151− self.main_window.get_current_focused_app_id(),
152− Eventually(Equals("messaging-app"))
153− )
91+ self.assert_current_focused_application(application1_name)
15492
155− @disable_qml_mocking
15693 def test_greeter_hides_on_app_open(self):
15794 """Greeter should hide when an app is opened"""
158− unity_proxy = self.launch_unity()
95+ process_helpers.lock_unity()
15996 greeter = self.main_window.get_greeter()
16097 self.assertThat(greeter.created, Eventually(Equals(True)))
16198
162− self._launch_app("messaging-app")
99+ application_name = self.launch_fake_app()
163100 self.assertThat(greeter.created, Eventually(Equals(False)))
164− self.assertThat(
165− self.main_window.get_current_focused_app_id(),
166− Eventually(Equals("messaging-app"))
167− )
101+ self.assert_current_focused_application(application_name)
168102
169− @disable_qml_mocking
170103 def test_greeter_hides_on_app_focus(self):
171104 """Greeter should hide when an app is re-focused"""
172− unity_proxy = self.launch_unity()
173− greeter = self.main_window.get_greeter()
174− unlock_unity(unity_proxy)
105+ application_name = self.launch_fake_app()
106+ self.assert_current_focused_application(application_name)
175107
176− self._launch_app("messaging-app")
177− self.assertThat(
178− self.main_window.get_current_focused_app_id(),
179− Eventually(Equals("messaging-app"))
180− )
108+ self.main_window.show_dash_swiping()
109+ self.assert_current_focused_application('')
181110
182− self.swipe_screen_from_left()
183− self.assertThat(
184− self.main_window.get_current_focused_app_id(),
185− Eventually(Equals(''))
186− )
187−
188− lock_unity()
111+ process_helpers.lock_unity()
112+ greeter = self.main_window.get_greeter()
189113 self.assertThat(greeter.created, Eventually(Equals(True)))
190114
191− self._launch_app("messaging-app")
115+ self.launch_upstart_application(application_name)
192116 self.assertThat(greeter.created, Eventually(Equals(False)))
193− self.assertThat(
194− self.main_window.get_current_focused_app_id(),
195− Eventually(Equals("messaging-app"))
196− )
117+ self.assert_current_focused_application(application_name)
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+8−39
@@ -20,48 +20,19 @@
2020"""Test the integration with the URL dispatcher service."""
2121
2222import os
23+import subprocess
2324
2425from autopilot import platform
25−from autopilot.matchers import Eventually
26−from testtools.matchers import Equals
27−from ubuntuuitoolkit import fixture_setup
2826
29−from unity8 import process_helpers
30−from unity8.shell import tests
27+from unity8.application_lifecycle import tests
3128
3229
33−class URLDispatcherTestCase(tests.UnityTestCase):
34−
35− scenarios = tests._get_device_emulation_scenarios()
36−
37− test_qml = ("""
38−import QtQuick 2.0
39−import Ubuntu.Components 0.1
40−
41−MainView {
42− width: units.gu(48)
43− height: units.gu(60)
44−
45− Label {
46− text: 'Test application.'
47− }
48−}
49−""")
30+class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
5031
5132 def setUp(self):
5233 if platform.model() == 'Desktop':
5334 self.skipTest("URL dispatcher doesn't work on the desktop.")
5435 super(URLDispatcherTestCase, self).setUp()
55− self._qml_mock_enabled = False
56− self._data_dirs_mock_enabled = False
57− unity_proxy = self.launch_unity()
58− process_helpers.unlock_unity(unity_proxy)
59−
60− def create_test_application(self):
61− fake_application = fixture_setup.FakeApplication(self.test_qml)
62− self.useFixture(fake_application)
63− return (
64− fake_application.qml_file_path, fake_application.desktop_file_path)
6536
6637 def test_swipe_out_application_started_by_url_dispatcher(self):
6738 _, desktop_file_path = self.create_test_application()
@@ -70,12 +41,10 @@ MainView {
7041
7142 self.assertEqual('', self.main_window.get_current_focused_app_id())
7243 self.addCleanup(os.system, 'pkill qmlscene')
73− os.system('url-dispatcher application:///{}'.format(desktop_file_name))
74− self.assertThat(
75− self.main_window.get_current_focused_app_id,
76− Eventually(Equals(application_name)))
44+
45+ subprocess.check_call(
46+ ['url-dispatcher', 'application:///{}'.format(desktop_file_name)])
47+ self.assert_current_focused_application(application_name)
7748
7849 self.main_window.show_dash_swiping()
79− self.assertThat(
80− self.main_window.get_current_focused_app_id,
81− Eventually(Equals('')))
50+ self.assert_current_focused_application('')
tests/autopilot/unity8/indicators/tests/__init__.py+17
@@ -0,0 +1,17 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity - Indicators Autopilot Test Suite
4+# Copyright (C) 2013, 2014 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
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.
15+#
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/>.
tests/autopilot/unity8/indicators/tests/test_indicators.py+69−13
@@ -1,7 +1,7 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
22#
3−# Unity - Indicators Autopilot Test Suite
4−# Copyright (C) 2013 Canonical
3+# Unity Indicators Autopilot Test Suite
4+# Copyright (C) 2013, 2014 Canonical
55#
66# This program is free software: you can redistribute it and/or modify
77# it under the terms of the GNU General Public License as published by
@@ -15,20 +15,32 @@
1515#
1616# You should have received a copy of the GNU General Public License
1717# along with this program. If not, see <http://www.gnu.org/licenses/>.
18−#
1918
2019from __future__ import absolute_import
2120
21+from testscenarios import multiply_scenarios
22+
2223from autopilot import platform
23−from testtools import skipIf
2424
2525from unity8.process_helpers import unlock_unity
26−from unity8.shell.tests import UnityTestCase
26+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
2727
2828
2929class IndicatorTestCase(UnityTestCase):
3030
31− scenarios = [
31+ device_emulation_scenarios = _get_device_emulation_scenarios()
32+
33+ def setUp(self):
34+ if platform.model() == 'Desktop':
35+ self.skipTest('Test cannot be run on the desktop.')
36+ super(IndicatorTestCase, self).setUp()
37+ self.unity_proxy = self.launch_unity()
38+ unlock_unity(self.unity_proxy)
39+
40+
41+class IndicatorExistsTestCase(IndicatorTestCase):
42+
43+ indicator_scenarios = [
3244 ('Bluetooth', dict(indicator_name='indicator-bluetooth')),
3345 ('Datetime', dict(indicator_name='indicator-datetime')),
3446 ('Location', dict(indicator_name='indicator-location')),
@@ -37,14 +49,58 @@ class IndicatorTestCase(UnityTestCase):
3749 ('Power', dict(indicator_name='indicator-power')),
3850 ('Sound', dict(indicator_name='indicator-sound')),
3951 ]
52+ scenarios = multiply_scenarios(
53+ indicator_scenarios,
54+ IndicatorTestCase.device_emulation_scenarios
55+ )
4056
41− @skipIf(platform.image_codename() == 'Desktop',
42− "Unity8/phablet-only test!")
4357 def setUp(self):
44− super(IndicatorTestCase, self).setUp()
58+ super(IndicatorExistsTestCase, self).setUp()
59+ if (platform.model() == 'Nexus 10' and
60+ self.indicator_name == 'indicator-bluetooth'):
61+ self.skipTest('Nexus 10 does not have bluetooth at the moment.')
4562
4663 def test_indicator_exists(self):
47− unity_proxy = self.launch_unity()
48− unlock_unity(unity_proxy)
49− indicator = self.main_window.get_indicator(self.indicator_name)
50− self.assertIsNotNone(indicator)
64+ self.main_window._get_indicator_widget(
65+ self.indicator_name
66+ )
67+
68+
69+class IndicatorPageTitleMatchesWidgetTestCase(IndicatorTestCase):
70+
71+ indicator_scenarios = [
72+ ('Bluetooth', dict(indicator_name='indicator-bluetooth',
73+ title='Bluetooth')),
74+ ('Datetime', dict(indicator_name='indicator-datetime',
75+ title='Upcoming')),
76+ ('Location', dict(indicator_name='indicator-location',
77+ title='Location')),
78+ ('Messaging', dict(indicator_name='indicator-messages',
79+ title='Incoming')),
80+ ('Network', dict(indicator_name='indicator-network',
81+ title='Network')),
82+ ('Power', dict(indicator_name='indicator-power',
83+ title='Battery')),
84+ ('Sound', dict(indicator_name='indicator-sound',
85+ title='Sound')),
86+ ]
87+ scenarios = multiply_scenarios(
88+ indicator_scenarios,
89+ IndicatorTestCase.device_emulation_scenarios
90+ )
91+
92+ def setUp(self):
93+ super(IndicatorPageTitleMatchesWidgetTestCase, self).setUp()
94+ if (platform.model() == 'Nexus 10' and
95+ self.indicator_name == 'indicator-bluetooth'):
96+ self.skipTest('Nexus 10 does not have bluetooth at the moment.')
97+
98+ def test_indicator_page_title_matches_widget(self):
99+ """Swiping open an indicator must show its correct title.
100+
101+ See https://bugs.launchpad.net/ubuntu-ux/+bug/1253804 .
102+ """
103+ indicator_page = self.main_window.open_indicator_page(
104+ self.indicator_name)
105+ self.assertTrue(indicator_page.visible)
106+ self.assertEqual(indicator_page.title, self.title)
tests/autopilot/unity8/process_helpers.py+2−1
@@ -89,7 +89,8 @@ def unlock_unity(unity_proxy_obj=None):
8989 break
9090
9191
92−def lock_unity():
92+def lock_unity(unity_proxy_obj=None):
93+ """Helper function that attempts to lock the unity greeter."""
9394 import evdev, time
9495 uinput = evdev.UInput(name='unity8-autopilot-power-button',
9596 devnode='/dev/autopilot-uinput')
tests/autopilot/unity8/shell/emulators/__init__.py+2−6
@@ -17,16 +17,12 @@
1717# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818#
1919
20−from autopilot import input, introspection
20+from ubuntuuitoolkit import emulators as toolkit_emulators
2121
2222
23−class UnityEmulatorBase(introspection.CustomEmulatorBase):
23+class UnityEmulatorBase(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2424 """A base class for all unity emulators."""
2525
26− def __init__(self, *args):
27− super(UnityEmulatorBase, self).__init__(*args)
28− self.pointing_device = input.Pointer(device=input.Touch.create())
29−
3026
3127class UnityEmulatorException(Exception):
3228 """Exception raised when there is an error with the Unity emulators."""
tests/autopilot/unity8/shell/emulators/dash.py+15
@@ -23,6 +23,8 @@ from unity8.shell import emulators
2323
2424from autopilot import logging as autopilot_logging
2525from autopilot.introspection import dbus
26+from testtools.matchers import MatchesAny, Equals
27+from ubuntuuitoolkit import emulators as toolkit_emulators
2628
2729
2830logger = logging.getLogger(__name__)
@@ -132,6 +134,19 @@ class Dash(emulators.UnityEmulatorBase):
132134 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
133135 self.dash_content_list.currentIndex.wait_for(original_index + 1)
134136
137+ def enter_search_query(self, query):
138+ search_text_field = self._get_search_text_field()
139+ search_text_field.write(query)
140+ search_text_field.state.wait_for('idle')
141+
142+ def _get_search_text_field(self):
143+ page_header = self._get_page_header()
144+ search_container = page_header.select_single(
145+ 'QQuickItem', objectName='searchContainer')
146+ search_container.state.wait_for(
147+ MatchesAny(Equals('narrowActive'), Equals('active')))
148+ return search_container.select_single(toolkit_emulators.TextField)
149+
135150
136151class GenericScopeView(emulators.UnityEmulatorBase):
137152 """Autopilot emulator for generic scopes."""
tests/autopilot/unity8/shell/emulators/main_window.py+32−2
@@ -20,6 +20,7 @@
2020import logging
2121
2222from autopilot import logging as autopilot_logging
23+from autopilot import input
2324
2425from unity8.shell import emulators
2526from unity8.shell.emulators.greeter import Greeter
@@ -87,12 +88,32 @@ class QQuickView(emulators.UnityEmulatorBase):
8788 def get_pinentryField(self):
8889 return self.select_single(objectName="pinentryField")
8990
90− def get_indicator(self, indicator_name):
91− return self.wait_select_single(
91+ def _get_indicator_widget(self, indicator_name):
92+ return self.select_single(
9293 'DefaultIndicatorWidget',
9394 objectName=indicator_name+'-widget'
9495 )
9596
97+ def _get_indicator_page(self, indicator_name):
98+ return self.select_single(
99+ 'DefaultIndicatorPage',
100+ objectName=indicator_name+'-page'
101+ )
102+
103+ @autopilot_logging.log_action(logger.info)
104+ def open_indicator_page(self, indicator_name):
105+ """Swipe to open the indicator, wait until it's open.
106+
107+ :returns: The indicator page.
108+ """
109+ widget = self._get_indicator_widget(indicator_name)
110+ start_x, start_y = input.get_center_point(widget)
111+ end_x = start_x
112+ end_y = self.height
113+ self.pointing_device.drag(start_x, start_y, end_x, end_y)
114+ self.wait_select_single('Indicators', fullyOpened=True)
115+ return self._get_indicator_page(indicator_name)
116+
96117 def get_shell_background(self):
97118 return self.select_single(
98119 "CrossFadeImage", objectName="backgroundImage")
@@ -113,3 +134,12 @@ class QQuickView(emulators.UnityEmulatorBase):
113134 def get_current_focused_app_id(self):
114135 """Return the id of the focused application."""
115136 return self.select_single('Shell').focusedApplicationId
137+
138+ @autopilot_logging.log_action(logger.info)
139+ def search(self, query):
140+ search_indicator = self._get_search_indicator()
141+ self.pointing_device.click_object(search_indicator)
142+ self.get_dash().enter_search_query(query)
143+
144+ def _get_search_indicator(self):
145+ return self.select_single('SearchIndicator', objectName='search')
tests/autopilot/unity8/shell/tests/test_emulators.py+16
@@ -39,6 +39,22 @@ from unity8.shell import emulators, fixture_setup, tests
3939from unity8.shell.emulators import dash as dash_emulators
4040
4141
42+class MainWindowTestCase(tests.UnityTestCase):
43+
44+ scenarios = tests._get_device_emulation_scenarios()
45+
46+ def setUp(self):
47+ super(MainWindowTestCase, self).setUp()
48+ unity_proxy = self.launch_unity()
49+ process_helpers.unlock_unity(unity_proxy)
50+
51+ def test_search(self):
52+ self.main_window.search('Test')
53+ text_field = self.main_window.get_dash()._get_search_text_field()
54+ self.assertEqual(text_field.text, 'Test')
55+ self.assertEqual(text_field.state, 'idle')
56+
57+
4258class DashBaseTestCase(tests.UnityTestCase):
4359
4460 scenarios = tests._get_device_emulation_scenarios()
tests/autopilot/unity8/shell/tests/test_system_integration.py+1−1
@@ -37,5 +37,5 @@ class SystemIntegrationTests(UnityTestCase):
3737 self.launch_unity()
3838
3939 # invoke policykit to check permissions
40− pid = subprocess.check_output("pidof -s unity8", shell=True)
40+ pid = subprocess.check_output(["pidof", "-s", "unity8"], universal_newlines=True)
4141 subprocess.check_call("pkcheck --action-id org.freedesktop.NetworkManager.enable-disable-network --process " + pid, shell=True)
tools/CMakeLists.txt+2
@@ -9,3 +9,5 @@ qt5_use_modules(${SCOPE_TOOL} Qml Quick)
99install(TARGETS ${SCOPE_TOOL}
1010 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
1111 )
12+
13+install(FILES unlock-device DESTINATION ${SHELL_APP_DIR})
tools/unlock-devicenew file+42
@@ -0,0 +1,42 @@
1+#!/bin/bash
2+# -*- Mode: sh; indent-tabs-mode: nil; tab-width: 4 -*-
3+
4+# Our goal here is to get an Ubuntu Touch device into a testable unlocked state.
5+# This will include a reboot.
6+
7+WAIT_COMMAND="sleep 20"
8+
9+while getopts s:w: opt; do
10+ case $opt in
11+ s)
12+ export ANDROID_SERIAL=$OPTARG
13+ ;;
14+ w)
15+ WAIT_COMMAND=$OPTARG
16+ ;;
17+ esac
18+done
19+
20+UNLOCK_SCRIPT='
21+import dbus, logging;
22+from unity8 import process_helpers as helpers;
23+logging.basicConfig(level=logging.INFO);
24+bus = dbus.SystemBus().get_object("com.canonical.powerd", "/com/canonical/powerd");
25+cookie = bus.requestSysState("unlock-device-hold", 1, dbus_interface="com.canonical.powerd");
26+helpers.restart_unity_with_testability();
27+bus.clearSysState(cookie, dbus_interface="com.canonical.powerd");
28+helpers.unlock_unity()
29+'
30+
31+adb reboot
32+sleep 5
33+adb "wait-for-device"
34+eval "$WAIT_COMMAND"
35+UNLOCK_OUTPUT=$(adb shell "sudo -u phablet -i python3 -c '$UNLOCK_SCRIPT'" 2>&1)
36+if echo "$UNLOCK_OUTPUT" | grep 'Greeter unlocked' >/dev/null; then
37+ echo "I: Unlock passed"
38+ exit 0
39+else
40+ echo "I: Unlock failed, script output: '$UNLOCK_OUTPUT'"
41+ exit 1
42+fi