Make the DBus timeout configurable in QDBusAbstractInterface.
authorDavid Faure <faure@kde.org>
Thu, 18 Aug 2011 15:48:35 +0000 (17:48 +0200)
committerQt by Nokia <qt-info@nokia.com>
Thu, 25 Aug 2011 09:36:52 +0000 (11:36 +0200)
Merge-request: 1253
Reviewed-by: Thiago
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@nokia.com>
(cherry picked from commit e58a402fbee2fc8af8cd651acafdc28525ed1314)

Change-Id: I4246047b149193e510f2984a0b1a1fae655b9a51
Reviewed-on: http://codereview.qt.nokia.com/3580
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@nokia.com>
src/dbus/qdbusabstractinterface.cpp
src/dbus/qdbusabstractinterface.h
src/dbus/qdbusabstractinterface_p.h
tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml
tests/auto/qdbusabstractinterface/interface.cpp
tests/auto/qdbusabstractinterface/interface.h
tests/auto/qdbusabstractinterface/pinger.h
tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp

index 187ad67..9f68313 100644 (file)
@@ -88,6 +88,7 @@ QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv
     : connection(con), service(serv), path(p), interface(iface),
       lastError(checkIfValid(serv, p, iface, isDynamic, (connectionPrivate() &&
                                                          connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode))),
+      timeout(-1),
       isValid(!lastError.isValid())
 {
     if (!isValid)
@@ -144,7 +145,7 @@ void QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp, QVariant &
                                                       QLatin1String("Get"));
     QDBusMessagePrivate::setParametersValidated(msg, true);
     msg << interface << QString::fromUtf8(mp.name());
-    QDBusMessage reply = connection.call(msg, QDBus::Block);
+    QDBusMessage reply = connection.call(msg, QDBus::Block, timeout);
 
     if (reply.type() != QDBusMessage::ReplyMessage) {
         lastError = reply;
@@ -210,7 +211,7 @@ bool QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const Q
                                                 QLatin1String("Set"));
     QDBusMessagePrivate::setParametersValidated(msg, true);
     msg << interface << QString::fromUtf8(mp.name()) << QVariant::fromValue(QDBusVariant(value));
-    QDBusMessage reply = connection.call(msg, QDBus::Block);
+    QDBusMessage reply = connection.call(msg, QDBus::Block, timeout);
 
     if (reply.type() != QDBusMessage::ReplyMessage) {
         lastError = reply;
@@ -384,6 +385,28 @@ QDBusError QDBusAbstractInterface::lastError() const
 }
 
 /*!
+    Sets the timeout in seconds for all future DBus calls to \a timeout.
+    -1 means the default DBus timeout (usually 25 seconds).
+
+    \since 4.8
+*/
+void QDBusAbstractInterface::setTimeout(int timeout)
+{
+    d_func()->timeout = timeout;
+}
+
+/*!
+    Returns the current value of the timeout in seconds.
+    -1 means the default DBus timeout (usually 25 seconds).
+
+    \since 4.8
+*/
+int QDBusAbstractInterface::timeout() const
+{
+    return d_func()->timeout;
+}
+
+/*!
     Places a call to the remote method specified by \a method on this interface, using \a args as
     arguments. This function returns the message that was received as a reply, which can be a normal
     QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call
@@ -442,7 +465,7 @@ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
     QDBusMessagePrivate::setParametersValidated(msg, true);
     msg.setArguments(args);
 
-    QDBusMessage reply = d->connection.call(msg, mode);
+    QDBusMessage reply = d->connection.call(msg, mode, d->timeout);
     if (thread() == QThread::currentThread())
         d->lastError = reply;       // will clear if reply isn't an error
 
@@ -475,7 +498,7 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
     QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), method);
     QDBusMessagePrivate::setParametersValidated(msg, true);
     msg.setArguments(args);
-    return d->connection.asyncCall(msg);
+    return d->connection.asyncCall(msg, d->timeout);
 }
 
 /*!
index 72b922e..34ff410 100644 (file)
@@ -95,6 +95,9 @@ public:
 
     QDBusError lastError() const;
 
+    void setTimeout(int timeout);
+    int timeout() const;
+
     QDBusMessage call(const QString &method,
                       const QVariant &arg1 = QVariant(),
                       const QVariant &arg2 = QVariant(),
index a000daf..4f96165 100644 (file)
@@ -77,6 +77,7 @@ public:
     QString path;
     QString interface;
     mutable QDBusError lastError;
+    int timeout;
 
     // this is set during creation and never changed
     // it can't be const because QDBusInterfacePrivate has one more check
index 1667591..d945ec9 100644 (file)
        <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="RegisteredType"/>
     </signal>
     <method name="voidMethod" />
+    <method name="sleepMethod">
+       <arg type="i" />
+       <arg type="i" direction="out"/>
+    </method>
     <method name="stringMethod">
        <arg type="s" direction="out"/>
     </method>
index 0326177..849db93 100644 (file)
 ****************************************************************************/
 
 #include "interface.h"
+#include <QThread>
 
 Interface::Interface()
 {
 }
 
