diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qdbusconnection/tst_qdbusconnection.cpp | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp index 599abbd..4494d6f 100644 --- a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp +++ b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp @@ -106,6 +106,8 @@ private slots: void slotsWithLessParameters(); void nestedCallWithCallback(); + void serviceRegistrationRaceCondition(); + public: QString serviceName() const { return "com.trolltech.Qt.Autotests.QDBusConnection"; } bool callMethod(const QDBusConnection &conn, const QString &path); @@ -647,6 +649,73 @@ void tst_QDBusConnection::nestedCallWithCallback() QCOMPARE(signalsReceived, 1); } +class RaceConditionSignalWaiter : public QObject +{ + Q_OBJECT +public: + int count; + RaceConditionSignalWaiter() : count (0) {} + virtual ~RaceConditionSignalWaiter() {} + +public slots: + void countUp() { ++count; emit done(); } +signals: + void done(); +}; + +void tst_QDBusConnection::serviceRegistrationRaceCondition() +{ + // There was a race condition in the updating of list of name owners in + // QtDBus. When the user connects to a signal coming from a given + // service, we must listen for NameOwnerChanged signals relevant to that + // name and update when the owner changes. However, it's possible that we + // receive in one chunk from the server both the NameOwnerChanged signal + // about the service and the signal we're interested in. Since QtDBus + // posts events in order to handle the incoming signals, the update + // happens too late. + + const QString connectionName = "testConnectionName"; + const QString serviceName = "org.example.SecondaryName"; + + QDBusConnection session = QDBusConnection::sessionBus(); + QVERIFY(!session.interface()->isServiceRegistered(serviceName)); + + // connect to the signal: + RaceConditionSignalWaiter recv; + session.connect(serviceName, "/", "com.trolltech.TestCase", "oneSignal", &recv, SLOT(countUp())); + + // create a secondary connection and register a name + QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, connectionName); + QDBusConnection::disconnectFromBus(connectionName); // disconnection happens when "connection" goes out of scope + QVERIFY(connection.isConnected()); + QVERIFY(connection.registerService(serviceName)); + + // send a signal + QDBusMessage msg = QDBusMessage::createSignal("/", "com.trolltech.TestCase", "oneSignal"); + connection.send(msg); + + // make a blocking call just to be sure that the buffer was flushed + msg = QDBusMessage::createMethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", + "NameHasOwner"); + msg << connectionName; + connection.call(msg); // ignore result + + // Now here's the race condition (more info on task QTBUG-15651): + // the bus has most likely queued three signals for us to work on: + // 1) NameOwnerChanged for the connection we created above + // 2) NameOwnerChanged for the service we registered above + // 3) The "oneSignal" signal we sent + // + // We'll most likely receive all three in one go from the server. We must + // update the owner of serviceName before we start processing the + // "oneSignal" signal. + + QTestEventLoop::instance().connect(&recv, SIGNAL(done()), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(recv.count, 1); +} + QString MyObject::path; QTEST_MAIN(tst_QDBusConnection) |