0d75f8e95a
The explanation is in the code comment. Ever since QDBusConnections began being processed in a separate thread, we were relying on the fact that the main thread didn't begin processing its event queue until the second event got posted (the event loop only exits after it has finished processing all pending events). We had a race between the main thread starting its processing, at which point it decides which is the last event it will process, and the QDBusConnectionManager thread posting the second event. This is very fragile code, since it depends on the behavior of QDBusConnectionPrivate (how it stores the signal relays in a hash) and that of QHash with duplicate keys. This only works because the hash key between the two connections is the same (it's only dependent on the method name and interface name). If we ever begin using something that isn't the same between "control" and "p", then with QHash's randomness, we'll be racy again. Change-Id: I42e7ef1a481840699a8dffff1406c3a4674ec3a6 Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
1419 lines
43 KiB
C++
1419 lines
43 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
#include <qcoreapplication.h>
|
|
#include <qdebug.h>
|
|
#include <qsharedpointer.h>
|
|
|
|
#include <QtTest/QtTest>
|
|
|
|
#include <QtDBus>
|
|
|
|
#include "interface.h"
|
|
#include "pinger_interface.h"
|
|
|
|
static const char serviceName[] = "org.qtproject.autotests.qpinger";
|
|
static const char objectPath[] = "/org/qtproject/qpinger";
|
|
static const char *interfaceName = serviceName;
|
|
|
|
typedef QSharedPointer<org::qtproject::QtDBus::Pinger> Pinger;
|
|
|
|
class tst_QDBusAbstractInterface: public QObject
|
|
{
|
|
Q_OBJECT
|
|
Interface targetObj;
|
|
QString peerAddress;
|
|
|
|
Pinger getPinger(QString service = "", const QString &path = "/")
|
|
{
|
|
QDBusConnection con = QDBusConnection::sessionBus();
|
|
if (!con.isConnected())
|
|
return Pinger();
|
|
if (service.isEmpty() && !service.isNull())
|
|
service = con.baseService();
|
|
return Pinger(new org::qtproject::QtDBus::Pinger(service, path, con));
|
|
}
|
|
|
|
Pinger getPingerPeer(const QString &path = "/", const QString &service = "")
|
|
{
|
|
QDBusConnection con = QDBusConnection("peer");
|
|
if (!con.isConnected())
|
|
return Pinger();
|
|
return Pinger(new org::qtproject::QtDBus::Pinger(service, path, con));
|
|
}
|
|
|
|
void resetServer()
|
|
{
|
|
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "reset");
|
|
QDBusConnection::sessionBus().send(req);
|
|
}
|
|
|
|
public:
|
|
tst_QDBusAbstractInterface();
|
|
|
|
private slots:
|
|
void initTestCase();
|
|
void cleanupTestCase();
|
|
|
|
void init();
|
|
void cleanup();
|
|
|
|
void makeVoidCall();
|
|
void makeStringCall();
|
|
void makeComplexCall();
|
|
void makeMultiOutCall();
|
|
|
|
void makeVoidCallPeer();
|
|
void makeStringCallPeer();
|
|
void makeComplexCallPeer();
|
|
void makeMultiOutCallPeer();
|
|
|
|
void makeAsyncVoidCall();
|
|
void makeAsyncStringCall();
|
|
void makeAsyncComplexCall();
|
|
void makeAsyncMultiOutCall();
|
|
|
|
void makeAsyncVoidCallPeer();
|
|
void makeAsyncStringCallPeer();
|
|
void makeAsyncComplexCallPeer();
|
|
void makeAsyncMultiOutCallPeer();
|
|
|
|
void callWithTimeout();
|
|
|
|
void stringPropRead();
|
|
void stringPropWrite();
|
|
void variantPropRead();
|
|
void variantPropWrite();
|
|
void complexPropRead();
|
|
void complexPropWrite();
|
|
|
|
void stringPropReadPeer();
|
|
void stringPropWritePeer();
|
|
void variantPropReadPeer();
|
|
void variantPropWritePeer();
|
|
void complexPropReadPeer();
|
|
void complexPropWritePeer();
|
|
|
|
void stringPropDirectRead();
|
|
void stringPropDirectWrite();
|
|
void variantPropDirectRead();
|
|
void variantPropDirectWrite();
|
|
void complexPropDirectRead();
|
|
void complexPropDirectWrite();
|
|
|
|
void stringPropDirectReadPeer();
|
|
void stringPropDirectWritePeer();
|
|
void variantPropDirectReadPeer();
|
|
void variantPropDirectWritePeer();
|
|
void complexPropDirectReadPeer();
|
|
void complexPropDirectWritePeer();
|
|
|
|
void getVoidSignal_data();
|
|
void getVoidSignal();
|
|
void getStringSignal_data();
|
|
void getStringSignal();
|
|
void getComplexSignal_data();
|
|
void getComplexSignal();
|
|
|
|
void getVoidSignalPeer_data();
|
|
void getVoidSignalPeer();
|
|
void getStringSignalPeer_data();
|
|
void getStringSignalPeer();
|
|
void getComplexSignalPeer_data();
|
|
void getComplexSignalPeer();
|
|
|
|
void followSignal();
|
|
|
|
void connectDisconnect_data();
|
|
void connectDisconnect();
|
|
void connectDisconnectPeer_data();
|
|
void connectDisconnectPeer();
|
|
|
|
void createErrors_data();
|
|
void createErrors();
|
|
|
|
void createErrorsPeer_data();
|
|
void createErrorsPeer();
|
|
|
|
void callErrors_data();
|
|
void callErrors();
|
|
void asyncCallErrors_data();
|
|
void asyncCallErrors();
|
|
|
|
void callErrorsPeer_data();
|
|
void callErrorsPeer();
|
|
void asyncCallErrorsPeer_data();
|
|
void asyncCallErrorsPeer();
|
|
|
|
void propertyReadErrors_data();
|
|
void propertyReadErrors();
|
|
void propertyWriteErrors_data();
|
|
void propertyWriteErrors();
|
|
void directPropertyReadErrors_data();
|
|
void directPropertyReadErrors();
|
|
void directPropertyWriteErrors_data();
|
|
void directPropertyWriteErrors();
|
|
|
|
void propertyReadErrorsPeer_data();
|
|
void propertyReadErrorsPeer();
|
|
void propertyWriteErrorsPeer_data();
|
|
void propertyWriteErrorsPeer();
|
|
void directPropertyReadErrorsPeer_data();
|
|
void directPropertyReadErrorsPeer();
|
|
void directPropertyWriteErrorsPeer_data();
|
|
void directPropertyWriteErrorsPeer();
|
|
|
|
void validity_data();
|
|
void validity();
|
|
|
|
private:
|
|
QProcess proc;
|
|
};
|
|
|
|
class SignalReceiver : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
int callCount;
|
|
SignalReceiver() : callCount(0) {}
|
|
public slots:
|
|
void receive() { ++callCount; }
|
|
};
|
|
|
|
tst_QDBusAbstractInterface::tst_QDBusAbstractInterface()
|
|
{
|
|
// register the meta types
|
|
qDBusRegisterMetaType<RegisteredType>();
|
|
qRegisterMetaType<UnregisteredType>();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::initTestCase()
|
|
{
|
|
// enable debugging temporarily:
|
|
//putenv("QDBUS_DEBUG=1");
|
|
|
|
// register the object
|
|
QDBusConnection con = QDBusConnection::sessionBus();
|
|
QVERIFY(con.isConnected());
|
|
con.registerObject("/", &targetObj, QDBusConnection::ExportScriptableContents);
|
|
|
|
// verify service isn't registered by something else
|
|
// (e.g. a left over qpinger from a previous test run)
|
|
QVERIFY(!con.interface()->isServiceRegistered(serviceName));
|
|
|
|
// start peer server
|
|
#ifdef Q_OS_WIN
|
|
# define EXE ".exe"
|
|
#else
|
|
# define EXE ""
|
|
#endif
|
|
proc.setProcessChannelMode(QProcess::ForwardedErrorChannel);
|
|
proc.start(QFINDTESTDATA("qpinger/qpinger" EXE));
|
|
QVERIFY2(proc.waitForStarted(), qPrintable(proc.errorString()));
|
|
QVERIFY(proc.waitForReadyRead());
|
|
|
|
// verify service is now registered
|
|
QTRY_VERIFY(con.interface()->isServiceRegistered(serviceName));
|
|
|
|
// get peer server address
|
|
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "address");
|
|
QDBusMessage rpl = con.call(req);
|
|
QVERIFY(rpl.type() == QDBusMessage::ReplyMessage);
|
|
peerAddress = rpl.arguments().at(0).toString();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::cleanupTestCase()
|
|
{
|
|
QDBusMessage msg = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "quit");
|
|
QDBusConnection::sessionBus().call(msg);
|
|
proc.waitForFinished(200);
|
|
proc.close();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::init()
|
|
{
|
|
QDBusConnection con = QDBusConnection::sessionBus();
|
|
QVERIFY(con.isConnected());
|
|
|
|
// connect to peer server
|
|
QDBusConnection peercon = QDBusConnection::connectToPeer(peerAddress, "peer");
|
|
QVERIFY(peercon.isConnected());
|
|
|
|
QDBusMessage req2 = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "waitForConnected");
|
|
QDBusMessage rpl2 = con.call(req2);
|
|
QVERIFY2(rpl2.type() == QDBusMessage::ReplyMessage, rpl2.errorMessage().toLatin1());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::cleanup()
|
|
{
|
|
QDBusConnection::disconnectFromPeer("peer");
|
|
|
|
// Reset the object exported by this process
|
|
targetObj.m_stringProp = QString();
|
|
targetObj.m_variantProp = QDBusVariant();
|
|
targetObj.m_complexProp = RegisteredType();
|
|
|
|
QDBusMessage resetCall = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "reset");
|
|
QVERIFY(QDBusConnection::sessionBus().call(resetCall).type() == QDBusMessage::ReplyMessage);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeVoidCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusReply<void> r = p->voidMethod();
|
|
QVERIFY(r.isValid());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeStringCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusReply<QString> r = p->stringMethod();
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.stringMethod());
|
|
}
|
|
|
|
static QHash<QString, QVariant> complexMethodArgs()
|
|
{
|
|
QHash<QString, QVariant> args;
|
|
args.insert("arg1", "Hello world");
|
|
args.insert("arg2", 12345);
|
|
return args;
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeComplexCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusReply<RegisteredType> r = p->complexMethod(complexMethodArgs());
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs()));
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeMultiOutCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
int value;
|
|
QDBusReply<QString> r = p->multiOutMethod(value);
|
|
QVERIFY(r.isValid());
|
|
|
|
int expectedValue;
|
|
QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
|
|
QCOMPARE(value, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeVoidCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusReply<void> r = p->voidMethod();
|
|
QVERIFY(r.isValid());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeStringCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusReply<QString> r = p->stringMethod();
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.stringMethod());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeComplexCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusReply<RegisteredType> r = p->complexMethod(complexMethodArgs());
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs()));
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeMultiOutCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
int value;
|
|
QDBusReply<QString> r = p->multiOutMethod(value);
|
|
QVERIFY(r.isValid());
|
|
|
|
int expectedValue;
|
|
QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
|
|
QCOMPARE(value, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeAsyncVoidCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusPendingReply<void> r = p->voidMethod();
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeAsyncStringCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusPendingReply<QString> r = p->stringMethod();
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.stringMethod());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeAsyncComplexCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusPendingReply<RegisteredType> r = p->complexMethod(complexMethodArgs());
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs()));
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeAsyncMultiOutCall()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusPendingReply<QString, int> r = p->multiOutMethod();
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
|
|
int expectedValue;
|
|
QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
|
|
QCOMPARE(r.argumentAt<1>(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeAsyncVoidCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusPendingReply<void> r = p->voidMethod();
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
}
|
|
void tst_QDBusAbstractInterface::makeAsyncStringCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusMessage reply = p->call(QDBus::BlockWithGui, QLatin1String("voidMethod"));
|
|
QVERIFY(reply.type() == QDBusMessage::ReplyMessage);
|
|
|
|
QDBusPendingReply<QString> r = p->stringMethod();
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.stringMethod());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeAsyncComplexCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusPendingReply<RegisteredType> r = p->complexMethod(complexMethodArgs());
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
QCOMPARE(r.value(), targetObj.complexMethod(complexMethodArgs()));
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::makeAsyncMultiOutCallPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusPendingReply<QString, int> r = p->multiOutMethod();
|
|
r.waitForFinished();
|
|
QVERIFY(r.isValid());
|
|
|
|
int expectedValue;
|
|
QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue));
|
|
QCOMPARE(r.argumentAt<1>(), expectedValue);
|
|
QCoreApplication::instance()->processEvents();
|
|
}
|
|
|
|
static const char server_serviceName[] = "org.qtproject.autotests.dbusserver";
|
|
static const char server_objectPath[] = "/org/qtproject/server";
|
|
static const char server_interfaceName[] = "org.qtproject.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; // sleep 100 ms
|
|
|
|
{
|
|
// 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 msec 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 msec timeout -> fails
|
|
iface.setTimeout(1);
|
|
QDBusMessage reply = iface.call("sleepMethod", 100);
|
|
QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
|
|
}
|
|
{
|
|
// Call with 300 msec timeout -> works
|
|
iface.setTimeout(300);
|
|
QDBusMessage reply = iface.call("sleepMethod", 100);
|
|
QCOMPARE(reply.arguments().at(0).toInt(), 42);
|
|
}
|
|
|
|
// Now using generated code
|
|
org::qtproject::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 msec timeout -> fails
|
|
p.setTimeout(1);
|
|
QDBusReply<int> reply = p.sleepMethod(100);
|
|
QVERIFY(!reply.isValid());
|
|
}
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropRead()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QString expectedValue = targetObj.m_stringProp = "This is a test";
|
|
QVariant v = p->property("stringProp");
|
|
QVERIFY(v.isValid());
|
|
QCOMPARE(v.toString(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropWrite()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QString expectedValue = "This is a value";
|
|
QVERIFY(p->setProperty("stringProp", expectedValue));
|
|
QCOMPARE(targetObj.m_stringProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropRead()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusVariant expectedValue = targetObj.m_variantProp = QDBusVariant(QVariant(42));
|
|
QVariant v = p->property("variantProp");
|
|
QVERIFY(v.isValid());
|
|
QDBusVariant value = v.value<QDBusVariant>();
|
|
QCOMPARE(value.variant().userType(), expectedValue.variant().userType());
|
|
QCOMPARE(value.variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropWrite()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
|
|
QVERIFY(p->setProperty("variantProp", QVariant::fromValue(expectedValue)));
|
|
QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropRead()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
RegisteredType expectedValue = targetObj.m_complexProp = RegisteredType("This is a test");
|
|
QVariant v = p->property("complexProp");
|
|
QVERIFY(v.userType() == qMetaTypeId<RegisteredType>());
|
|
QCOMPARE(v.value<RegisteredType>(), targetObj.m_complexProp);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropWrite()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
RegisteredType expectedValue = RegisteredType("This is a value");
|
|
QVERIFY(p->setProperty("complexProp", QVariant::fromValue(expectedValue)));
|
|
QCOMPARE(targetObj.m_complexProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropReadPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QString expectedValue = "This is a test";
|
|
QVariant v = p->property("stringProp");
|
|
QVERIFY(v.isValid());
|
|
QCOMPARE(v.toString(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropWritePeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QString expectedValue = "This is a value";
|
|
QVERIFY(p->setProperty("stringProp", expectedValue));
|
|
QEXPECT_FAIL("", "QTBUG-24262 peer tests are broken", Abort);
|
|
QCOMPARE(targetObj.m_stringProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropReadPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QDBusVariant expectedValue = QDBusVariant(QVariant(42));
|
|
QVariant v = p->property("variantProp");
|
|
QVERIFY(v.isValid());
|
|
QDBusVariant value = v.value<QDBusVariant>();
|
|
QCOMPARE(value.variant().userType(), expectedValue.variant().userType());
|
|
QCOMPARE(value.variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropWritePeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
|
|
QVERIFY(p->setProperty("variantProp", QVariant::fromValue(expectedValue)));
|
|
QEXPECT_FAIL("", "QTBUG-24262 peer tests are broken", Abort);
|
|
QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropReadPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
RegisteredType expectedValue = RegisteredType("This is a test");
|
|
QVariant v = p->property("complexProp");
|
|
QVERIFY(v.userType() == qMetaTypeId<RegisteredType>());
|
|
QCOMPARE(v.value<RegisteredType>(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropWritePeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
RegisteredType expectedValue = RegisteredType("This is a value");
|
|
QVERIFY(p->setProperty("complexProp", QVariant::fromValue(expectedValue)));
|
|
QEXPECT_FAIL("", "QTBUG-24262 peer tests are broken", Abort);
|
|
QCOMPARE(targetObj.m_complexProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropDirectRead()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QString expectedValue = targetObj.m_stringProp = "This is a test";
|
|
QCOMPARE(p->stringProp(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropDirectWrite()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QString expectedValue = "This is a value";
|
|
p->setStringProp(expectedValue);
|
|
QCOMPARE(targetObj.m_stringProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropDirectRead()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusVariant expectedValue = targetObj.m_variantProp = QDBusVariant(42);
|
|
QCOMPARE(p->variantProp().variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropDirectWrite()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
|
|
p->setVariantProp(expectedValue);
|
|
QCOMPARE(targetObj.m_variantProp.variant().userType(), expectedValue.variant().userType());
|
|
QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropDirectRead()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
RegisteredType expectedValue = targetObj.m_complexProp = RegisteredType("This is a test");
|
|
QCOMPARE(p->complexProp(), targetObj.m_complexProp);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropDirectWrite()
|
|
{
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
RegisteredType expectedValue = RegisteredType("This is a value");
|
|
p->setComplexProp(expectedValue);
|
|
QCOMPARE(targetObj.m_complexProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropDirectReadPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QString expectedValue = "This is a test";
|
|
QCOMPARE(p->stringProp(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::stringPropDirectWritePeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QString expectedValue = "This is a value";
|
|
p->setStringProp(expectedValue);
|
|
QEXPECT_FAIL("", "QTBUG-24262 peer tests are broken", Abort);
|
|
QCOMPARE(targetObj.m_stringProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropDirectReadPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QDBusVariant expectedValue = QDBusVariant(42);
|
|
QCOMPARE(p->variantProp().variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::variantPropDirectWritePeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47));
|
|
p->setVariantProp(expectedValue);
|
|
QEXPECT_FAIL("", "QTBUG-24262 peer tests are broken", Abort);
|
|
QCOMPARE(targetObj.m_variantProp.variant().userType(), expectedValue.variant().userType());
|
|
QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropDirectReadPeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
RegisteredType expectedValue = RegisteredType("This is a test");
|
|
QCOMPARE(p->complexProp(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::complexPropDirectWritePeer()
|
|
{
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
resetServer();
|
|
|
|
RegisteredType expectedValue = RegisteredType("This is a value");
|
|
p->setComplexProp(expectedValue);
|
|
QEXPECT_FAIL("", "QTBUG-24262 peer tests are broken", Abort);
|
|
QCOMPARE(targetObj.m_complexProp, expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getVoidSignal_data()
|
|
{
|
|
QTest::addColumn<QString>("service");
|
|
QTest::addColumn<QString>("path");
|
|
|
|
QTest::newRow("specific") << QDBusConnection::sessionBus().baseService() << "/";
|
|
QTest::newRow("service-wildcard") << QString() << "/";
|
|
QTest::newRow("path-wildcard") << QDBusConnection::sessionBus().baseService() << QString();
|
|
QTest::newRow("full-wildcard") << QString() << QString();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getVoidSignal()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we need to connect the signal somewhere in order for D-Bus to enable the rules
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
|
|
QSignalSpy s(p.data(), SIGNAL(voidSignal()));
|
|
|
|
emit targetObj.voidSignal();
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
QVERIFY(s.size() == 1);
|
|
QVERIFY(s.at(0).size() == 0);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getStringSignal_data()
|
|
{
|
|
getVoidSignal_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getStringSignal()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we need to connect the signal somewhere in order for D-Bus to enable the rules
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(stringSignal(QString)), SLOT(exitLoop()));
|
|
QSignalSpy s(p.data(), SIGNAL(stringSignal(QString)));
|
|
|
|
QString expectedValue = "Good morning";
|
|
emit targetObj.stringSignal(expectedValue);
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
QVERIFY(s.size() == 1);
|
|
QVERIFY(s[0].size() == 1);
|
|
QCOMPARE(s[0][0].userType(), int(QVariant::String));
|
|
QCOMPARE(s[0][0].toString(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getComplexSignal_data()
|
|
{
|
|
getVoidSignal_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getComplexSignal()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we need to connect the signal somewhere in order for D-Bus to enable the rules
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(complexSignal(RegisteredType)), SLOT(exitLoop()));
|
|
QSignalSpy s(p.data(), SIGNAL(complexSignal(RegisteredType)));
|
|
|
|
RegisteredType expectedValue("Good evening");
|
|
emit targetObj.complexSignal(expectedValue);
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
QVERIFY(s.size() == 1);
|
|
QVERIFY(s[0].size() == 1);
|
|
QCOMPARE(s[0][0].userType(), qMetaTypeId<RegisteredType>());
|
|
QCOMPARE(s[0][0].value<RegisteredType>(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getVoidSignalPeer_data()
|
|
{
|
|
QTest::addColumn<QString>("path");
|
|
|
|
QTest::newRow("specific") << "/";
|
|
QTest::newRow("wildcard") << QString();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getVoidSignalPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we need to connect the signal somewhere in order for D-Bus to enable the rules
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
|
|
QSignalSpy s(p.data(), SIGNAL(voidSignal()));
|
|
|
|
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "voidSignal");
|
|
QVERIFY(QDBusConnection::sessionBus().send(req));
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
QVERIFY(s.size() == 1);
|
|
QVERIFY(s.at(0).size() == 0);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getStringSignalPeer_data()
|
|
{
|
|
getVoidSignalPeer_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getStringSignalPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we need to connect the signal somewhere in order for D-Bus to enable the rules
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(stringSignal(QString)), SLOT(exitLoop()));
|
|
QSignalSpy s(p.data(), SIGNAL(stringSignal(QString)));
|
|
|
|
QString expectedValue = "Good morning";
|
|
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "stringSignal");
|
|
req << expectedValue;
|
|
QVERIFY(QDBusConnection::sessionBus().send(req));
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
QVERIFY(s.size() == 1);
|
|
QVERIFY(s[0].size() == 1);
|
|
QCOMPARE(s[0][0].userType(), int(QVariant::String));
|
|
QCOMPARE(s[0][0].toString(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getComplexSignalPeer_data()
|
|
{
|
|
getVoidSignalPeer_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::getComplexSignalPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we need to connect the signal somewhere in order for D-Bus to enable the rules
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(complexSignal(RegisteredType)), SLOT(exitLoop()));
|
|
QSignalSpy s(p.data(), SIGNAL(complexSignal(RegisteredType)));
|
|
|
|
RegisteredType expectedValue("Good evening");
|
|
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "complexSignal");
|
|
req << "Good evening";
|
|
QVERIFY(QDBusConnection::sessionBus().send(req));
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
QVERIFY(s.size() == 1);
|
|
QVERIFY(s[0].size() == 1);
|
|
QCOMPARE(s[0][0].userType(), qMetaTypeId<RegisteredType>());
|
|
QCOMPARE(s[0][0].value<RegisteredType>(), expectedValue);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::followSignal()
|
|
{
|
|
const QString serviceToFollow = "org.qtproject.tst_qdbusabstractinterface.FollowMe";
|
|
Pinger p = getPinger(serviceToFollow);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QDBusConnection con = p->connection();
|
|
QVERIFY(!con.interface()->isServiceRegistered(serviceToFollow));
|
|
Pinger control = getPinger("");
|
|
|
|
// connect our test signal
|
|
// FRAGILE CODE AHEAD:
|
|
// Connection order is important: we connect the control first because that
|
|
// needs to be delivered last, to ensure that we don't exitLoop() before
|
|
// the signal delivery to QSignalSpy is posted to the current thread. That
|
|
// happens because QDBusConnectionPrivate runs in a separate thread and
|
|
// uses a QMultiHash and insertMulti prepends to the list of items with the
|
|
// same key.
|
|
QTestEventLoop::instance().connect(control.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
|
|
QSignalSpy s(p.data(), SIGNAL(voidSignal()));
|
|
|
|
emit targetObj.voidSignal();
|
|
QTestEventLoop::instance().enterLoop(200);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
// signal must not have been received because the service isn't registered
|
|
QVERIFY(s.isEmpty());
|
|
|
|
// now register the service
|
|
QDBusReply<QDBusConnectionInterface::RegisterServiceReply> r =
|
|
con.interface()->registerService(serviceToFollow, QDBusConnectionInterface::DontQueueService,
|
|
QDBusConnectionInterface::DontAllowReplacement);
|
|
QVERIFY(r.isValid() && r.value() == QDBusConnectionInterface::ServiceRegistered);
|
|
QVERIFY(con.interface()->isServiceRegistered(serviceToFollow));
|
|
QCoreApplication::instance()->processEvents();
|
|
|
|
// emit the signal again:
|
|
emit targetObj.voidSignal();
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
// now the signal must have been received:
|
|
QCOMPARE(s.size(), 1);
|
|
QVERIFY(s.at(0).size() == 0);
|
|
|
|
// cleanup:
|
|
con.interface()->unregisterService(serviceToFollow);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::connectDisconnect_data()
|
|
{
|
|
QTest::addColumn<int>("connectCount");
|
|
QTest::addColumn<int>("disconnectCount");
|
|
|
|
// we don't actually need multiple disconnects
|
|
// QObject::disconnect() disconnects all matching rules
|
|
// we'd have to use QMetaObject::disconnectOne if we wanted just one
|
|
QTest::newRow("null") << 0 << 0;
|
|
QTest::newRow("connect-disconnect") << 1 << 1;
|
|
QTest::newRow("connect-disconnect-wildcard") << 1 << -1;
|
|
QTest::newRow("connect-twice") << 2 << 0;
|
|
QTest::newRow("connect-twice-disconnect") << 2 << 1;
|
|
QTest::newRow("connect-twice-disconnect-wildcard") << 2 << -1;
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::connectDisconnect()
|
|
{
|
|
QFETCH(int, connectCount);
|
|
QFETCH(int, disconnectCount);
|
|
|
|
Pinger p = getPinger();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// connect the exitLoop slot first
|
|
// if the disconnect() below does something weird, we'll get a timeout
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
|
|
|
|
SignalReceiver sr;
|
|
for (int i = 0; i < connectCount; ++i)
|
|
sr.connect(p.data(), SIGNAL(voidSignal()), SLOT(receive()));
|
|
if (disconnectCount)
|
|
QObject::disconnect(p.data(), disconnectCount > 0 ? SIGNAL(voidSignal()) : 0, &sr, SLOT(receive()));
|
|
|
|
emit targetObj.voidSignal();
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
if (disconnectCount != 0)
|
|
QCOMPARE(sr.callCount, 0);
|
|
else
|
|
QCOMPARE(sr.callCount, connectCount);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::connectDisconnectPeer_data()
|
|
{
|
|
connectDisconnect_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::connectDisconnectPeer()
|
|
{
|
|
QFETCH(int, connectCount);
|
|
QFETCH(int, disconnectCount);
|
|
|
|
Pinger p = getPingerPeer();
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// connect the exitLoop slot first
|
|
// if the disconnect() below does something weird, we'll get a timeout
|
|
QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop()));
|
|
|
|
SignalReceiver sr;
|
|
for (int i = 0; i < connectCount; ++i)
|
|
sr.connect(p.data(), SIGNAL(voidSignal()), SLOT(receive()));
|
|
if (disconnectCount)
|
|
QObject::disconnect(p.data(), disconnectCount > 0 ? SIGNAL(voidSignal()) : 0, &sr, SLOT(receive()));
|
|
|
|
QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "voidSignal");
|
|
QVERIFY(QDBusConnection::sessionBus().send(req));
|
|
QTestEventLoop::instance().enterLoop(2);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
|
|
if (disconnectCount != 0)
|
|
QCOMPARE(sr.callCount, 0);
|
|
else
|
|
QCOMPARE(sr.callCount, connectCount);
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::createErrors_data()
|
|
{
|
|
QTest::addColumn<QString>("service");
|
|
QTest::addColumn<QString>("path");
|
|
QTest::addColumn<QString>("errorName");
|
|
|
|
QTest::newRow("invalid-service") << "this isn't valid" << "/" << "org.qtproject.QtDBus.Error.InvalidService";
|
|
QTest::newRow("invalid-path") << QDBusConnection::sessionBus().baseService() << "this isn't valid"
|
|
<< "org.qtproject.QtDBus.Error.InvalidObjectPath";
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::createErrors()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QVERIFY(!p->isValid());
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::createErrorsPeer_data()
|
|
{
|
|
QTest::addColumn<QString>("path");
|
|
QTest::addColumn<QString>("errorName");
|
|
|
|
QTest::newRow("invalid-path") << "this isn't valid" << "org.qtproject.QtDBus.Error.InvalidObjectPath";
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::createErrorsPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QVERIFY(!p->isValid());
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::callErrors_data()
|
|
{
|
|
createErrors_data();
|
|
QTest::newRow("service-wildcard") << QString() << "/" << "org.qtproject.QtDBus.Error.InvalidService";
|
|
QTest::newRow("path-wildcard") << QDBusConnection::sessionBus().baseService() << QString()
|
|
<< "org.qtproject.QtDBus.Error.InvalidObjectPath";
|
|
QTest::newRow("full-wildcard") << QString() << QString() << "org.qtproject.QtDBus.Error.InvalidService";
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::callErrors()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to make this call:
|
|
QDBusReply<QString> r = p->stringMethod();
|
|
QVERIFY(!r.isValid());
|
|
QTEST(r.error().name(), "errorName");
|
|
QCOMPARE(p->lastError().name(), r.error().name());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::asyncCallErrors_data()
|
|
{
|
|
callErrors_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::asyncCallErrors()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to make this call:
|
|
QDBusPendingReply<QString> r = p->stringMethod();
|
|
QVERIFY(r.isError());
|
|
QTEST(r.error().name(), "errorName");
|
|
QCOMPARE(p->lastError().name(), r.error().name());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::callErrorsPeer_data()
|
|
{
|
|
createErrorsPeer_data();
|
|
QTest::newRow("path-wildcard") << QString() << "org.qtproject.QtDBus.Error.InvalidObjectPath";
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::callErrorsPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to make this call:
|
|
QDBusReply<QString> r = p->stringMethod();
|
|
QVERIFY(!r.isValid());
|
|
QTEST(r.error().name(), "errorName");
|
|
QCOMPARE(p->lastError().name(), r.error().name());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::asyncCallErrorsPeer_data()
|
|
{
|
|
callErrorsPeer_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::asyncCallErrorsPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to make this call:
|
|
QDBusPendingReply<QString> r = p->stringMethod();
|
|
QVERIFY(r.isError());
|
|
QTEST(r.error().name(), "errorName");
|
|
QCOMPARE(p->lastError().name(), r.error().name());
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyReadErrors_data()
|
|
{
|
|
callErrors_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyReadErrors()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
QVariant v = p->property("stringProp");
|
|
QVERIFY(v.isNull());
|
|
QVERIFY(!v.isValid());
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyWriteErrors_data()
|
|
{
|
|
callErrors_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyWriteErrors()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
if (p->isValid())
|
|
QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
|
|
QVERIFY(!p->setProperty("stringProp", ""));
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyReadErrors_data()
|
|
{
|
|
callErrors_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyReadErrors()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
QString v = p->stringProp();
|
|
QVERIFY(v.isNull());
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyWriteErrors_data()
|
|
{
|
|
callErrors_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyWriteErrors()
|
|
{
|
|
QFETCH(QString, service);
|
|
QFETCH(QString, path);
|
|
Pinger p = getPinger(service, path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
// but there's no direct way of verifying that the setting failed
|
|
if (p->isValid())
|
|
QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
|
|
p->setStringProp("");
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyReadErrorsPeer_data()
|
|
{
|
|
callErrorsPeer_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyReadErrorsPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
QVariant v = p->property("stringProp");
|
|
QVERIFY(v.isNull());
|
|
QVERIFY(!v.isValid());
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyWriteErrorsPeer_data()
|
|
{
|
|
callErrorsPeer_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::propertyWriteErrorsPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
if (p->isValid())
|
|
QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
|
|
QVERIFY(!p->setProperty("stringProp", ""));
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyReadErrorsPeer_data()
|
|
{
|
|
callErrorsPeer_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyReadErrorsPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
QString v = p->stringProp();
|
|
QVERIFY(v.isNull());
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyWriteErrorsPeer_data()
|
|
{
|
|
callErrorsPeer_data();
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::directPropertyWriteErrorsPeer()
|
|
{
|
|
QFETCH(QString, path);
|
|
Pinger p = getPingerPeer(path);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
// we shouldn't be able to get this value:
|
|
// but there's no direct way of verifying that the setting failed
|
|
if (p->isValid())
|
|
QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError));
|
|
p->setStringProp("");
|
|
QTEST(p->lastError().name(), "errorName");
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::validity_data()
|
|
{
|
|
QTest::addColumn<QString>("service");
|
|
|
|
QTest::newRow("null-service") << "";
|
|
QTest::newRow("ignored-service") << "org.example.anyservice";
|
|
}
|
|
|
|
void tst_QDBusAbstractInterface::validity()
|
|
{
|
|
/* Test case for QTBUG-32374 */
|
|
QFETCH(QString, service);
|
|
Pinger p = getPingerPeer("/", service);
|
|
QVERIFY2(p, "Not connected to D-Bus");
|
|
|
|
QVERIFY(p->isValid());
|
|
}
|
|
|
|
QTEST_MAIN(tst_QDBusAbstractInterface)
|
|
#include "tst_qdbusabstractinterface.moc"
|