File indexing completed on 2024-04-28 16:45:11

0001 /*
0002 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004 SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 // own
0007 #include "../ksldapp.h"
0008 // KDE Frameworks
0009 #include <KIdleTime>
0010 // Qt
0011 #include <QProcess>
0012 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0013 #include <private/qtx11extras_p.h>
0014 #else
0015 #include <QX11Info>
0016 #endif
0017 #include <QtTest>
0018 // xcb
0019 #include <xcb/xcb.h>
0020 #include <xcb/xtest.h>
0021 
0022 class KSldTest : public QObject
0023 {
0024     Q_OBJECT
0025 private Q_SLOTS:
0026     void initTestCase();
0027     void testEstablishGrab();
0028     void testActivateOnTimeout();
0029     void testGraceTimeUnlocking();
0030 };
0031 
0032 void KSldTest::initTestCase()
0033 {
0034     QCoreApplication::setAttribute(Qt::AA_ForceRasterWidgets);
0035     // change to the build bin dir
0036     QDir::setCurrent(QCoreApplication::applicationDirPath());
0037 }
0038 
0039 void KSldTest::testEstablishGrab()
0040 {
0041     ScreenLocker::KSldApp ksld;
0042     ksld.initialize();
0043     QVERIFY(ksld.establishGrab());
0044     // grab is established, trying again should succeed as well
0045     QVERIFY(ksld.establishGrab());
0046 
0047     // let's ungrab
0048     ksld.doUnlock();
0049 
0050     // to get the grab to fail we need another X client
0051     // we start another process to perform our grab
0052     QProcess keyboardGrabber;
0053     keyboardGrabber.start(QStringLiteral("./keyboardGrabber"), QStringList());
0054     QVERIFY(keyboardGrabber.waitForStarted());
0055 
0056     // let's add some delay to be sure that keyboardGrabber has it's X stuff done
0057     QTest::qWait(100);
0058 
0059     // now grabbing should fail
0060     QVERIFY(!ksld.establishGrab());
0061 
0062     // let's terminate again
0063     keyboardGrabber.terminate();
0064     QVERIFY(keyboardGrabber.waitForFinished());
0065 
0066     // now grabbing should succeed again
0067     QVERIFY(ksld.establishGrab());
0068 
0069     ksld.doUnlock();
0070 
0071     // now the same with pointer
0072     QProcess pointerGrabber;
0073     pointerGrabber.start(QStringLiteral("./pointerGrabber"), QStringList());
0074     QVERIFY(pointerGrabber.waitForStarted());
0075 
0076     // let's add some delay to be sure that pointerGrabber has it's X stuff done
0077     QTest::qWait(100);
0078 
0079     // now grabbing should fail
0080     QVERIFY(!ksld.establishGrab());
0081 
0082     // let's terminate again
0083     pointerGrabber.terminate();
0084     QVERIFY(pointerGrabber.waitForFinished());
0085 
0086     // now grabbing should succeed again
0087     QVERIFY(ksld.establishGrab());
0088 }
0089 
0090 void KSldTest::testActivateOnTimeout()
0091 {
0092     // this time verifies that the screen gets locked on idle timeout, requires the system to be idle
0093     ScreenLocker::KSldApp ksld;
0094     ksld.initialize();
0095 
0096     // we need to modify the idle timeout of KSLD, it's in minutes we cannot wait that long
0097     if (ksld.idleId() != 0) {
0098         // remove old Idle id
0099         KIdleTime::instance()->removeIdleTimeout(ksld.idleId());
0100     }
0101     ksld.setIdleId(KIdleTime::instance()->addIdleTimeout(5000));
0102 
0103     QSignalSpy lockStateChangedSpy(&ksld, &ScreenLocker::KSldApp::lockStateChanged);
0104     QVERIFY(lockStateChangedSpy.isValid());
0105 
0106     // let's wait the double of the idle timeout
0107     QVERIFY(lockStateChangedSpy.wait(10000));
0108     QCOMPARE(ksld.lockState(), ScreenLocker::KSldApp::AcquiringLock);
0109 
0110     // let's simulate unlock to get rid of started greeter process
0111     const auto children = ksld.children();
0112     for (auto it = children.begin(); it != children.end(); ++it) {
0113         if (qstrcmp((*it)->metaObject()->className(), "LogindIntegration") != 0) {
0114             continue;
0115         }
0116         QMetaObject::invokeMethod(*it, "requestUnlock");
0117         break;
0118     }
0119     QVERIFY(lockStateChangedSpy.wait());
0120 
0121     KIdleTime::instance()->removeIdleTimeout(ksld.idleId());
0122 }
0123 
0124 void KSldTest::testGraceTimeUnlocking()
0125 {
0126     // this time verifies that the screen gets unlocked during grace time by simulated user activity
0127     ScreenLocker::KSldApp ksld(this);
0128     ksld.initialize();
0129 
0130     // we need to modify the idle timeout of KSLD, it's in minutes we cannot wait that long
0131     if (ksld.idleId() != 0) {
0132         // remove old Idle id
0133         KIdleTime::instance()->removeIdleTimeout(ksld.idleId());
0134     }
0135     ksld.setIdleId(KIdleTime::instance()->addIdleTimeout(5000));
0136     // infinite
0137     ksld.setGraceTime(-1);
0138 
0139     QSignalSpy lockedSpy(&ksld, &ScreenLocker::KSldApp::locked);
0140     QVERIFY(lockedSpy.isValid());
0141     QSignalSpy unlockedSpy(&ksld, &ScreenLocker::KSldApp::unlocked);
0142     QVERIFY(unlockedSpy.isValid());
0143 
0144     // let's wait quite some time to give the greeter a chance to come up
0145     QVERIFY(lockedSpy.wait(30000));
0146     QCOMPARE(ksld.lockState(), ScreenLocker::KSldApp::Locked);
0147 
0148     // let's simulate unlock by faking input
0149     const QPoint cursorPos = QCursor::pos();
0150     xcb_test_fake_input(QX11Info::connection(), XCB_MOTION_NOTIFY, 0, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, cursorPos.x() + 1, cursorPos.y() + 1, 0);
0151     xcb_flush(QX11Info::connection());
0152     QVERIFY(unlockedSpy.wait());
0153 
0154     // now let's test again without grace time
0155     ksld.setGraceTime(0);
0156     QVERIFY(lockedSpy.wait(30000));
0157     QCOMPARE(ksld.lockState(), ScreenLocker::KSldApp::Locked);
0158 
0159     xcb_test_fake_input(QX11Info::connection(), XCB_MOTION_NOTIFY, 0, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, cursorPos.x(), cursorPos.y(), 0);
0160     xcb_flush(QX11Info::connection());
0161     QVERIFY(!unlockedSpy.wait());
0162 
0163     // and unlock
0164     const auto children = ksld.children();
0165     for (auto it = children.begin(); it != children.end(); ++it) {
0166         if (qstrcmp((*it)->metaObject()->className(), "LogindIntegration") != 0) {
0167             continue;
0168         }
0169         QMetaObject::invokeMethod(*it, "requestUnlock");
0170         break;
0171     }
0172     QVERIFY(unlockedSpy.wait());
0173 }
0174 
0175 QTEST_MAIN(KSldTest)
0176 #include "ksldtest.moc"