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"