File indexing completed on 2024-05-05 05:30:27

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 <config-kscreenlocker.h>
0008 // KF
0009 #include <KLibexec>
0010 // Qt
0011 #include <QProcess>
0012 #include <QSignalSpy>
0013 #include <QTest>
0014 // system
0015 #include <signal.h>
0016 
0017 Q_DECLARE_METATYPE(QProcess::ExitStatus)
0018 
0019 class KillTest : public QObject
0020 {
0021     Q_OBJECT
0022 private Q_SLOTS:
0023     void testKill_data();
0024     void testKill();
0025     void testImmediateKill_data();
0026     void testImmediateKill();
0027 };
0028 
0029 void KillTest::testKill_data()
0030 {
0031     QTest::addColumn<int>("signal");
0032     QTest::addColumn<bool>("expectedQuit");
0033     QTest::addColumn<QProcess::ExitStatus>("exitStatus");
0034 
0035     QTest::newRow("SIGHUP") << SIGHUP << true << QProcess::CrashExit;
0036     QTest::newRow("SIGINT") << SIGINT << true << QProcess::CrashExit;
0037     QTest::newRow("SIGQUIT") << SIGQUIT << true << QProcess::CrashExit;
0038     QTest::newRow("SIGILL") << SIGILL << true << QProcess::CrashExit;
0039     QTest::newRow("SIGTRAP") << SIGTRAP << true << QProcess::CrashExit;
0040     QTest::newRow("SIGABRT") << SIGABRT << true << QProcess::CrashExit;
0041     QTest::newRow("SIGIOT") << SIGIOT << true << QProcess::CrashExit;
0042     QTest::newRow("SIGBUS") << SIGBUS << true << QProcess::CrashExit;
0043     QTest::newRow("SIGFPE") << SIGFPE << true << QProcess::CrashExit;
0044     QTest::newRow("SIGKILL") << SIGKILL << true << QProcess::CrashExit;
0045     QTest::newRow("SIGUSR1") << SIGUSR1 << false << QProcess::CrashExit;
0046     QTest::newRow("SIGSEGV") << SIGSEGV << true << QProcess::CrashExit;
0047     QTest::newRow("SIGUSR2") << SIGUSR2 << true << QProcess::CrashExit;
0048     QTest::newRow("SIGPIPE") << SIGPIPE << true << QProcess::CrashExit;
0049     QTest::newRow("SIGALRM") << SIGALRM << true << QProcess::CrashExit;
0050     QTest::newRow("SIGTERM") << SIGTERM << true << QProcess::NormalExit;
0051     // ignore
0052     // QTest::newRow("SIGCHLD")   << SIGCHLD;
0053     // QTest::newRow("SIGCONT")   << SIGCONT;
0054     // QTest::newRow("SIGSTOP")   << SIGSTOP;
0055     // QTest::newRow("SIGTSTP")   << SIGTSTP;
0056     // QTest::newRow("SIGTTIN")   << SIGTTIN;
0057     // QTest::newRow("SIGTTOU")   << SIGTTOU;
0058     // QTest::newRow("SIGURG")    << SIGURG;
0059     // QTest::newRow("SIGXCPU")   << SIGXCPU;
0060     // QTest::newRow("SIGXFSZ")   << SIGXFSZ;
0061     // QTest::newRow("SIGVTALRM") << SIGVTALRM;
0062     // QTest::newRow("SIGPROF")   << SIGPROF;
0063     // QTest::newRow("SIGWINCH")  << SIGWINCH;
0064     // QTest::newRow("SIGIO")     << SIGIO;
0065     // QTest::newRow("SIGPWR")    << SIGPWR;
0066     QTest::newRow("SIGSYS") << SIGSYS << true << QProcess::CrashExit;
0067 #ifdef Q_OS_LINUX
0068 #ifdef SIGUNUSED
0069     QTest::newRow("SIGUNUSED") << SIGUNUSED << true << QProcess::CrashExit;
0070 #endif
0071 #ifdef SIGSTKFLT
0072     QTest::newRow("SIGSTKFLT") << SIGSTKFLT << true << QProcess::CrashExit;
0073 #endif
0074 #endif
0075 }
0076 
0077 void KillTest::testKill()
0078 {
0079     QProcess greeter(this);
0080     QSignalSpy spy(&greeter, &QProcess::readyReadStandardOutput);
0081 
0082     greeter.setReadChannel(QProcess::StandardOutput);
0083     greeter.start(KLibexec::path(KSCREENLOCKER_GREET_BIN_REL), QStringList({QStringLiteral("--testing")}));
0084 
0085     // Wait for the "locked at" message as an indication that the greeter is ready
0086     spy.wait(5000);
0087     QCOMPARE(spy.count(), 1);
0088 
0089     QVERIFY(greeter.readAllStandardOutput().contains(QByteArrayLiteral("Locked at")));
0090 
0091     // now kill
0092     QFETCH(int, signal);
0093     kill(greeter.processId(), signal);
0094 
0095     QFETCH(bool, expectedQuit);
0096     QCOMPARE(greeter.waitForFinished(3000), expectedQuit);
0097     if (greeter.state() == QProcess::Running) {
0098         greeter.terminate();
0099         QVERIFY(greeter.waitForFinished());
0100     } else {
0101         QFETCH(QProcess::ExitStatus, exitStatus);
0102         QCOMPARE(greeter.exitStatus(), exitStatus);
0103 
0104         if (greeter.exitStatus() == QProcess::NormalExit) {
0105             // exit code is only valid for NormalExit
0106             QCOMPARE(greeter.exitCode(), 1);
0107         }
0108     }
0109 }
0110 
0111 void KillTest::testImmediateKill_data()
0112 {
0113     QTest::addColumn<int>("signal");
0114 
0115     QTest::newRow("SIGHUP") << SIGHUP;
0116     QTest::newRow("SIGINT") << SIGINT;
0117     QTest::newRow("SIGQUIT") << SIGQUIT;
0118     QTest::newRow("SIGILL") << SIGILL;
0119     QTest::newRow("SIGTRAP") << SIGTRAP;
0120     QTest::newRow("SIGABRT") << SIGABRT;
0121     QTest::newRow("SIGIOT") << SIGIOT;
0122     QTest::newRow("SIGBUS") << SIGBUS;
0123     QTest::newRow("SIGFPE") << SIGFPE;
0124     QTest::newRow("SIGKILL") << SIGKILL;
0125     QTest::newRow("SIGUSR1") << SIGUSR1;
0126     QTest::newRow("SIGSEGV") << SIGSEGV;
0127     QTest::newRow("SIGUSR2") << SIGUSR2;
0128     QTest::newRow("SIGPIPE") << SIGPIPE;
0129     QTest::newRow("SIGALRM") << SIGALRM;
0130     QTest::newRow("SIGTERM") << SIGTERM;
0131     // ignore
0132     // QTest::newRow("SIGCHLD")   << SIGCHLD;
0133     // QTest::newRow("SIGCONT")   << SIGCONT;
0134     // QTest::newRow("SIGSTOP")   << SIGSTOP;
0135     // QTest::newRow("SIGTSTP")   << SIGTSTP;
0136     // QTest::newRow("SIGTTIN")   << SIGTTIN;
0137     // QTest::newRow("SIGTTOU")   << SIGTTOU;
0138     // QTest::newRow("SIGURG")    << SIGURG;
0139     // QTest::newRow("SIGXCPU")   << SIGXCPU;
0140     // QTest::newRow("SIGXFSZ")   << SIGXFSZ;
0141     // QTest::newRow("SIGVTALRM") << SIGVTALRM;
0142     // QTest::newRow("SIGPROF")   << SIGPROF;
0143     // QTest::newRow("SIGWINCH")  << SIGWINCH;
0144     // QTest::newRow("SIGIO")     << SIGIO;
0145     // QTest::newRow("SIGPWR")    << SIGPWR;
0146     QTest::newRow("SIGSYS") << SIGSYS;
0147 #ifdef Q_OS_LINUX
0148 #ifdef SIGSTKFLT
0149     QTest::newRow("SIGSTKFLT") << SIGSTKFLT;
0150 #endif
0151 #ifdef SIGUNUSED
0152     QTest::newRow("SIGUNUSED") << SIGUNUSED;
0153 #endif
0154 #endif
0155 }
0156 
0157 void KillTest::testImmediateKill()
0158 {
0159     // this test ensures that the greeter indicates crashexit when a signal is sent to the greeter
0160     // before it had time to properly setup
0161     QProcess greeter(this);
0162     greeter.start(KLibexec::path(KSCREENLOCKER_GREET_BIN_REL), QStringList({QStringLiteral("--testing")}));
0163     QVERIFY(greeter.waitForStarted());
0164 
0165     // now kill
0166     QFETCH(int, signal);
0167     kill(greeter.processId(), signal);
0168 
0169     QVERIFY(greeter.waitForFinished());
0170     QCOMPARE(greeter.exitStatus(), QProcess::CrashExit);
0171 }
0172 
0173 QTEST_MAIN(KillTest)
0174 #include "killtest.moc"