on xenial help sign in
Add some tests
commit17570290c6a1addb7ec3ce1036e87b0aa744c8ef authorMichael Terry <michael.terry@canonical.com> dateThu 11 Sep 2014, 15:05 (12 years ago) parentf89c252
4 files changed+322−2
qml/Shell.qml+4−2 tests/qmltests/CMakeLists.txt+1 tests/qmltests/tst_ShellWithPin.qml+32 tests/qmltests/tst_TabletShell.qml+285
qml/Shell.qml+4−2
@@ -178,10 +178,12 @@ Item {
178178
179179 Loader {
180180 id: applicationsDisplayLoader
181+ objectName: "applicationsDisplayLoader"
181182 anchors.fill: parent
182183
183184 // When we have a locked app, we only want to show that one app
184− source: (shell.sideStageEnabled && !greeter.hasLockedApp) ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
185+ property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
186+ source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
185187
186188 Binding {
187189 target: applicationsDisplayLoader.item
@@ -399,7 +401,7 @@ Item {
399401 }
400402
401403 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
402− onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
404+ onShowProgressChanged: if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
403405
404406 Greeter {
405407 id: greeter
tests/qmltests/CMakeLists.txt+1
@@ -21,6 +21,7 @@ set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
2121
2222add_qml_test(. Shell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
2323add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single-pin")
24+add_qml_test(. TabletShell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
2425add_qml_test(Components Background)
2526add_qml_test(Components Carousel)
2627add_qml_test(Components DraggingArea)
tests/qmltests/tst_ShellWithPin.qml+32
@@ -87,6 +87,7 @@ Item {
8787 }
8888
8989 function init() {
90+ shell.tablet = false
9091 swipeAwayGreeter()
9192 shell.failedLoginsDelayAttempts = -1
9293 maxRetriesTextField.text = "-1"
@@ -253,5 +254,36 @@ Item {
253254 enterPin("1111")
254255 tryCompare(resetSpy, "count", 1)
255256 }
257+
258+ function test_emergencyDialerLockOut() {
259+ // This is a theoretical attack on the lockscreen: Enter emergency
260+ // dialer mode on a phone, then plug into a larger screen,
261+ // switching to a tablet interface. This would in theory move the
262+ // dialer to a side stage and give access to other apps. So just
263+ // confirm that such an attack doesn't work.
264+
265+ var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader")
266+
267+ // We start in phone mode
268+ tryCompare(shell, "sideStageEnabled", false)
269+ tryCompare(applicationsDisplayLoader, "tabletMode", false)
270+
271+ var app = ApplicationManager.startApplication("dialer-app")
272+
273+ var greeter = findChild(shell, "greeter")
274+ tryCompare(greeter, "showProgress", 0)
275+ tryCompare(greeter, "hasLockedApp", true)
276+
277+ // OK, we're in. Now try (but fail) to switch to tablet mode
278+ shell.tablet = true
279+ tryCompare(shell, "sideStageEnabled", true)
280+ tryCompare(applicationsDisplayLoader, "tabletMode", false)
281+
282+ // And when we kill the app, we go back to locked tablet mode
283+ killApps()
284+ tryCompare(greeter, "showProgress", 1)
285+ tryCompare(shell, "sideStageEnabled", true)
286+ tryCompare(applicationsDisplayLoader, "tabletMode", true)
287+ }
256288 }
257289}
tests/qmltests/tst_TabletShell.qmlnew file+285
@@ -0,0 +1,285 @@
1+/*
2+ * Copyright (C) 2013,2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import GSettings 1.0
20+import LightDM 0.1 as LightDM
21+import Ubuntu.Components 1.1
22+import Ubuntu.Telephony 0.1 as Telephony
23+import Unity.Application 0.1
24+import Unity.Connectivity 0.1
25+import Unity.Test 0.1 as UT
26+import Powerd 0.1
27+
28+import "../../qml"
29+
30+Row {
31+ id: root
32+ spacing: 0
33+
34+ QtObject {
35+ id: applicationArguments
36+
37+ function hasGeometry() {
38+ return false
39+ }
40+
41+ function width() {
42+ return 0
43+ }
44+
45+ function height() {
46+ return 0
47+ }
48+ }
49+
50+ Loader {
51+ id: shellLoader
52+
53+ width: units.gu(100)
54+ height: units.gu(80)
55+
56+ property bool itemDestroyed: false
57+ sourceComponent: Component {
58+ Shell {
59+ Component.onDestruction: {
60+ shellLoader.itemDestroyed = true
61+ }
62+ }
63+ }
64+ }
65+
66+ Rectangle {
67+ color: "white"
68+ width: units.gu(20)
69+ height: shellLoader.height
70+
71+ Column {
72+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
73+ spacing: units.gu(1)
74+ Row {
75+ anchors { left: parent.left; right: parent.right }
76+ Button {
77+ text: "Show Greeter"
78+ onClicked: {
79+ if (shellLoader.status !== Loader.Ready)
80+ return
81+
82+ var greeter = testCase.findChild(shellLoader.item, "greeter")
83+ if (!greeter.shown) {
84+ greeter.show()
85+ }
86+ }
87+ }
88+ }
89+ }
90+ }
91+
92+ SignalSpy {
93+ id: sessionSpy
94+ signalName: "sessionStarted"
95+ }
96+
97+ SignalSpy {
98+ id: dashCommunicatorSpy
99+ signalName: "setCurrentScopeCalled"
100+ }
101+
102+ SignalSpy {
103+ id: unlockAllModemsSpy
104+ target: Connectivity
105+ signalName: "unlockingAllModems"
106+ }
107+
108+ Telephony.CallEntry {
109+ id: phoneCall
110+ phoneNumber: "+447812221111"
111+ }
112+
113+ UT.UnityTestCase {
114+ id: testCase
115+ name: "Shell"
116+ when: windowShown
117+
118+ property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null
119+
120+ function init() {
121+ sessionSpy.clear()
122+ sessionSpy.target = findChild(shell, "greeter")
123+ dashCommunicatorSpy.target = findInvisibleChild(shell, "dashCommunicator")
124+ }
125+
126+ function cleanup() {
127+ shellLoader.itemDestroyed = false
128+
129+ shellLoader.active = false
130+
131+ tryCompare(shellLoader, "status", Loader.Null)
132+ tryCompare(shellLoader, "item", null)
133+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
134+ // item might still be alive. So if we set Loader.active back to true
135+ // again right now we will get the very same Shell instance back. So no reload
136+ // actually took place. Likely because Loader waits until the next event loop
137+ // iteration to do its work. So to ensure the reload, we will wait until the
138+ // Shell instance gets destroyed.
139+ tryCompare(shellLoader, "itemDestroyed", true)
140+
141+ // kill all (fake) running apps
142+ killApps(ApplicationManager)
143+
144+ unlockAllModemsSpy.clear()
145+
146+ // reload our test subject to get it in a fresh state once again
147+ shellLoader.active = true
148+
149+ tryCompare(shellLoader, "status", Loader.Ready)
150+ removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item)
151+ }
152+
153+ function killApps() {
154+ while (ApplicationManager.count > 1) {
155+ var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0
156+ ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId)
157+ }
158+ compare(ApplicationManager.count, 1)
159+ }
160+
161+ function selectIndex(i) {
162+ // We could be anywhere in list; find target index to know which direction
163+ var greeter = findChild(shell, "greeter")
164+ var userlist = findChild(greeter, "userList")
165+ if (userlist.currentIndex == i)
166+ keyClick(Qt.Key_Escape) // Reset state if we're not moving
167+ while (userlist.currentIndex != i) {
168+ var next = userlist.currentIndex + 1
169+ if (userlist.currentIndex > i) {
170+ next = userlist.currentIndex - 1
171+ }
172+ var account = findChild(greeter, "username"+next)
173+ mouseClick(account, 1, 1)
174+ tryCompare(userlist, "currentIndex", next)
175+ tryCompare(userlist, "movingInternally", false)
176+ }
177+ }
178+
179+ function selectUser(name) {
180+ // Find index of user with the right name
181+ var greeter = findChild(shell, "greeter")
182+ for (var i = 0; i < greeter.model.count; i++) {
183+ if (greeter.model.data(i, LightDM.UserRoles.NameRole) == name) {
184+ break
185+ }
186+ }
187+ if (i == greeter.model.count) {
188+ fail("Didn't find name")
189+ return -1
190+ }
191+ selectIndex(i)
192+ return i
193+ }
194+
195+ function clickPasswordInput() {
196+ var greeter = findChild(shell, "greeter")
197+ tryCompare(greeter, "showProgress", 1)
198+
199+ var passwordInput = findChild(shell, "passwordInput")
200+ mouseClick(passwordInput, passwordInput.width / 2, passwordInput.height / 2)
201+ }
202+
203+ function confirmLoggedIn(loggedIn) {
204+ var greeter = findChild(shell, "greeter")
205+ tryCompare(greeter, "showProgress", loggedIn ? 0 : 1)
206+ tryCompare(sessionSpy, "count", loggedIn ? 1 : 0)
207+ }
208+
209+ function swipeFromLeftEdge(swipeLength) {
210+ var touchStartX = 2
211+ var touchStartY = shell.height / 2
212+ touchFlick(shell, touchStartX, touchStartY, swipeLength, touchStartY)
213+ }
214+
215+ function test_noLockscreen() {
216+ selectUser("has-password")
217+ var lockscreen = findChild(shell, "lockscreen")
218+ tryCompare(lockscreen, "shown", false)
219+ }
220+
221+ function test_showAndHideGreeterDBusCalls() {
222+ var greeter = findChild(shell, "greeter")
223+ LightDM.Greeter.hideGreeter()
224+ tryCompare(greeter, "showProgress", 0)
225+ LightDM.Greeter.showGreeter()
226+ tryCompare(greeter, "showProgress", 1)
227+ }
228+
229+ function test_login_data() {
230+ return [
231+ //{tag: "auth error", user: "auth-error", loggedIn: false, password: ""},
232+ //{tag: "without password", user: "no-password", loggedIn: true, password: ""},
233+ {tag: "with password", user: "has-password", loggedIn: true, password: "password"},
234+ ]
235+ }
236+
237+ function test_login(data) {
238+ selectUser(data.user)
239+
240+ clickPasswordInput()
241+
242+ if (data.password !== "") {
243+ typeString(data.password)
244+ keyClick(Qt.Key_Enter)
245+ }
246+
247+ confirmLoggedIn(data.loggedIn)
248+ }
249+
250+ function test_appLaunchDuringGreeter_data() {
251+ return [
252+ {tag: "auth error", user: "auth-error", loggedIn: false, passwordFocus: false},
253+ {tag: "without password", user: "no-password", loggedIn: true, passwordFocus: false},
254+ {tag: "with password", user: "has-password", loggedIn: false, passwordFocus: true},
255+ ]
256+ }
257+
258+ function test_appLaunchDuringGreeter(data) {
259+ selectUser(data.user)
260+
261+ var greeter = findChild(shell, "greeter")
262+ var app = ApplicationManager.startApplication("dialer-app")
263+
264+ confirmLoggedIn(data.loggedIn)
265+
266+ if (data.passwordFocus) {
267+ var passwordInput = findChild(greeter, "passwordInput")
268+ tryCompare(passwordInput, "focus", true)
269+ }
270+ }
271+
272+ function test_leftEdgeDrag_data() {
273+ return [
274+ {tag: "without password", user: "no-password", loggedIn: true},
275+ {tag: "with password", user: "has-password", loggedIn: false},
276+ ]
277+ }
278+
279+ function test_leftEdgeDrag(data) {
280+ selectUser(data.user)
281+ swipeFromLeftEdge(shell.width * 0.75)
282+ confirmLoggedIn(data.loggedIn)
283+ }
284+ }
285+}