SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "../ksldapp.h"
#include <KIdleTime>
#include <KWindowSystem>
#include <QProcess>
#include <QSignalSpy>
#include <QTest>
#include <private/qtx11extras_p.h>
#include <xcb/xcb.h>
#include <xcb/xtest.h>
#include <sys/socket.h>
class KSldTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void testEstablishGrab();
void testActivateOnTimeout();
void testGraceTimeUnlocking();
};
void KSldTest::initTestCase()
{
QCoreApplication::setAttribute(Qt::AA_ForceRasterWidgets);
QDir::setCurrent(QCoreApplication::applicationDirPath());
}
void KSldTest::testEstablishGrab()
{
if (!KWindowSystem::isPlatformX11()) {
QSKIP("keyboard and pointer grabbing by other processes is only possible on X11");
}
ScreenLocker::KSldApp ksld;
ksld.initialize();
QVERIFY(ksld.establishGrab());
QVERIFY(ksld.establishGrab());
ksld.doUnlock();
QProcess keyboardGrabber;
keyboardGrabber.start(QStringLiteral("./keyboardGrabber"), QStringList());
QVERIFY(keyboardGrabber.waitForStarted());
QTest::qWait(std::chrono::milliseconds{100});
QVERIFY(!ksld.establishGrab());
keyboardGrabber.terminate();
QVERIFY(keyboardGrabber.waitForFinished());
QVERIFY(ksld.establishGrab());
ksld.doUnlock();
QProcess pointerGrabber;
pointerGrabber.start(QStringLiteral("./pointerGrabber"), QStringList());
QVERIFY(pointerGrabber.waitForStarted());
QTest::qWait(std::chrono::milliseconds{100});
QVERIFY(!ksld.establishGrab());
pointerGrabber.terminate();
QVERIFY(pointerGrabber.waitForFinished());
QVERIFY(ksld.establishGrab());
}
void KSldTest::testActivateOnTimeout()
{
ScreenLocker::KSldApp ksld;
ksld.initialize();
if (KWindowSystem::isPlatformWayland()) {
int sx[2];
QCOMPARE(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx), 0);
ksld.setWaylandFd(sx[1]);
}
if (ksld.idleId() != 0) {
KIdleTime::instance()->removeIdleTimeout(ksld.idleId());
}
ksld.setIdleId(KIdleTime::instance()->addIdleTimeout(std::chrono::seconds{5}));
QSignalSpy lockStateChangedSpy(&ksld, &ScreenLocker::KSldApp::lockStateChanged);
QVERIFY(lockStateChangedSpy.isValid());
QVERIFY2(lockStateChangedSpy.wait(std::chrono::seconds{10}),
"If running the test locally, make sure you're not moving the mouse or otherwise interrupting this test's idle check.");
QCOMPARE(ksld.lockState(), ScreenLocker::KSldApp::AcquiringLock);
const auto children = ksld.children();
for (auto it = children.begin(); it != children.end(); ++it) {
if (qstrcmp((*it)->metaObject()->className(), "LogindIntegration") != 0) {
continue;
}
QMetaObject::invokeMethod(*it, "requestUnlock");
break;
}
QVERIFY(lockStateChangedSpy.wait());
KIdleTime::instance()->removeIdleTimeout(ksld.idleId());
}
void KSldTest::testGraceTimeUnlocking()
{
if (!KWindowSystem::isPlatformX11()) {
QSKIP("XCB fake input won't work on Wayland");
}
ScreenLocker::KSldApp ksld(this);
ksld.initialize();
if (ksld.idleId() != 0) {
KIdleTime::instance()->removeIdleTimeout(ksld.idleId());
}
ksld.setIdleId(KIdleTime::instance()->addIdleTimeout(std::chrono::seconds{5}));
ksld.setGraceTime(-1);
QSignalSpy lockedSpy(&ksld, &ScreenLocker::KSldApp::locked);
QVERIFY(lockedSpy.isValid());
QSignalSpy unlockedSpy(&ksld, &ScreenLocker::KSldApp::unlocked);
QVERIFY(unlockedSpy.isValid());
QVERIFY(lockedSpy.wait(std::chrono::seconds{30}));
QCOMPARE(ksld.lockState(), ScreenLocker::KSldApp::Locked);
const QPoint cursorPos = QCursor::pos();
xcb_test_fake_input(QX11Info::connection(), XCB_MOTION_NOTIFY, 0, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, cursorPos.x() + 1, cursorPos.y() + 1, 0);
xcb_flush(QX11Info::connection());
QVERIFY(unlockedSpy.wait());
ksld.setGraceTime(0);
QVERIFY(lockedSpy.wait(std::chrono::seconds{30}));
QCOMPARE(ksld.lockState(), ScreenLocker::KSldApp::Locked);
xcb_test_fake_input(QX11Info::connection(), XCB_MOTION_NOTIFY, 0, XCB_TIME_CURRENT_TIME, XCB_WINDOW_NONE, cursorPos.x(), cursorPos.y(), 0);
xcb_flush(QX11Info::connection());
QVERIFY(!unlockedSpy.wait());
const auto children = ksld.children();
for (auto it = children.begin(); it != children.end(); ++it) {
if (qstrcmp((*it)->metaObject()->className(), "LogindIntegration") != 0) {
continue;
}
QMetaObject::invokeMethod(*it, "requestUnlock");
break;
}
QVERIFY(unlockedSpy.wait());
}
QTEST_MAIN(KSldTest)
#include "ksldtest.moc"