@@ -0,0 +1,419 @@
1+/*
2+ * Copyright 2013 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 ".."
20+import "../../../qml/Greeter"
21+import Ubuntu.Components 0.1
22+import AccountsService 0.1
23+import LightDM 0.1 as LightDM
24+import Unity.Test 0.1 as UT
25+
26+Item {
27+ width: units.gu(120)
28+ height: units.gu(80)
29+
30+ property url defaultBackground: Qt.resolvedUrl("../../../qml/graphics/tablet_background.jpg")
31+
32+ Row {
33+ anchors.fill: parent
34+ Loader {
35+ id: loader
36+ width: parent.width - controls.width
37+ height: parent.height
38+
39+ property bool itemDestroyed: false
40+ sourceComponent: Component {
41+ Greeter {
42+ width: loader.width
43+ height: loader.height
44+ background: defaultBackground
45+ viewSource: Qt.resolvedUrl("TestView.qml")
46+
47+ Component.onDestruction: {
48+ loader.itemDestroyed = true;
49+ }
50+ }
51+ }
52+ }
53+
54+ Rectangle {
55+ id: controls
56+ color: "white"
57+ width: units.gu(40)
58+ height: parent.height
59+
60+ Column {
61+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
62+ spacing: units.gu(1)
63+
64+ Row {
65+ Button {
66+ text: "Show Greeter"
67+ onClicked: loader.item.show()
68+ }
69+ }
70+ }
71+ }
72+ }
73+
74+ SignalSpy {
75+ id: teaseSpy
76+ target: loader.item
77+ signalName: "tease"
78+ }
79+
80+ SignalSpy {
81+ id: sessionStartedSpy
82+ target: loader.item
83+ signalName: "sessionStarted"
84+ }
85+
86+ SignalSpy {
87+ id: emergencyCallSpy
88+ target: loader.item
89+ signalName: "emergencyCall"
90+ }
91+
92+ UT.UnityTestCase {
93+ id: testCase
94+ name: "Greeter"
95+ when: windowShown
96+
97+ property Item greeter: loader.status === Loader.Ready ? loader.item : null
98+ property Item view
99+
100+ SignalSpy {
101+ id: viewShowMessageSpy
102+ target: testCase.view
103+ signalName: "_showMessageCalled"
104+ }
105+
106+ SignalSpy {
107+ id: viewShowPromptSpy
108+ target: testCase.view
109+ signalName: "_showPromptCalled"
110+ }
111+
112+ SignalSpy {
113+ id: viewShowLastChanceSpy
114+ target: testCase.view
115+ signalName: "_showLastChanceCalled"
116+ }
117+
118+ SignalSpy {
119+ id: viewHideSpy
120+ target: testCase.view
121+ signalName: "_hideCalled"
122+ }
123+
124+ SignalSpy {
125+ id: viewAuthenticatedSpy
126+ target: testCase.view
127+ signalName: "_authenticatedCalled"
128+ }
129+
130+ SignalSpy {
131+ id: viewResetSpy
132+ target: testCase.view
133+ signalName: "_resetCalled"
134+ }
135+
136+ SignalSpy {
137+ id: viewTryToUnlockSpy
138+ target: testCase.view
139+ signalName: "_tryToUnlockCalled"
140+ }
141+
142+ function init() {
143+ teaseSpy.clear();
144+ sessionStartedSpy.clear();
145+ emergencyCallSpy.clear();
146+ viewShowMessageSpy.clear();
147+ viewShowPromptSpy.clear();
148+ viewShowLastChanceSpy.clear();
149+ viewHideSpy.clear();
150+ viewAuthenticatedSpy.clear();
151+ viewResetSpy.clear();
152+ viewTryToUnlockSpy.clear();
153+ tryCompare(greeter, "waiting", false);
154+ view = findChild(greeter, "testView");
155+ verifySelected(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
156+ }
157+
158+ function cleanup() {
159+ loader.itemDestroyed = false;
160+ loader.active = false;
161+ tryCompare(loader, "status", Loader.Null);
162+ tryCompare(loader, "item", null);
163+ tryCompare(loader, "itemDestroyed", true);
164+ loader.active = true;
165+ tryCompare(loader, "status", Loader.Ready);
166+ removeTimeConstraintsFromDirectionalDragAreas(loader.item);
167+ }
168+
169+ function getIndexOf(name) {
170+ for (var i = 0; i < LightDM.Users.count; i++) {
171+ if (name === LightDM.Users.data(i, LightDM.UserRoles.NameRole)) {
172+ return i;
173+ }
174+ }
175+ fail("Didn't find name")
176+ return -1;
177+ }
178+
179+ function selectUser(name) {
180+ var i = getIndexOf(name);
181+ view.selected(i);
182+ verifySelected(name);
183+ return i;
184+ }
185+
186+ function verifySelected(name) {
187+ var i = getIndexOf(name);
188+ compare(view.currentIndex, i);
189+ compare(AccountsService.user, name);
190+ compare(LightDM.Greeter.authenticationUser, name);
191+ }
192+
193+ function verifyLoggedIn() {
194+ tryCompare(sessionStartedSpy, "count", 1);
195+ verify(viewAuthenticatedSpy.count > 0);
196+ compare(viewAuthenticatedSpy.signalArguments[viewAuthenticatedSpy.count - 1][0], true);
197+ compare(LightDM.Greeter.authenticated, true);
198+ compare(greeter.shown, false);
199+ }
200+
201+ function test_unlockPass() {
202+ selectUser("has-password");
203+ tryCompare(viewShowPromptSpy, "count", 1);
204+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
205+ compare(viewShowPromptSpy.signalArguments[0][1], true);
206+ compare(viewShowPromptSpy.signalArguments[0][2], true);
207+
208+ view.responded("password");
209+ verifyLoggedIn();
210+ }
211+
212+ function test_unlockFail() {
213+ selectUser("has-password");
214+ tryCompare(viewShowPromptSpy, "count", 1);
215+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
216+ compare(viewShowPromptSpy.signalArguments[0][1], true);
217+ compare(viewShowPromptSpy.signalArguments[0][2], true);
218+
219+ view.responded("wr0ng p4ssw0rd");
220+ tryCompare(viewAuthenticatedSpy, "count", 1);
221+ compare(viewAuthenticatedSpy.signalArguments[0][0], false);
222+
223+ tryCompare(viewShowPromptSpy, "count", 2);
224+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
225+ compare(viewShowPromptSpy.signalArguments[0][1], true);
226+ compare(viewShowPromptSpy.signalArguments[0][2], true);
227+ }
228+
229+ function test_twoFactorPass() {
230+ selectUser("two-factor");
231+ tryCompare(viewShowPromptSpy, "count", 1);
232+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
233+ compare(viewShowPromptSpy.signalArguments[0][1], true);
234+ compare(viewShowPromptSpy.signalArguments[0][2], true);
235+
236+ view.responded("password");
237+ tryCompare(viewShowPromptSpy, "count", 2);
238+ compare(viewShowPromptSpy.signalArguments[1][0], "otp");
239+ compare(viewShowPromptSpy.signalArguments[1][1], false);
240+ compare(viewShowPromptSpy.signalArguments[1][2], false);
241+
242+ view.responded("otp");
243+ verifyLoggedIn();
244+ }
245+
246+ function test_twoFactorFailOnFirst() {
247+ selectUser("two-factor");
248+ tryCompare(viewShowPromptSpy, "count", 1);
249+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
250+ compare(viewShowPromptSpy.signalArguments[0][1], true);
251+ compare(viewShowPromptSpy.signalArguments[0][2], true);
252+
253+ view.responded("wr0ng p4ssw0rd");
254+ tryCompare(viewAuthenticatedSpy, "count", 1);
255+ compare(viewAuthenticatedSpy.signalArguments[0][0], false);
256+
257+ tryCompare(viewShowPromptSpy, "count", 2);
258+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
259+ compare(viewShowPromptSpy.signalArguments[0][1], true);
260+ compare(viewShowPromptSpy.signalArguments[0][2], true);
261+ }
262+
263+ function test_twoFactorFailOnSecond() {
264+ selectUser("two-factor");
265+ tryCompare(viewShowPromptSpy, "count", 1);
266+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
267+ compare(viewShowPromptSpy.signalArguments[0][1], true);
268+ compare(viewShowPromptSpy.signalArguments[0][2], true);
269+
270+ view.responded("password");
271+ tryCompare(viewShowPromptSpy, "count", 2);
272+ compare(viewShowPromptSpy.signalArguments[1][0], "otp");
273+ compare(viewShowPromptSpy.signalArguments[1][1], false);
274+ compare(viewShowPromptSpy.signalArguments[1][2], false);
275+
276+ view.responded("wr0ng p4ssw0rd");
277+ tryCompare(viewAuthenticatedSpy, "count", 1);
278+ compare(viewAuthenticatedSpy.signalArguments[0][0], false);
279+
280+ tryCompare(viewShowPromptSpy, "count", 3);
281+ compare(viewShowPromptSpy.signalArguments[0][0], "Password");
282+ compare(viewShowPromptSpy.signalArguments[0][1], true);
283+ compare(viewShowPromptSpy.signalArguments[0][2], true);
284+ }
285+
286+ function test_htmlInfoPrompt() {
287+ selectUser("html-info-prompt");
288+ tryCompare(viewShowPromptSpy, "count", 1);
289+ compare(viewShowMessageSpy.count, 1);
290+ compare(viewShowMessageSpy.signalArguments[0][0], "<b>&</b>");
291+ }
292+
293+ function test_multiInfoPrompt() {
294+ selectUser("multi-info-prompt");
295+ tryCompare(viewShowPromptSpy, "count", 1);
296+ compare(viewShowMessageSpy.count, 3);
297+ compare(viewShowMessageSpy.signalArguments[0][0], "Welcome to Unity Greeter");
298+ compare(viewShowMessageSpy.signalArguments[1][0], "<font color=\"#df382c\">This is an error</font>");
299+ compare(viewShowMessageSpy.signalArguments[2][0], "You should have seen three messages");
300+ }
301+
302+ function test_waiting() {
303+ // Make sure we unset 'waiting' on prompt
304+ selectUser("has-password");
305+ compare(greeter.waiting, true);
306+ tryCompare(greeter, "waiting", false);
307+
308+ // Make sure we unset 'waiting' on authentication
309+ selectUser("no-password");
310+ compare(greeter.waiting, true);
311+ tryCompare(greeter, "waiting", false);
312+ }
313+
314+ function test_locked() {
315+ selectUser("has-password");
316+ compare(view.locked, true);
317+
318+ LightDM.Greeter.active = false;
319+ compare(view.locked, false);
320+ LightDM.Greeter.active = true;
321+
322+ greeter.forcedUnlock = true;
323+ compare(view.locked, false);
324+ greeter.forcedUnlock = false;
325+
326+ selectUser("no-password");
327+ tryCompare(view, "locked", false);
328+ selectUser("has-password");
329+ }
330+
331+ function test_fullyShown() {
332+ compare(greeter.fullyShown, true);
333+ view.hide();
334+ compare(greeter.fullyShown, false);
335+ }
336+
337+ function test_alphanumeric() {
338+ selectUser("has-password");
339+ compare(view.alphanumeric, true);
340+ selectUser("has-pin");
341+ compare(view.alphanumeric, false);
342+ }
343+
344+ function test_background() {
345+ greeter.background = "testing";
346+ compare(view.background, Qt.resolvedUrl("testing"));
347+ }
348+
349+ function test_dragHandleLeftMargin() {
350+ compare(view.dragHandleLeftMargin, 0);
351+ greeter.dragHandleLeftMargin = 5;
352+ compare(view.dragHandleLeftMargin, 5);
353+ }
354+
355+ function test_launcherOffset() {
356+ compare(view.launcherOffset, 0);
357+ greeter.launcherOffset = 5;
358+ tryCompare(view, "launcherOffset", 5);
359+ }
360+
361+ function test_backgroundTopMargin() {
362+ compare(view.backgroundTopMargin, 0);
363+ greeter.y = 5;
364+ compare(view.backgroundTopMargin, -5);
365+ }
366+
367+ function test_differentPrompt() {
368+ selectUser("different-prompt");
369+ tryCompare(viewShowPromptSpy, "count", 1);
370+ compare(viewShowPromptSpy.signalArguments[0][0], "Secret word");
371+ compare(viewShowPromptSpy.signalArguments[0][1], true);
372+ compare(viewShowPromptSpy.signalArguments[0][2], false);
373+ }
374+
375+ function test_authError() {
376+ selectUser("auth-error");
377+ tryCompare(viewAuthenticatedSpy, "count", 1);
378+ compare(viewAuthenticatedSpy.signalArguments[0][0], false);
379+ compare(viewShowPromptSpy.count, 0);
380+ compare(view.locked, true);
381+ }
382+
383+ function test_dbusRequestAuthenticationUser() {
384+ LightDM.Greeter.requestAuthenticationUser("has-password");
385+ verifySelected("has-password");
386+ }
387+
388+ function test_dbusHideGreeter() {
389+ compare(view.required, true);
390+ LightDM.Greeter.hideGreeter();
391+ compare(view.required, false);
392+ compare(greeter.required, false);
393+ }
394+
395+ function test_dbusShowGreeterFromHiddenState() {
396+ greeter.hide();
397+ compare(greeter.required, false);
398+
399+ LightDM.Greeter.showGreeter();
400+ compare(greeter.required, true);
401+ compare(greeter.fullyShown, true);
402+ view = findChild(greeter, "testView");
403+ compare(view.required, true);
404+
405+ // Can't test some of the stuff called on 'view' here because
406+ // the view was torn down and created again. So the spies missed
407+ // the good stuff while it down. See next test for more.
408+ }
409+
410+ function test_dbusShowGreeterFromShownState() {
411+ selectUser("has-password");
412+ tryCompare(viewShowPromptSpy, "count", 1);
413+ viewShowPromptSpy.clear();
414+ LightDM.Greeter.showGreeter();
415+ compare(viewResetSpy.count, 1);
416+ tryCompare(viewShowPromptSpy, "count", 1);
417+ }
418+ }
419+}