on ab2f849 help sign in
unity8/tests/qmltests/tst_ShellWithPin.qml
560 lines 20 kB history raw
1/*
2 * Copyright (C) 2014-2016 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 */
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import QtTest 1.0
20import AccountsService 0.1
21import GSettings 1.0
22import LightDM.IntegratedLightDM 0.1 as LightDM
23import Ubuntu.SystemImage 0.1
24import Ubuntu.Telephony 0.1 as Telephony
25import Unity.Application 0.1
26import Unity.Test 0.1 as UT
27import Powerd 0.1
29import "../../qml"
31Item {
32 id: root
33 width: contentRow.width
34 height: contentRow.height
36 Component.onCompleted: {
37 // must set the mock mode before loading the Shell
38 LightDM.Greeter.mockMode = "single-pin";
39 LightDM.Users.mockMode = "single-pin";
40 shellLoader.active = true;
41 }
43 QtObject {
44 id: applicationArguments
46 function hasGeometry() {
47 return false;
48 }
50 function width() {
51 return 0;
52 }
54 function height() {
55 return 0;
56 }
57 }
59 Row {
60 id: contentRow
62 Loader {
63 id: shellLoader
64 active: false
66 width: units.gu(40)
67 height: units.gu(71)
69 property bool itemDestroyed: false
70 sourceComponent: Component {
71 Shell {
72 Component.onDestruction: {
73 shellLoader.itemDestroyed = true
74 }
75 }
76 }
77 }
79 Rectangle {
80 color: "white"
81 width: units.gu(30)
82 height: shellLoader.height
84 Column {
85 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
86 spacing: units.gu(1)
87 Button {
88 anchors { left: parent.left; right: parent.right }
89 text: "Show Greeter"
90 onClicked: LightDM.Greeter.showGreeter()
91 }
93 Label {
94 text: "Max retries:"
95 color: "black"
96 }
97 TextField {
98 id: maxRetriesTextField
99 text: "-1"
100 onTextChanged: {
101 var greeter = testCase.findChild(shellLoader.item, "greeter");
102 greeter.maxFailedLogins = text;
103 }
104 }
105 }
106 }
107 }
109 SignalSpy {
110 id: sessionSpy
111 signalName: "sessionStarted"
112 }
114 SignalSpy {
115 id: resetSpy
116 target: SystemImage
117 signalName: "resettingDevice"
118 }
120 SignalSpy {
121 id: promptSpy
122 target: LightDM.Greeter
123 signalName: "showPrompt"
124 }
126 Telephony.CallEntry {
127 id: phoneCall
128 phoneNumber: "+447812221111"
129 }
131 Item {
132 id: fakeDismissTimer
133 property bool running: false
134 signal triggered
136 function stop() {
137 running = false;
138 }
140 function restart() {
141 running = true;
142 }
143 }
145 UT.StageTestCase {
146 id: testCase
147 name: "ShellWithPin"
148 when: windowShown
150 property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null
152 function init() {
153 tryCompare(shell, "waitingOnGreeter", false); // will be set when greeter is all ready
154 var greeter = findChild(shell, "greeter");
155 sessionSpy.target = greeter;
156 swipeAwayGreeter(true);
157 greeter.failedLoginsDelayAttempts = -1;
158 greeter.maxFailedLogins = -1;
160 var launcher = findChild(shell, "launcher");
161 var panel = findChild(launcher, "launcherPanel");
162 verify(!!panel);
163 panel.dismissTimer = fakeDismissTimer;
165 // from StageTestCase
166 stage = findChild(shell, "stage");
167 topLevelSurfaceList = findInvisibleChild(shell, "topLevelSurfaceList");
168 verify(topLevelSurfaceList);
170 startApplication("unity8-dash");
171 }
173 function cleanup() {
174 tryCompare(shell, "waitingOnGreeter", false); // make sure greeter didn't leave us in disabled state
176 topLevelSurfaceList = null;
178 shellLoader.itemDestroyed = false
180 shellLoader.active = false
182 tryCompare(shellLoader, "status", Loader.Null)
183 tryCompare(shellLoader, "item", null)
184 // Loader.status might be Loader.Null and Loader.item might be null but the Loader
185 // item might still be alive. So if we set Loader.active back to true
186 // again right now we will get the very same Shell instance back. So no reload
187 // actually took place. Likely because Loader waits until the next event loop
188 // iteration to do its work. So to ensure the reload, we will wait until the
189 // Shell instance gets destroyed.
190 tryCompare(shellLoader, "itemDestroyed", true)
192 // kill all (fake) running apps
193 killApps()
195 AccountsService.enableLauncherWhileLocked = true
196 AccountsService.enableIndicatorsWhileLocked = true
197 AccountsService.demoEdges = false
198 callManager.foregroundCall = null
199 LightDM.Greeter.authenticate(""); // reset greeter
201 // reload our test subject to get it in a fresh state once again
202 shellLoader.active = true
204 tryCompare(shellLoader, "status", Loader.Ready)
205 removeTimeConstraintsFromSwipeAreas(shellLoader.item)
206 }
208 function swipeAwayGreeter(waitForCoverPage) {
209 var greeter = findChild(shell, "greeter");
210 waitForRendering(greeter)
211 var coverPage = findChild(shell, "coverPage");
212 tryCompare(coverPage, "showProgress", 1);
214 var touchX = shell.width - (shell.edgeSize / 2);
215 var touchY = shell.height / 2;
216 touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
218 if (waitForCoverPage) {
219 // wait until the animation has finished
220 var coverPage = findChild(shell, "coverPage");
221 tryCompare(coverPage, "showProgress", 0);
222 }
223 }
225 function enterPin(pin) {
226 typeString(pin);
227 }
229 function showGreeter() {
230 LightDM.Greeter.showGreeter();
231 tryCompare(shell, "waitingOnGreeter", false);
232 var coverPage = findChild(shell, "coverPage");
233 tryCompare(coverPage, "showProgress", 1);
234 removeTimeConstraintsFromSwipeAreas(shell);
235 }
237 function confirmLockedApp(app) {
238 var greeter = findChild(shell, "greeter")
239 tryCompare(greeter, "shown", false)
240 tryCompare(greeter, "hasLockedApp", true)
241 tryCompare(greeter, "lockedApp", app)
242 tryCompare(LightDM.Greeter, "active", true)
243 tryCompare(ApplicationManager, "focusedApplicationId", app)
244 }
246 function test_greeterChangesIndicatorProfile() {
247 skip("Not supported yet, waiting on design for new settings panel");
249 var panel = findChild(shell, "panel");
250 tryCompare(panel.indicators.indicatorsModel, "profile", shell.indicatorProfile + "_greeter");
252 LightDM.Greeter.hideGreeter();
253 tryCompare(panel.indicators.indicatorsModel, "profile", shell.indicatorProfile);
255 showGreeter();
256 tryCompare(panel.indicators.indicatorsModel, "profile", shell.indicatorProfile + "_greeter");
258 LightDM.Greeter.hideGreeter();
259 tryCompare(panel.indicators.indicatorsModel, "profile", shell.indicatorProfile);
260 }
262 function test_login() {
263 sessionSpy.clear()
264 tryCompare(sessionSpy, "count", 0)
265 enterPin("1234")
266 tryCompare(sessionSpy, "count", 1)
267 }
269 function test_disabledEdges() {
270 var launcher = findChild(shell, "launcher")
271 tryCompare(launcher, "available", true)
272 AccountsService.enableLauncherWhileLocked = false
273 tryCompare(launcher, "available", false)
275 var indicators = findChild(shell, "indicators")
276 tryCompare(indicators, "available", true)
277 AccountsService.enableIndicatorsWhileLocked = false
278 tryCompare(indicators, "available", false)
279 }
281 function test_emergencyCall() {
282 var greeter = findChild(shell, "greeter")
283 var panel = findChild(shell, "panel")
284 var indicators = findChild(shell, "indicators")
285 var launcher = findChild(shell, "launcher")
286 var stage = findChild(shell, "stage")
288 tap(findChild(greeter, "emergencyCallLabel"));
290 tryCompare(greeter, "lockedApp", "dialer-app")
291 tryCompare(greeter, "hasLockedApp", true)
292 tryCompare(greeter, "shown", false);
293 tryCompare(panel, "fullscreenMode", true)
294 tryCompare(indicators, "available", false)
295 tryCompare(launcher, "available", false)
296 tryCompare(stage, "spreadEnabled", false)
298 // Cancel emergency mode, and go back to normal
299 waitForRendering(greeter)
300 showGreeter()
302 tryCompare(greeter, "shown", true)
303 tryCompare(greeter, "lockedApp", "")
304 tryCompare(greeter, "hasLockedApp", false)
305 tryCompare(greeter, "fullyShown", true);
306 tryCompare(panel, "fullscreenMode", false)
307 tryCompare(indicators, "available", true)
308 tryCompare(launcher, "available", true)
309 tryCompare(stage, "spreadEnabled", false)
310 }
312 function test_emergencyCallCrash() {
313 var dialerSurfaceId = topLevelSurfaceList.nextId;
314 var greeter = findChild(shell, "greeter");
315 var emergencyButton = findChild(greeter, "emergencyCallLabel");
316 tap(emergencyButton)
317 tryCompare(topLevelSurfaceList, "count", 2);
318 waitUntilAppWindowIsFullyLoaded(dialerSurfaceId);
320 tryCompare(greeter, "shown", false);
321 ApplicationManager.stopApplication("dialer-app"); // kill dialer-app, as if it crashed
322 tryCompare(greeter, "shown", true);
323 tryCompare(findChild(greeter, "lockscreen"), "shown", true);
324 tryCompare(findChild(greeter, "coverPage"), "shown", false);
325 }
327 function test_emergencyCallAppLaunch() {
328 var greeter = findChild(shell, "greeter");
329 var emergencyButton = findChild(greeter, "emergencyCallLabel");
330 tap(emergencyButton)
332 tryCompare(greeter, "shown", false);
333 startApplication("gallery-app");
334 tryCompare(greeter, "shown", true);
335 }
337 function test_emergencyCallPausesTutorial() {
338 var greeter = findChild(shell, "greeter");
339 var tutorial = findChild(shell, "tutorial");
341 AccountsService.demoEdges = true;
342 enterPin("1234");
343 tryCompare(tutorial, "paused", false);
345 showGreeter();
346 verify(tutorial.paused);
348 swipeAwayGreeter(true);
349 tap(findChild(greeter, "emergencyCallLabel"));
350 verify(tutorial.paused);
351 }
353 function test_failedLoginsCount() {
354 AccountsService.failedLogins = 0
356 enterPin("1111")
357 tryCompare(AccountsService, "failedLogins", 1)
359 enterPin("1234")
360 tryCompare(AccountsService, "failedLogins", 0)
361 }
363 function test_wrongEntries() {
364 var greeter = findChild(shell, "greeter");
365 greeter.failedLoginsDelayAttempts = 3;
367 var wrongPasswordAnimation = findInvisibleChild(shell, "wrongPasswordAnimation");
369 enterPin("1111")
370 verify(wrongPasswordAnimation.running);
372 enterPin("1111")
373 verify(wrongPasswordAnimation.running);
375 var delayedLockscreen = findChild(shell, "delayedLockscreen");
376 tryCompare(delayedLockscreen, "delayMinutes", 0);
377 enterPin("1111")
378 tryCompare(delayedLockscreen, "delayMinutes", greeter.failedLoginsDelayMinutes);
379 }
381 function test_factoryReset() {
382 skip("Factory reset support is not finished")
384 maxRetriesTextField.text = "3"
385 resetSpy.clear()
387 enterPin("1111")
388 enterPin("1111")
390 var dialog = findChild(root, "infoPopup")
391 var button = findChild(dialog, "infoPopupOkButton")
392 tap(button)
393 tryCompareFunction(function() {return findChild(root, "infoPopup", 0 /* timeout */)}, null)
395 tryCompare(resetSpy, "count", 0)
396 enterPin("1111")
397 tryCompare(resetSpy, "count", 1)
398 }
400 function test_emergencyDialerLockOut() {
401 // This is a theoretical attack on the lockscreen: Enter emergency
402 // dialer mode on a phone, then plug into a larger screen,
403 // switching to a tablet interface. This would in theory move the
404 // dialer to a side stage and give access to other apps. So just
405 // confirm that such an attack doesn't work.
407 var stage = findChild(shell, "stage")
409 // We start in phone mode
410 compare(stage.usageScenario, "phone");
412 tap(findChild(shell, "emergencyCallLabel"));
413 confirmLockedApp("dialer-app")
415 // OK, we're in. Now try (but fail) to switch to tablet mode
416 shell.usageScenario = "tablet";
417 compare(stage.usageScenario, "phone");
419 // And when we kill the app, we go back to locked tablet mode
420 ApplicationManager.stopApplication("dialer-app");
421 var greeter = findChild(shell, "greeter")
422 tryCompare(greeter, "fullyShown", true)
423 compare(stage.usageScenario, "tablet");
424 }
426 function test_emergencyDialerIncoming() {
427 callManager.foregroundCall = phoneCall
428 confirmLockedApp("dialer-app")
429 }
431 function test_emergencyDialerActiveCallPanel() {
432 // Make sure that the following sequence works:
433 // - Enter emergency mode call
434 // - Return to greeter
435 // - Click on active call panel
436 // - Should be back in emergency mode dialer
438 var greeter = findChild(shell, "greeter");
440 tap(findChild(shell, "emergencyCallLabel"));
441 confirmLockedApp("dialer-app");
442 callManager.foregroundCall = phoneCall;
444 showGreeter();
445 var lockscreen = findChild(shell, "lockscreen");
446 tryCompare(lockscreen, "shown", true);
447 tryCompare(greeter, "hasLockedApp", false);
449 // simulate a callHint press, the real thing requires dialer: url support
450 ApplicationManager.requestFocusApplication("dialer-app");
452 confirmLockedApp("dialer-app");
453 }
455 function test_normalDialerActiveCallPanel() {
456 // Make sure that the following sequence works:
457 // - Log in
458 // - Start a call
459 // - Switch apps
460 // - Click on active call panel
461 // - Should be back in normal dialer
462 // (we've had a bug where we locked screen in this case)
464 var greeter = findChild(shell, "greeter");
465 var panel = findChild(shell, "panel");
467 enterPin("1234");
468 tryCompare(greeter, "shown", false);
469 tryCompare(LightDM.Greeter, "active", false);
471 startApplication("dialer-app");
472 tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app");
473 callManager.foregroundCall = phoneCall;
475 ApplicationManager.requestFocusApplication("unity8-dash");
476 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
477 tryCompare(panel.callHint, "visible", true);
479 // simulate a callHint press, the real thing requires dialer: url support
480 ApplicationManager.requestFocusApplication("dialer-app");
482 tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app");
483 tryCompare(greeter, "shown", false);
484 tryCompare(LightDM.Greeter, "active", false);
485 }
487 function test_focusRequestedHidesCoverPage() {
488 showGreeter();
490 startApplication("gallery-app");
492 // New app hides coverPage?
493 var greeter = findChild(shell, "greeter");
494 var coverPage = testCase.findChild(shell, "coverPage");
495 tryCompare(coverPage, "showProgress", 0);
496 tryCompare(greeter, "fullyShown", true);
498 showGreeter();
500 // Make sure focusing same app triggers same behavior
501 ApplicationManager.requestFocusApplication("gallery-app");
502 tryCompare(coverPage, "showProgress", 0);
503 tryCompare(greeter, "fullyShown", true);
504 }
506 function test_suspend() {
507 var greeter = findChild(shell, "greeter");
508 var stage = findChild(shell, "stage")
510 // Put it to sleep
511 Powerd.setStatus(Powerd.Off, Powerd.Unknown);
513 // If locked, stage.suspended should be true
514 tryCompare(stage, "suspended", true);
516 // And wake up
517 Powerd.setStatus(Powerd.On, Powerd.Unknown);
518 tryCompare(greeter, "fullyShown", true);
520 // Swipe away greeter to focus app
521 swipeAwayGreeter(true);
523 // We have a lockscreen, make sure we're still suspended
524 tryCompare(stage, "suspended", true);
526 enterPin("1234")
528 // Now that the lockscreen has gone too, make sure we're waking up
529 tryCompare(stage, "suspended", false);
530 }
532 /* We had a bug (1395075) where if a user kept swiping as the greeter
533 loaded, they would be able to get into the session before the
534 lockscreen appeared. Make sure that doesn't happen. */
535 function test_earlyDisable() {
536 // Kill current shell
537 shellLoader.itemDestroyed = false;
538 shellLoader.active = false;
539 tryCompare(shellLoader, "itemDestroyed", true);
540 LightDM.Greeter.authenticate(""); // reset greeter
542 // Create new shell
543 promptSpy.clear();
544 shellLoader.active = true;
545 tryCompareFunction(function() {return shell !== null}, true);
547 // Confirm that we start disabled
548 compare(promptSpy.count, 0);
549 verify(shell.waitingOnGreeter);
550 var coverPageDragHandle = findChild(shell, "coverPageDragHandle");
551 verify(!coverPageDragHandle.enabled);
553 // And that we only become enabled once the lockscreen is up
554 tryCompare(shell, "waitingOnGreeter", false);
555 verify(promptSpy.count > 0);
556 var lockscreen = findChild(shell, "lockscreen");
557 verify(lockscreen.shown);
558 }
559 }