+// Export the sleep function
+// TODO QT5: remove this class, QThread::msleep is now public
+class FriendlySleepyThread : public QThread {
+public:
+    using QThread::msleep;
+};
+
+int Interface::sleepMethod(int msec)
+{
+    FriendlySleepyThread::msleep(msec);
+    return 42;
+}
+
 #include "moc_interface.cpp"
index b840a38..0fb15fe 100644 (file)
@@ -101,6 +101,7 @@ public:
 
 public slots:
     Q_SCRIPTABLE void voidMethod() {}
+    Q_SCRIPTABLE int sleepMethod(int);
     Q_SCRIPTABLE QString stringMethod() { return "Hello, world"; }
     Q_SCRIPTABLE RegisteredType complexMethod() { return RegisteredType("Hello, world"); }
     Q_SCRIPTABLE QString multiOutMethod(int &value) { value = 42; return "Hello, world"; }
index 6245a5a..739a142 100644 (file)
@@ -117,6 +117,13 @@ public Q_SLOTS: // METHODS
         return reply;
     }
 
+    inline QDBusPendingReply<int> sleepMethod(int in0)
+    {
+        QList<QVariant> argumentList;
+        argumentList << qVariantFromValue(in0);
+        return asyncCallWithArgumentList(QLatin1String("sleepMethod"), argumentList);
+    }
+
     inline QDBusPendingReply<QString> stringMethod()
     {
         QList<QVariant> argumentList;
index 00e3a76..994df05 100644 (file)
@@ -111,6 +111,8 @@ private slots:
     void makeAsyncComplexCallPeer();
     void makeAsyncMultiOutCallPeer();
 
+    void callWithTimeout();
+
     void stringPropRead();
     void stringPropWrite();
     void variantPropRead();
@@ -458,6 +460,96 @@ void tst_QDBusAbstractInterface::makeAsyncMultiOutCallPeer()
     QCoreApplication::instance()->processEvents();
 }
 
+static const char server_serviceName[] = "com.trolltech.autotests.dbusserver";
+static const char server_objectPath[] = "/com/trolltech/server";
+static const char server_interfaceName[] = "com.trolltech.QtDBus.Pinger";
+
+class DBusServerThread : public QThread
+{
+public:
+    DBusServerThread() {
+        start();
+        m_ready.acquire();
+    }
+    ~DBusServerThread() {
+        quit();
+        wait();
+    }
+
+    void run()
+    {
+        QDBusConnection con = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "ThreadConnection");
+        if (!con.isConnected())
+            qWarning("Error registering to DBus");
+        if (!con.registerService(server_serviceName))
+            qWarning("Error registering service name");
+        Interface targetObj;
+        con.registerObject(server_objectPath, &targetObj, QDBusConnection::ExportScriptableContents);
+        m_ready.release();
+        exec();
+
+        QDBusConnection::disconnectFromBus( con.name() );
+    }
+private:
+    QSemaphore m_ready;
+};
+
+void tst_QDBusAbstractInterface::callWithTimeout()
+{
+    QDBusConnection con = QDBusConnection::sessionBus();
+    QVERIFY2(con.isConnected(), "Not connected to D-Bus");
+
+    DBusServerThread serverThread;
+
+    QDBusMessage msg = QDBusMessage::createMethodCall(server_serviceName,
+                                                      server_objectPath, server_interfaceName, "sleepMethod");
+    msg << 100;
+
+    {
+       // Call with no timeout -> works
+        QDBusMessage reply = con.call(msg);
+        QCOMPARE((int)reply.type(), (int)QDBusMessage::ReplyMessage);
+        QCOMPARE(reply.arguments().at(0).toInt(), 42);
+    }
+
+    {
+        // Call with 1 sec timeout -> fails
+        QDBusMessage reply = con.call(msg, QDBus::Block, 1);
+        QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
+    }
+
+    // Now using QDBusInterface
+
+    QDBusInterface iface(server_serviceName, server_objectPath, server_interfaceName, con);
+    {
+        // Call with no timeout
+        QDBusMessage reply = iface.call("sleepMethod", 100);
+        QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+        QCOMPARE(reply.arguments().at(0).toInt(), 42);
+    }
+    {
+        // Call with 1 sec timeout -> fails
+        iface.setTimeout(1);
+        QDBusMessage reply = iface.call("sleepMethod", 100);
+        QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
+    }
+
+    // Now using generated code
+    com::trolltech::QtDBus::Pinger p(server_serviceName, server_objectPath, QDBusConnection::sessionBus());
+    {
+        // Call with no timeout
+        QDBusReply<int> reply = p.sleepMethod(100);
+        QVERIFY(reply.isValid());
+        QCOMPARE(int(reply), 42);
+    }
+    {
+        // Call with 1 sec timeout -> fails
+        p.setTimeout(1);
+        QDBusReply<int> reply = p.sleepMethod(100);
+        QVERIFY(!reply.isValid());
+    }
+}
+
 void tst_QDBusAbstractInterface::stringPropRead()
 {
     Pinger p = getPinger();