File: deadservicetest.cpp

package info (click to toggle)
kdbusaddons 5.116.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 612 kB
  • sloc: cpp: 1,144; xml: 32; sh: 14; makefile: 7
file content (107 lines) | stat: -rw-r--r-- 3,601 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
   This file is part of libkdbus

    SPDX-FileCopyrightText: 2019 Harald Sitter <sitter@kde.org>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusServiceWatcher>
#include <QDebug>
#include <QProcess>
#include <QTest>

#include <signal.h>
#include <unistd.h>

static const QString s_serviceName = QStringLiteral("org.kde.kdbussimpleservice");

class TestObject : public QObject
{
    Q_OBJECT

    QList<int> m_danglingPids;
private Q_SLOTS:
    void cleanupTestCase()
    {
        // Make sure we don't leave dangling processes even when we had an
        // error and the process is stopped.
        for (int pid : m_danglingPids) {
            kill(pid, SIGKILL);
        }
    }

    void testDeadService()
    {
        QVERIFY(!QDBusConnection::sessionBus().interface()->isServiceRegistered(s_serviceName).value());

        QProcess proc1;
        proc1.setProgram(QFINDTESTDATA("kdbussimpleservice"));
        proc1.setProcessChannelMode(QProcess::ForwardedChannels);
        proc1.start();
        QVERIFY(proc1.waitForStarted());
        m_danglingPids << proc1.processId();

        // Spy isn't very suitable here because we'd be racing with proc1 or
        // signal blocking since we'd need to unblock before spying but then
        // there is an ɛ between unblock and spy.
        qint64 pid1 = proc1.processId(); // store local, in case the proc disappears
        QVERIFY(pid1 >= 0);
        bool proc1Registered = QTest::qWaitFor(
            [&]() {
                QTest::qSleep(1000);
                return QDBusConnection::sessionBus().interface()->servicePid(s_serviceName).value() == pid1;
            },
            8000);
        QVERIFY(proc1Registered);

        // suspend proc1, we don't want it responding on dbus anymore, but still
        // be running so it holds the name.
        QCOMPARE(kill(proc1.processId(), SIGSTOP), 0);

        // start second instance
        QProcess proc2;
        proc2.setProgram(QFINDTESTDATA("kdbussimpleservice"));
        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
        env.insert("KCRASH_AUTO_RESTARTED", "1");
        proc2.setProcessEnvironment(env);
        proc2.setProcessChannelMode(QProcess::ForwardedChannels);
        proc2.start();
        QVERIFY(proc2.waitForStarted());
        m_danglingPids << proc2.processId();

        // sleep a bit. fairly awkward. we need proc2 to be waiting on the name
        // but we can't easily determine when it started waiting. in lieu of
        // better instrumentation let's just sleep a bit.
        qDebug() << "sleeping";
        QTest::qSleep(4000);

        // Let proc1 go up in flames so that dbus-daemon reclaims the name and
        // gives it to proc2.
        qDebug() << "murder on the orient express";
        QCOMPARE(0, kill(proc1.processId(), SIGUSR1));
        QCOMPARE(0, kill(proc1.processId(), SIGCONT));

        qint64 pid2 = proc2.processId(); // store local, in case the proc disappears
        QVERIFY(pid2 >= 0);
        // Wait for service to be owned by proc2.
        bool proc2Registered = QTest::qWaitFor(
            [&]() {
                QTest::qSleep(1000);
                return QDBusConnection::sessionBus().interface()->servicePid(s_serviceName).value() == pid2;
            },
            8000);
        QVERIFY(proc2Registered);

        proc1.kill();
        m_danglingPids.removeAll(pid1);
        proc2.kill();
        m_danglingPids.removeAll(pid2);
    }
};

QTEST_MAIN(TestObject)

#include "deadservicetest.moc"