File indexing completed on 2024-04-28 15:20:30

0001 /*
0002    This file is part of libkdbus
0003 
0004     SPDX-FileCopyrightText: 2019 Harald Sitter <sitter@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include <QDBusConnection>
0010 #include <QDBusConnectionInterface>
0011 #include <QDBusServiceWatcher>
0012 #include <QDebug>
0013 #include <QProcess>
0014 #include <QTest>
0015 
0016 #include <signal.h>
0017 #include <unistd.h>
0018 
0019 static const QString s_serviceName = QStringLiteral("org.kde.kdbussimpleservice");
0020 
0021 class TestObject : public QObject
0022 {
0023     Q_OBJECT
0024 
0025     QList<int> m_danglingPids;
0026 private Q_SLOTS:
0027     void cleanupTestCase()
0028     {
0029         // Make sure we don't leave dangling processes even when we had an
0030         // error and the process is stopped.
0031         for (int pid : m_danglingPids) {
0032             kill(pid, SIGKILL);
0033         }
0034     }
0035 
0036     void testDeadService()
0037     {
0038         QVERIFY(!QDBusConnection::sessionBus().interface()->isServiceRegistered(s_serviceName).value());
0039 
0040         QProcess proc1;
0041         proc1.setProgram(QFINDTESTDATA("kdbussimpleservice"));
0042         proc1.setProcessChannelMode(QProcess::ForwardedChannels);
0043         proc1.start();
0044         QVERIFY(proc1.waitForStarted());
0045         m_danglingPids << proc1.processId();
0046 
0047         // Spy isn't very suitable here because we'd be racing with proc1 or
0048         // signal blocking since we'd need to unblock before spying but then
0049         // there is an ɛ between unblock and spy.
0050         qint64 pid1 = proc1.processId(); // store local, in case the proc disappears
0051         QVERIFY(pid1 >= 0);
0052         bool proc1Registered = QTest::qWaitFor(
0053             [&]() {
0054                 QTest::qSleep(1000);
0055                 return QDBusConnection::sessionBus().interface()->servicePid(s_serviceName).value() == pid1;
0056             },
0057             8000);
0058         QVERIFY(proc1Registered);
0059 
0060         // suspend proc1, we don't want it responding on dbus anymore, but still
0061         // be running so it holds the name.
0062         QCOMPARE(kill(proc1.processId(), SIGSTOP), 0);
0063 
0064         // start second instance
0065         QProcess proc2;
0066         proc2.setProgram(QFINDTESTDATA("kdbussimpleservice"));
0067         QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
0068         env.insert("KCRASH_AUTO_RESTARTED", "1");
0069         proc2.setProcessEnvironment(env);
0070         proc2.setProcessChannelMode(QProcess::ForwardedChannels);
0071         proc2.start();
0072         QVERIFY(proc2.waitForStarted());
0073         m_danglingPids << proc2.processId();
0074 
0075         // sleep a bit. fairly awkward. we need proc2 to be waiting on the name
0076         // but we can't easily determine when it started waiting. in lieu of
0077         // better instrumentation let's just sleep a bit.
0078         qDebug() << "sleeping";
0079         QTest::qSleep(4000);
0080 
0081         // Let proc1 go up in flames so that dbus-daemon reclaims the name and
0082         // gives it to proc2.
0083         qDebug() << "murder on the orient express";
0084         QCOMPARE(0, kill(proc1.processId(), SIGUSR1));
0085         QCOMPARE(0, kill(proc1.processId(), SIGCONT));
0086 
0087         qint64 pid2 = proc2.processId(); // store local, in case the proc disappears
0088         QVERIFY(pid2 >= 0);
0089         // Wait for service to be owned by proc2.
0090         bool proc2Registered = QTest::qWaitFor(
0091             [&]() {
0092                 QTest::qSleep(1000);
0093                 return QDBusConnection::sessionBus().interface()->servicePid(s_serviceName).value() == pid2;
0094             },
0095             8000);
0096         QVERIFY(proc2Registered);
0097 
0098         proc1.kill();
0099         m_danglingPids.removeAll(pid1);
0100         proc2.kill();
0101         m_danglingPids.removeAll(pid2);
0102     }
0103 };
0104 
0105 QTEST_MAIN(TestObject)
0106 
0107 #include "deadservicetest.moc"