// SPDX-License-Identifier: MIT import QtQml import QtTest import ".." TestCase { id: testCase name: "FingerprintRetry" property alias authenticator: auth QtObject { id: auth property int authenticatorTypes: 0 property int starts: 0 signal noninteractiveInfo(int kind, QtObject source) signal noninteractiveError(int kind, QtObject source) signal failed(int kind, QtObject source) signal succeeded() function startAuthenticating() { ++starts; } } FedoraToolsFingerprintRetry { id: retry auth: testCase.authenticator fingerprintType: 1 } function initTestCase() { compare(retry.interval, 6000); compare(retry.repeat, false); } function init() { retry.enabled = false; auth.authenticatorTypes = 0; auth.starts = 0; retry.interval = 20; retry.enabled = true; } function beginFingerprint() { auth.authenticatorTypes = 1; auth.noninteractiveInfo(1, auth); } function test_idleTimeoutRetriesWithoutInput() { beginFingerprint(); wait(50); compare(auth.starts, 0); // Never restart a working conversation. auth.authenticatorTypes = 0; verify(retry.running); tryCompare(auth, "starts", 1); wait(60); compare(auth.starts, 1); // No polling while the reader stays unavailable. beginFingerprint(); auth.authenticatorTypes = 0; tryCompare(auth, "starts", 2); // Later idle timeouts can also recover. } function test_noReaderOrNoInstructions() { wait(60); compare(auth.starts, 0); auth.authenticatorTypes = 1; auth.authenticatorTypes = 0; wait(60); compare(auth.starts, 0); } function test_failedScansDoNotGetAutomaticNewAttempts() { beginFingerprint(); auth.noninteractiveError(1, auth); auth.noninteractiveInfo(1, auth); // Another instruction or timeout message. auth.failed(1, auth); auth.authenticatorTypes = 0; wait(60); compare(auth.starts, 0); } function test_unavailableRetryDoesNotLoop() { beginFingerprint(); auth.authenticatorTypes = 0; tryCompare(auth, "starts", 1); auth.authenticatorTypes = 1; // PAM marks active before opening the reader. auth.failed(1, auth); auth.authenticatorTypes = 0; wait(60); compare(auth.starts, 1); } function test_smartcardDoesNotArmOrCancelFingerprintRetry() { auth.authenticatorTypes = 2; auth.noninteractiveInfo(2, auth); auth.authenticatorTypes = 0; wait(60); compare(auth.starts, 0); beginFingerprint(); auth.noninteractiveError(2, auth); auth.authenticatorTypes = 2; tryCompare(auth, "starts", 1); } function test_cancelPendingRetry_data() { return [ {tag: "manual restart"}, {tag: "success"}, {tag: "password failure"}, {tag: "hidden or suspended"} ]; } function test_cancelPendingRetry(data) { beginFingerprint(); auth.authenticatorTypes = 0; verify(retry.running); switch (data.tag) { case "manual restart": auth.authenticatorTypes = 1; break; case "success": auth.succeeded(); break; case "password failure": auth.failed(0, auth); break; case "hidden or suspended": retry.enabled = false; break; } wait(60); compare(auth.starts, 0); } function test_passwordFailureBeforeAvailabilityChange() { beginFingerprint(); auth.failed(0, auth); auth.authenticatorTypes = 0; wait(60); compare(auth.starts, 0); } }