Fix race condition in tst_QDBusConnection::pendingCallWhenDisconnected

The test sent a message and hoped that the "delete server" would cause
the server object in the QDBusConnectionManager thread be deleted before
it could receive and process the message. That's racy, because on some
CI machines, it did and then sent back an error reply indicating the
object sought was not found.

Instead, let's use a child process that we can kill to make it exit at
the right time.

I've chosen to use dbus-daemon itself, because that lets us test the
actual conditions that triggered the original bug: the daemon getting
killed during a desktop session shutdown on Linux.

Change-Id: I87e17314d8b24ae983b1fffd1454483aea87c921
Reviewed-by: Tony Sarajärvi <tony.sarajarvi@qt.io>
bb10
Thiago Macieira 2016-06-02 10:46:36 -03:00 committed by Tony Sarajärvi
parent d5ac97e36f
commit f8b5142e30
1 changed files with 30 additions and 9 deletions

View File

@ -40,6 +40,11 @@
#include <QtTest/QtTest>
#include <QtDBus/QtDBus>
#ifdef Q_OS_UNIX
# include <sys/types.h>
# include <signal.h>
#endif
void MyObject::method(const QDBusMessage &msg)
{
path = msg.path();
@ -1357,23 +1362,39 @@ void tst_QDBusConnection::callVirtualObjectLocal()
void tst_QDBusConnection::pendingCallWhenDisconnected()
{
#ifdef QT_NO_PROCESS
QSKIP("Test requires QProcess");
#else
if (!QCoreApplication::instance())
QSKIP("Test requires a QCoreApplication");
QDBusServer *server = new QDBusServer;
QDBusConnection con = QDBusConnection::connectToPeer(server->address(), "disconnect");
QTestEventLoop::instance().enterLoop(2);
QVERIFY(con.isConnected());
QDBusMessage message = QDBusMessage::createMethodCall("", "/", QString(), "method");
QProcess daemon;
daemon.start("dbus-daemon", QStringList() << "--session" << "--nofork" << "--print-address");
QVERIFY2(daemon.waitForReadyRead(2000),
"Daemon didn't print its address in time; error: \"" + daemon.errorString().toLocal8Bit() +
"\"; stderr:\n" + daemon.readAllStandardError());
QString address = QString::fromLocal8Bit(daemon.readAll().trimmed());
QDBusConnection con = QDBusConnection::connectToBus(address, "disconnect");
QVERIFY2(con.isConnected(), (con.lastError().name() + ": " + con.lastError().message()).toLocal8Bit());
// confirm we're connected and we're alone in this bus
QCOMPARE(con.baseService(), QString(":1.0"));
// kill the bus
daemon.terminate();
daemon.waitForFinished();
// send something, which we should get an error with
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.DBus", "/", QString(), "ListNames");
QDBusPendingCall reply = con.asyncCall(message);
delete server;
QTestEventLoop::instance().enterLoop(2);
reply.waitForFinished();
QVERIFY(!con.isConnected());
QVERIFY(reply.isFinished());
QVERIFY(reply.isError());
QVERIFY(reply.error().type() == QDBusError::Disconnected);
QCOMPARE(reply.error().type(), QDBusError::Disconnected);
#endif
}
QString MyObject::path;