/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** 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 Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/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. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #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 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(); qRegisterMetaType(); } 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 proc.start("qpinger"); #else proc.start("./qpinger/qpinger"); #endif QVERIFY(proc.waitForStarted()); // 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() { // Kill peer, resetting the object exported by a separate process proc.terminate(); QVERIFY(proc.waitForFinished() || proc.state() == QProcess::NotRunning); // Wait until the service is certainly not registered QDBusConnection con = QDBusConnection::sessionBus(); if (con.isConnected()) { QTRY_VERIFY(!con.interface()->isServiceRegistered(serviceName)); } } 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, "isConnected"); QDBusMessage rpl2 = con.call(req2); QVERIFY(rpl2.type() == QDBusMessage::ReplyMessage); QVERIFY(rpl2.arguments().at(0).toBool()); } 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 r = p->voidMethod(); QVERIFY(r.isValid()); } void tst_QDBusAbstractInterface::makeStringCall() { Pinger p = getPinger(); QVERIFY2(p, "Not connected to D-Bus"); QDBusReply r = p->stringMethod(); QVERIFY(r.isValid()); QCOMPARE(r.value(), targetObj.stringMethod()); } static QHash complexMethodArgs() { QHash 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 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 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 r = p->voidMethod(); QVERIFY(r.isValid()); } void tst_QDBusAbstractInterface::makeStringCallPeer() { Pinger p = getPingerPeer(); QVERIFY2(p, "Not connected to D-Bus"); QDBusReply 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 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 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 r = p->voidMethod(); r.waitForFinished(); QVERIFY(r.isValid()); } void tst_QDBusAbstractInterface::makeAsyncStringCall() { Pinger p = getPinger(); QVERIFY2(p, "Not connected to D-Bus"); QDBusPendingReply 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 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 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 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 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 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 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 reply = p.sleepMethod(100); QVERIFY(reply.isValid()); QCOMPARE(int(reply), 42); } { // Call with 1 msec timeout -> fails p.setTimeout(1); QDBusReply 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(); 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()); QCOMPARE(v.value(), 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(); 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()); QCOMPARE(v.value(), 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("service"); QTest::addColumn("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()); QCOMPARE(s[0][0].value(), expectedValue); } void tst_QDBusAbstractInterface::getVoidSignalPeer_data() { QTest::addColumn("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()); QCOMPARE(s[0][0].value(), 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(""); // 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())); 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 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("connectCount"); QTest::addColumn("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("service"); QTest::addColumn("path"); QTest::addColumn("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("path"); QTest::addColumn("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 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 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 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 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("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"