on xenial help sign in
Merge in ~elopio/unity8/use_fake_instead_of_messaging
295ab57Michael Terry
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+
1unity8 (7.85+14.04.20140404-0ubuntu1) trusty; urgency=low
45unity8 (7.85+14.04.20140404-0ubuntu1) trusty; urgency=low
2
46
3 [ Albert Astals ]
47 [ Albert Astals ]
debian/unity8-autopilot.install+1
@@ -1 +1,2 @@
1usr/lib/python*/*/unity*
1usr/lib/python*/*/unity*
2+usr/share/unity8/unlock-device
po/gl.po+1−1
@@ -14,7 +14,7 @@ msgstr ""
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"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"
18"X-Generator: Launchpad (build 16976)\n"
18"X-Generator: Launchpad (build 16976)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
qml/Components/FilterGrid.qml+1
@@ -59,6 +59,7 @@ Item {
59 property alias cellHeight: iconTileGrid.cellHeight
59 property alias cellHeight: iconTileGrid.cellHeight
60 property alias delegateCreationBegin: iconTileGrid.delegateCreationBegin
60 property alias delegateCreationBegin: iconTileGrid.delegateCreationBegin
61 property alias delegateCreationEnd: iconTileGrid.delegateCreationEnd
61 property alias delegateCreationEnd: iconTileGrid.delegateCreationEnd
62+ readonly property alias originY: iconTileGrid.originY
62 readonly property alias flicking: iconTileGrid.flicking
63 readonly property alias flicking: iconTileGrid.flicking
63 readonly property alias moving: iconTileGrid.moving
64 readonly property alias moving: iconTileGrid.moving
64 readonly property alias pressDelay: iconTileGrid.pressDelay
65 readonly property alias pressDelay: iconTileGrid.pressDelay
qml/Components/ResponsiveGridView.qml+1
@@ -40,6 +40,7 @@ Item {
40 readonly property alias flicking: gridView.flicking
40 readonly property alias flicking: gridView.flicking
41 readonly property alias moving: gridView.moving
41 readonly property alias moving: gridView.moving
42 readonly property alias pressDelay: gridView.pressDelay
42 readonly property alias pressDelay: gridView.pressDelay
43+ readonly property alias originY: gridView.originY
43 property alias delegateCreationBegin: gridView.delegateCreationBegin
44 property alias delegateCreationBegin: gridView.delegateCreationBegin
44 property alias delegateCreationEnd: gridView.delegateCreationEnd
45 property alias delegateCreationEnd: gridView.delegateCreationEnd
45 property alias highlightIndex: gridView.highlightIndex
46 property alias highlightIndex: gridView.highlightIndex
qml/Dash/CardFilterGrid.qml+1
@@ -24,6 +24,7 @@ DashRenderer {
24 collapsedHeight: filterGrid.collapsedHeight
24 collapsedHeight: filterGrid.collapsedHeight
25 margins: filterGrid.margins
25 margins: filterGrid.margins
26 uncollapsedHeight: filterGrid.uncollapsedHeight
26 uncollapsedHeight: filterGrid.uncollapsedHeight
27+ originY: filterGrid.originY
27 verticalSpacing: units.gu(1)
28 verticalSpacing: units.gu(1)
28 currentItem: filterGrid.currentItem
29 currentItem: filterGrid.currentItem
29 height: filterGrid.height
30 height: filterGrid.height
qml/Dash/DashContent.qml+10−18
@@ -17,7 +17,6 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Unity 0.2
19import Unity 0.2
20−import Utils 0.1
21import "../Components"
20import "../Components"
22
21
23Item {
22Item {
@@ -189,30 +188,23 @@ Item {
189 width: parent.width
188 width: parent.width
190 style: DashContentTabBarStyle {}
189 style: DashContentTabBarStyle {}
191
190
192− SortFilterProxyModel {
191+ model: dashContentList.model
193− id: tabBarModel
194
192
195− model: dashContentList.model
196−
197− property int selectedIndex: -1
198− onSelectedIndexChanged: {
193+ onSelectedIndexChanged: {
199− if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
194+ if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
200− // TODO This together with the Timer below
195+ // TODO This together with the Timer below
201− // are a workaround for the first tab sometimes not showing the text.
196+ // 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
197+ // But Tabs are going away in the future so not sure if makes
203− // sense invetigating what's the problem at this stage
198+ // sense invetigating what's the problem at this stage
204− selectionModeTimer.restart();
199+ selectionModeTimer.restart();
205− }
206− dashContentList.currentIndex = selectedIndex;
207 }
200 }
201+ dashContentList.currentIndex = selectedIndex;
208 }
202 }
209
203
210− model: tabBarModel.count > 0 ? tabBarModel : null
211−
212 Connections {
204 Connections {
213 target: dashContentList
205 target: dashContentList
214 onCurrentIndexChanged: {
206 onCurrentIndexChanged: {
215− tabBarModel.selectedIndex = dashContentList.currentIndex
207+ tabBar.selectedIndex = dashContentList.currentIndex
216 }
208 }
217 }
209 }
218
210
qml/Dash/DashRenderer.qml+2
@@ -33,6 +33,8 @@ Item {
33
33
34 property var delegateCreationEnd: undefined
34 property var delegateCreationEnd: undefined
35
35
36+ property real originY: 0
37+
36 property real verticalSpacing: 0
38 property real verticalSpacing: 0
37
39
38 // The current item of the renderer
40 // The current item of the renderer
qml/Dash/GenericScopeView.qml+8−8
@@ -247,16 +247,16 @@ FocusScope {
247
247
248 if (item && item.hasOwnProperty("delegateCreationBegin")) {
248 if (item && item.hasOwnProperty("delegateCreationBegin")) {
249 if (baseItem.y + baseItem.height <= 0) {
249 if (baseItem.y + baseItem.height <= 0) {
250− // Not visible (item at top of the list)
250+ // Not visible (item at top of the list viewport)
251− item.delegateCreationBegin = baseItem.height
251+ item.delegateCreationBegin = item.originY + baseItem.height
252− item.delegateCreationEnd = baseItem.height
252+ item.delegateCreationEnd = item.originY + baseItem.height
253 } else if (baseItem.y >= categoryView.height) {
253 } else if (baseItem.y >= categoryView.height) {
254− // Not visible (item at bottom of the list)
254+ // Not visible (item at bottom of the list viewport)
255− item.delegateCreationBegin = 0
255+ item.delegateCreationBegin = item.originY
256− item.delegateCreationEnd = 0
256+ item.delegateCreationEnd = item.originY
257 } else {
257 } else {
258− item.delegateCreationBegin = Math.max(-baseItem.y, 0)
258+ item.delegateCreationBegin = item.originY + Math.max(-baseItem.y, 0)
259− item.delegateCreationEnd = Math.min(categoryView.height + item.delegateCreationBegin, baseItem.height)
259+ item.delegateCreationEnd = item.originY + Math.min(categoryView.height + item.delegateCreationBegin, baseItem.height)
260 }
260 }
261 }
261 }
262 }
262 }
qml/Notifications/NotificationMenuItemFactory.qml+2−1
@@ -66,7 +66,8 @@ Loader {
66 TextField {
66 TextField {
67 id: textfield
67 id: textfield
68
68
69+ // TODO using Qt.ImhNoPredictiveText here until lp #1291575 is fixed for ubuntu-ui-toolkit
69− inputMethodHints: Qt.ImhNoAutoUppercase
70+ inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
70 anchors.left: parent.left; anchors.right: parent.right
71 anchors.left: parent.left; anchors.right: parent.right
71 echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
72 echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
72 height: units.gu(5)
73 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 @@
21
21
22from __future__ import absolute_import
22from __future__ import absolute_import
23
23
24−from unity8.process_helpers import lock_unity, unlock_unity
24+import logging
25−from unity8.shell import disable_qml_mocking
25+import os
26−from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
27
26
28from autopilot.matchers import Eventually
27from autopilot.matchers import Eventually
29from autopilot.platform import model
28from autopilot.platform import model
30−from testtools.matchers import Equals, NotEquals
29+from testtools.matchers import Equals
31
30
32−import logging
31+from unity8 import process_helpers
33−import subprocess
32+from unity8.application_lifecycle import tests
34
33
35−logger = logging.getLogger(__name__)
36
34
35+logger = logging.getLogger(__name__)
37
36
38−class ApplicationLifecycleTests(UnityTestCase):
39
37
40− scenarios = _get_device_emulation_scenarios()
38+class ApplicationLifecycleTests(tests.ApplicationLifeCycleTestCase):
41
39
42 def setUp(self):
40 def setUp(self):
41+ if model() == 'Desktop':
42+ self.skipTest('Test cannot be run on the desktop.')
43 super(ApplicationLifecycleTests, self).setUp()
43 super(ApplicationLifecycleTests, self).setUp()
44− if model() == "Desktop":
45− self.skipTest("Test cannot be run on the desktop.")
46
44
47 def swipe_screen_from_right(self):
45 def swipe_screen_from_right(self):
48 width = self.main_window.width
46 width = self.main_window.width
@@ -55,142 +53,65 @@ class ApplicationLifecycleTests(UnityTestCase):
55 logger.info("Swiping screen from the right edge")
53 logger.info("Swiping screen from the right edge")
56 self.touch.drag(start_x, start_y, end_x, end_y)
54 self.touch.drag(start_x, start_y, end_x, end_y)
57
55
58− def swipe_screen_from_left(self):
56+ def launch_fake_app(self):
59− width = self.main_window.width
57+ _, desktop_file_path = self.create_test_application()
60− height = self.main_window.height
58+ desktop_file_name = os.path.basename(desktop_file_path)
61− start_x = 0
59+ application_name, _ = os.path.splitext(desktop_file_name)
62− start_y = int(height/2)
60+ self.launch_upstart_application(application_name)
63− end_x = width
61+ return application_name
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
74
62
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
97 def test_can_launch_application(self):
63 def test_can_launch_application(self):
98 """Must be able to launch an application."""
64 """Must be able to launch an application."""
99− unity_proxy = self.launch_unity()
65+ application_name = self.launch_fake_app()
100− unlock_unity(unity_proxy)
66+ self.assert_current_focused_application(application_name)
101
67
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
109 def test_can_launch_multiple_applications(self):
68 def test_can_launch_multiple_applications(self):
110 """A second application launched must be focused."""
69 """A second application launched must be focused."""
111− unity_proxy = self.launch_unity()
70+ application1_name = self.launch_fake_app()
112− unlock_unity(unity_proxy)
71+ self.assert_current_focused_application(application1_name)
113−
72+
114− self._launch_app("messaging-app")
73+ application2_name = self.launch_fake_app()
115− self.assertThat(
74+ self.assertFalse(application1_name == application2_name)
116− self.main_window.get_current_focused_app_id(),
75+ self.assert_current_focused_application(application2_name)
117− Eventually(Equals("messaging-app"))
76+
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
127 def test_app_moves_from_unfocused_to_focused(self):
77 def test_app_moves_from_unfocused_to_focused(self):
128 """An application that is in the unfocused state must be able to be
78 """An application that is in the unfocused state must be able to be
129 brought back to the focused state.
79 brought back to the focused state.
130
80
131 """
81 """
132− unity_proxy = self.launch_unity()
82+ application1_name = self.launch_fake_app()
133− unlock_unity(unity_proxy)
83+ self.assert_current_focused_application(application1_name)
134−
84+
135− self._launch_app("messaging-app")
85+ application2_name = self.launch_fake_app()
136− self.assertThat(
86+ self.assertFalse(application1_name == application2_name)
137− self.main_window.get_current_focused_app_id(),
87+ self.assert_current_focused_application(application2_name)
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− )
147
88
148 self.swipe_screen_from_right()
89 self.swipe_screen_from_right()
149
90
150− self.assertThat(
91+ self.assert_current_focused_application(application1_name)
151− self.main_window.get_current_focused_app_id(),
152− Eventually(Equals("messaging-app"))
153− )
154
92
155− @disable_qml_mocking
156 def test_greeter_hides_on_app_open(self):
93 def test_greeter_hides_on_app_open(self):
157 """Greeter should hide when an app is opened"""
94 """Greeter should hide when an app is opened"""
158− unity_proxy = self.launch_unity()
95+ process_helpers.lock_unity()
159 greeter = self.main_window.get_greeter()
96 greeter = self.main_window.get_greeter()
160 self.assertThat(greeter.created, Eventually(Equals(True)))
97 self.assertThat(greeter.created, Eventually(Equals(True)))
161
98
162− self._launch_app("messaging-app")
99+ application_name = self.launch_fake_app()
163 self.assertThat(greeter.created, Eventually(Equals(False)))
100 self.assertThat(greeter.created, Eventually(Equals(False)))
164− self.assertThat(
101+ self.assert_current_focused_application(application_name)
165− self.main_window.get_current_focused_app_id(),
166− Eventually(Equals("messaging-app"))
167− )
168
102
169− @disable_qml_mocking
170 def test_greeter_hides_on_app_focus(self):
103 def test_greeter_hides_on_app_focus(self):
171 """Greeter should hide when an app is re-focused"""
104 """Greeter should hide when an app is re-focused"""
172− unity_proxy = self.launch_unity()
105+ application_name = self.launch_fake_app()
173− greeter = self.main_window.get_greeter()
106+ self.assert_current_focused_application(application_name)
174− unlock_unity(unity_proxy)
175
107
176− self._launch_app("messaging-app")
108+ self.main_window.show_dash_swiping()
177− self.assertThat(
109+ self.assert_current_focused_application('')
178− self.main_window.get_current_focused_app_id(),
179− Eventually(Equals("messaging-app"))
180− )
181
110
182− self.swipe_screen_from_left()
111+ process_helpers.lock_unity()
183− self.assertThat(
184− self.main_window.get_current_focused_app_id(),
112+ greeter = self.main_window.get_greeter()
185− Eventually(Equals(''))
186− )
187−
188− lock_unity()
189 self.assertThat(greeter.created, Eventually(Equals(True)))
113 self.assertThat(greeter.created, Eventually(Equals(True)))
190
114
191− self._launch_app("messaging-app")
115+ self.launch_upstart_application(application_name)
192 self.assertThat(greeter.created, Eventually(Equals(False)))
116 self.assertThat(greeter.created, Eventually(Equals(False)))
193− self.assertThat(
117+ self.assert_current_focused_application(application_name)
194− self.main_window.get_current_focused_app_id(),
195− Eventually(Equals("messaging-app"))
196− )
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+8−39
@@ -20,48 +20,19 @@
20"""Test the integration with the URL dispatcher service."""
20"""Test the integration with the URL dispatcher service."""
21
21
22import os
22import os
23+import subprocess
23
24
24from autopilot import platform
25from autopilot import platform
25−from autopilot.matchers import Eventually
26−from testtools.matchers import Equals
27−from ubuntuuitoolkit import fixture_setup
28
26
29−from unity8 import process_helpers
27+from unity8.application_lifecycle import tests
30−from unity8.shell import tests
31
28
32
29
33−class URLDispatcherTestCase(tests.UnityTestCase):
30+class URLDispatcherTestCase(tests.ApplicationLifeCycleTestCase):
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−""")
50
31
51 def setUp(self):
32 def setUp(self):
52 if platform.model() == 'Desktop':
33 if platform.model() == 'Desktop':
53 self.skipTest("URL dispatcher doesn't work on the desktop.")
34 self.skipTest("URL dispatcher doesn't work on the desktop.")
54 super(URLDispatcherTestCase, self).setUp()
35 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)
65
36
66 def test_swipe_out_application_started_by_url_dispatcher(self):
37 def test_swipe_out_application_started_by_url_dispatcher(self):
67 _, desktop_file_path = self.create_test_application()
38 _, desktop_file_path = self.create_test_application()
@@ -70,12 +41,10 @@ MainView {
70
41
71 self.assertEqual('', self.main_window.get_current_focused_app_id())
42 self.assertEqual('', self.main_window.get_current_focused_app_id())
72 self.addCleanup(os.system, 'pkill qmlscene')
43 self.addCleanup(os.system, 'pkill qmlscene')
44+
45+ subprocess.check_call(
73− os.system('url-dispatcher application:///{}'.format(desktop_file_name))
46+ ['url-dispatcher', 'application:///{}'.format(desktop_file_name)])
74− self.assertThat(
47+ self.assert_current_focused_application(application_name)
75− self.main_window.get_current_focused_app_id,
76− Eventually(Equals(application_name)))
77
48
78 self.main_window.show_dash_swiping()
49 self.main_window.show_dash_swiping()
79− self.assertThat(
50+ self.assert_current_focused_application('')
80− self.main_window.get_current_focused_app_id,
81− Eventually(Equals('')))
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 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
2#
3−# Unity - Indicators Autopilot Test Suite
3+# Unity Indicators Autopilot Test Suite
4−# Copyright (C) 2013 Canonical
4+# Copyright (C) 2013, 2014 Canonical
5#
5#
6# This program is free software: you can redistribute it and/or modify
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
7# it under the terms of the GNU General Public License as published by
@@ -15,20 +15,32 @@
15#
15#
16# You should have received a copy of the GNU General Public License
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/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18−#
19
18
20from __future__ import absolute_import
19from __future__ import absolute_import
21
20
21+from testscenarios import multiply_scenarios
22+
22from autopilot import platform
23from autopilot import platform
23−from testtools import skipIf
24
24
25from unity8.process_helpers import unlock_unity
25from unity8.process_helpers import unlock_unity
26−from unity8.shell.tests import UnityTestCase
26+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
27
27
28
28
29class IndicatorTestCase(UnityTestCase):
29class IndicatorTestCase(UnityTestCase):
30
30
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 = [
32 ('Bluetooth', dict(indicator_name='indicator-bluetooth')),
44 ('Bluetooth', dict(indicator_name='indicator-bluetooth')),
33 ('Datetime', dict(indicator_name='indicator-datetime')),
45 ('Datetime', dict(indicator_name='indicator-datetime')),
34 ('Location', dict(indicator_name='indicator-location')),
46 ('Location', dict(indicator_name='indicator-location')),
@@ -37,14 +49,58 @@ class IndicatorTestCase(UnityTestCase):
37 ('Power', dict(indicator_name='indicator-power')),
49 ('Power', dict(indicator_name='indicator-power')),
38 ('Sound', dict(indicator_name='indicator-sound')),
50 ('Sound', dict(indicator_name='indicator-sound')),
39 ]
51 ]
52+ scenarios = multiply_scenarios(
53+ indicator_scenarios,
54+ IndicatorTestCase.device_emulation_scenarios
55+ )
40
56
41− @skipIf(platform.image_codename() == 'Desktop',
42− "Unity8/phablet-only test!")
43 def setUp(self):
57 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.')
45
62
46 def test_indicator_exists(self):
63 def test_indicator_exists(self):
47− unity_proxy = self.launch_unity()
64+ self.main_window._get_indicator_widget(
48− unlock_unity(unity_proxy)
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(
49− indicator = self.main_window.get_indicator(self.indicator_name)
104+ self.indicator_name)
50− self.assertIsNotNone(indicator)
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):
89 break
89 break
90
90
91
91
92−def lock_unity():
92+def lock_unity(unity_proxy_obj=None):
93+ """Helper function that attempts to lock the unity greeter."""
93 import evdev, time
94 import evdev, time
94 uinput = evdev.UInput(name='unity8-autopilot-power-button',
95 uinput = evdev.UInput(name='unity8-autopilot-power-button',
95 devnode='/dev/autopilot-uinput')
96 devnode='/dev/autopilot-uinput')
tests/autopilot/unity8/shell/emulators/__init__.py+2−6
@@ -17,16 +17,12 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
18#
19
19
20−from autopilot import input, introspection
20+from ubuntuuitoolkit import emulators as toolkit_emulators
21
21
22
22
23−class UnityEmulatorBase(introspection.CustomEmulatorBase):
23+class UnityEmulatorBase(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
24 """A base class for all unity emulators."""
24 """A base class for all unity emulators."""
25
25
26− def __init__(self, *args):
27− super(UnityEmulatorBase, self).__init__(*args)
28− self.pointing_device = input.Pointer(device=input.Touch.create())
29−
30
26
31class UnityEmulatorException(Exception):
27class UnityEmulatorException(Exception):
32 """Exception raised when there is an error with the Unity emulators."""
28 """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
23
23
24from autopilot import logging as autopilot_logging
24from autopilot import logging as autopilot_logging
25from autopilot.introspection import dbus
25from autopilot.introspection import dbus
26+from testtools.matchers import MatchesAny, Equals
27+from ubuntuuitoolkit import emulators as toolkit_emulators
26
28
27
29
28logger = logging.getLogger(__name__)
30logger = logging.getLogger(__name__)
@@ -132,6 +134,19 @@ class Dash(emulators.UnityEmulatorBase):
132 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
134 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
133 self.dash_content_list.currentIndex.wait_for(original_index + 1)
135 self.dash_content_list.currentIndex.wait_for(original_index + 1)
134
136
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+
135
150
136class GenericScopeView(emulators.UnityEmulatorBase):
151class GenericScopeView(emulators.UnityEmulatorBase):
137 """Autopilot emulator for generic scopes."""
152 """Autopilot emulator for generic scopes."""
tests/autopilot/unity8/shell/emulators/main_window.py+32−2
@@ -20,6 +20,7 @@
20import logging
20import logging
21
21
22from autopilot import logging as autopilot_logging
22from autopilot import logging as autopilot_logging
23+from autopilot import input
23
24
24from unity8.shell import emulators
25from unity8.shell import emulators
25from unity8.shell.emulators.greeter import Greeter
26from unity8.shell.emulators.greeter import Greeter
@@ -87,12 +88,32 @@ class QQuickView(emulators.UnityEmulatorBase):
87 def get_pinentryField(self):
88 def get_pinentryField(self):
88 return self.select_single(objectName="pinentryField")
89 return self.select_single(objectName="pinentryField")
89
90
90− def get_indicator(self, indicator_name):
91+ def _get_indicator_widget(self, indicator_name):
91− return self.wait_select_single(
92+ return self.select_single(
92 'DefaultIndicatorWidget',
93 'DefaultIndicatorWidget',
93 objectName=indicator_name+'-widget'
94 objectName=indicator_name+'-widget'
94 )
95 )
95
96
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+
96 def get_shell_background(self):
117 def get_shell_background(self):
97 return self.select_single(
118 return self.select_single(
98 "CrossFadeImage", objectName="backgroundImage")
119 "CrossFadeImage", objectName="backgroundImage")
@@ -113,3 +134,12 @@ class QQuickView(emulators.UnityEmulatorBase):
113 def get_current_focused_app_id(self):
134 def get_current_focused_app_id(self):
114 """Return the id of the focused application."""
135 """Return the id of the focused application."""
115 return self.select_single('Shell').focusedApplicationId
136 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
39from unity8.shell.emulators import dash as dash_emulators
39from unity8.shell.emulators import dash as dash_emulators
40
40
41
41
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+
42class DashBaseTestCase(tests.UnityTestCase):
58class DashBaseTestCase(tests.UnityTestCase):
43
59
44 scenarios = tests._get_device_emulation_scenarios()
60 scenarios = tests._get_device_emulation_scenarios()
tests/autopilot/unity8/shell/tests/test_system_integration.py+1−1
@@ -37,5 +37,5 @@ class SystemIntegrationTests(UnityTestCase):
37 self.launch_unity()
37 self.launch_unity()
38
38
39 # invoke policykit to check permissions
39 # 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)
41 subprocess.check_call("pkcheck --action-id org.freedesktop.NetworkManager.enable-disable-network --process " + pid, shell=True)
41 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)
9install(TARGETS ${SCOPE_TOOL}
9install(TARGETS ${SCOPE_TOOL}
10 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
10 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
11 )
11 )
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