From a3ebacbc33eb4c026a90e1191ac8da9c38aebcac Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 9 Apr 2012 17:12:12 +0300 Subject: tests: Add a new test for testing BaseConnectionManager The test currently contains an adaptation of tp-glib's example-no-protocols test. --- tests/dbus/CMakeLists.txt | 4 +++ tests/dbus/base-cm.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 tests/dbus/base-cm.cpp diff --git a/tests/dbus/CMakeLists.txt b/tests/dbus/CMakeLists.txt index a7105488..5b87a6c1 100644 --- a/tests/dbus/CMakeLists.txt +++ b/tests/dbus/CMakeLists.txt @@ -83,6 +83,10 @@ tpqt_add_dbus_unit_test(CmProtocol cm-protocol) tpqt_add_dbus_unit_test(ProfileManager profile-manager) tpqt_add_dbus_unit_test(Types types) +if(ENABLE_EXPERIMENTAL_SERVICE_SUPPORT) + tpqt_add_dbus_unit_test(BaseConnectionManager base-cm telepathy-qt${QT_VERSION_MAJOR}-service) +endif(ENABLE_EXPERIMENTAL_SERVICE_SUPPORT) + # Make check target. In case of check, output on failure and put it into a log # This target has to stay here for catching all of the tests add_custom_target(check ctest --output-on-failure -O test.log diff --git a/tests/dbus/base-cm.cpp b/tests/dbus/base-cm.cpp new file mode 100644 index 00000000..75064088 --- /dev/null +++ b/tests/dbus/base-cm.cpp @@ -0,0 +1,92 @@ +#include + +#define TP_QT_ENABLE_LOWLEVEL_API + +#include +#include +#include +#include +#include +#include + +using namespace Tp; + +class TestBaseCM : public Test +{ + Q_OBJECT +public: + TestBaseCM(QObject *parent = 0) + : Test(parent) + { } + +private Q_SLOTS: + void initTestCase(); + void init(); + + void testNoProtocols(); + + void cleanup(); + void cleanupTestCase(); + +}; + +void TestBaseCM::initTestCase() +{ + initTestCaseImpl(); +} + +void TestBaseCM::init() +{ + initImpl(); +} + +void TestBaseCM::testNoProtocols() +{ + qDebug() << "Introspecting non-existing CM"; + + ConnectionManagerPtr cliCM = ConnectionManager::create( + QLatin1String("testcm")); + PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); + connect(pr, SIGNAL(finished(Tp::PendingOperation*)), + SLOT(expectFailure(Tp::PendingOperation*))); + QCOMPARE(mLoop->exec(), 0); + + qDebug() << "Creating CM"; + + BaseConnectionManagerPtr cm = BaseConnectionManager::create( + QLatin1String("testcm")); + Tp::DBusError err; + QVERIFY(cm->registerObject(&err)); + QVERIFY(!err.isValid()); + + qDebug() << "Introspecting new CM"; + + cliCM = ConnectionManager::create(QLatin1String("testcm")); + pr = cliCM->becomeReady(ConnectionManager::FeatureCore); + connect(pr, SIGNAL(finished(Tp::PendingOperation*)), + SLOT(expectSuccessfulCall(Tp::PendingOperation*))); + QCOMPARE(mLoop->exec(), 0); + + QCOMPARE(cliCM->supportedProtocols().size(), 0); + + qDebug() << "Requesting connection"; + + PendingConnection *pc = cliCM->lowlevel()->requestConnection( + QLatin1String("jabber"), QVariantMap()); + connect(pc, SIGNAL(finished(Tp::PendingOperation*)), + SLOT(expectFailure(Tp::PendingOperation*))); + QCOMPARE(mLoop->exec(), 0); +} + +void TestBaseCM::cleanup() +{ + cleanupImpl(); +} + +void TestBaseCM::cleanupTestCase() +{ + cleanupTestCaseImpl(); +} + +QTEST_MAIN(TestBaseCM) +#include "_gen/base-cm.cpp.moc.hpp" -- cgit v1.2.3 From df0621ea1b0ae7896edf69087790b4cd750d5ce0 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 9 Apr 2012 17:17:29 +0300 Subject: DBusService: Fix QString args replacement in registerObject() --- TelepathyQt/dbus-service.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TelepathyQt/dbus-service.cpp b/TelepathyQt/dbus-service.cpp index a22c6569..6a8f978f 100644 --- a/TelepathyQt/dbus-service.cpp +++ b/TelepathyQt/dbus-service.cpp @@ -167,7 +167,7 @@ bool DBusService::registerObject(const QString &busName, const QString &objectPa if (!mPriv->dbusObject->dbusConnection().registerService(busName)) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, - QString(QLatin1String("Name %s already in use by another process")) + QString(QLatin1String("Name %1 already in use by another process")) .arg(busName)); warning() << "Unable to register service" << busName << "- name already registered by another process"; @@ -176,7 +176,7 @@ bool DBusService::registerObject(const QString &busName, const QString &objectPa if (!mPriv->dbusObject->dbusConnection().registerObject(objectPath, mPriv->dbusObject)) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, - QString(QLatin1String("Object at path %s already registered")) + QString(QLatin1String("Object at path %1 already registered")) .arg(objectPath)); warning() << "Unable to register object" << objectPath << "- path already registered"; -- cgit v1.2.3 From 5872ea5f62c6eff9d55e50941824f3ade55ec5fd Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 9 Apr 2012 17:18:54 +0300 Subject: BaseConnection: Fix QString args replacement in registerObject() --- TelepathyQt/base-connection.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TelepathyQt/base-connection.cpp b/TelepathyQt/base-connection.cpp index c3b93b20..45389c58 100644 --- a/TelepathyQt/base-connection.cpp +++ b/TelepathyQt/base-connection.cpp @@ -187,10 +187,10 @@ bool BaseConnection::registerObject(DBusError *error) QString escapedProtocolName = mPriv->protocolName; escapedProtocolName.replace(QLatin1Char('-'), QLatin1Char('_')); QString name = uniqueName(); - QString busName = QString(QLatin1String("%s.%s.%s.%s")) - .arg(TP_QT_CONNECTION_BUS_NAME_BASE).arg(mPriv->cmName).arg(escapedProtocolName).arg(name); - QString objectPath = QString(QLatin1String("%s/%s/%s/%s")) - .arg(TP_QT_CONNECTION_OBJECT_PATH_BASE).arg(mPriv->cmName).arg(escapedProtocolName).arg(name); + QString busName = QString(QLatin1String("%1.%2.%3.%4")) + .arg(TP_QT_CONNECTION_BUS_NAME_BASE, mPriv->cmName, escapedProtocolName, name); + QString objectPath = QString(QLatin1String("%1/%2/%3/%4")) + .arg(TP_QT_CONNECTION_OBJECT_PATH_BASE, mPriv->cmName, escapedProtocolName, name); DBusError _error; bool ret = registerObject(busName, objectPath, &_error); if (!ret && error) { -- cgit v1.2.3 From 9f7c332174554ebf821f9490e2463a666a7842ab Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 9 Apr 2012 17:19:15 +0300 Subject: ConnectionManager: Finish introspection sucessfully when no protocols are found on the CM --- TelepathyQt/connection-manager.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/TelepathyQt/connection-manager.cpp b/TelepathyQt/connection-manager.cpp index 5418bbf2..96b32348 100644 --- a/TelepathyQt/connection-manager.cpp +++ b/TelepathyQt/connection-manager.cpp @@ -1046,12 +1046,17 @@ void ConnectionManager::gotProtocolsLegacy(QDBusPendingCallWatcher *watcher) debug() << "Got reply to ConnectionManager.ListProtocols"; protocolsNames = reply.value(); - foreach (const QString &protocolName, protocolsNames) { - mPriv->protocols.append(ProtocolInfo(ConnectionManagerPtr(this), protocolName)); - mPriv->parametersQueue.enqueue(protocolName); - } + if (!protocolsNames.isEmpty()) { + foreach (const QString &protocolName, protocolsNames) { + mPriv->protocols.append(ProtocolInfo(ConnectionManagerPtr(this), protocolName)); + mPriv->parametersQueue.enqueue(protocolName); + } - mPriv->introspectParametersLegacy(); + mPriv->introspectParametersLegacy(); + } else { + //no protocols - introspection finished + mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); + } } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); -- cgit v1.2.3 From a1e4147a4677293164eed80e056f812309c6a33a Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 9 Apr 2012 17:52:05 +0300 Subject: test-base-cm: Add test for the protocol-related methods of BaseCM --- tests/dbus/base-cm.cpp | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/dbus/base-cm.cpp b/tests/dbus/base-cm.cpp index 75064088..3cc35e0f 100644 --- a/tests/dbus/base-cm.cpp +++ b/tests/dbus/base-cm.cpp @@ -3,6 +3,7 @@ #define TP_QT_ENABLE_LOWLEVEL_API #include +#include #include #include #include @@ -24,6 +25,7 @@ private Q_SLOTS: void init(); void testNoProtocols(); + void testProtocols(); void cleanup(); void cleanupTestCase(); @@ -59,6 +61,8 @@ void TestBaseCM::testNoProtocols() QVERIFY(cm->registerObject(&err)); QVERIFY(!err.isValid()); + QCOMPARE(cm->protocols().size(), 0); + qDebug() << "Introspecting new CM"; cliCM = ConnectionManager::create(QLatin1String("testcm")); @@ -76,6 +80,66 @@ void TestBaseCM::testNoProtocols() connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); +} + +void TestBaseCM::testProtocols() +{ + qDebug() << "Creating CM"; + + BaseConnectionManagerPtr cm = BaseConnectionManager::create(QLatin1String("testcm")); + + BaseProtocolPtr protocol = BaseProtocol::create(QLatin1String("myprotocol")); + QVERIFY(!protocol.isNull()); + QVERIFY(cm->addProtocol(protocol)); + + QVERIFY(cm->hasProtocol(QLatin1String("myprotocol"))); + QCOMPARE(cm->protocol(QLatin1String("myprotocol")), protocol); + QCOMPARE(cm->protocols().size(), 1); + + QVERIFY(!cm->hasProtocol(QLatin1String("otherprotocol"))); + QVERIFY(cm->protocol(QLatin1String("otherprotocol")).isNull()); + + //can't add the same protocol twice + QVERIFY(!cm->addProtocol(protocol)); + + Tp::DBusError err; + QVERIFY(cm->registerObject(&err)); + QVERIFY(!err.isValid()); + + //can't add another protocol after registerObject() + protocol = BaseProtocol::create(QLatin1String("otherprotocol")); + QVERIFY(!protocol.isNull()); + QVERIFY(!cm->addProtocol(protocol)); + QCOMPARE(cm->protocols().size(), 1); + protocol.reset(); + + QVariantMap props = cm->immutableProperties(); + QVERIFY(props.contains(TP_QT_IFACE_CONNECTION_MANAGER + QLatin1String(".Protocols"))); + + ProtocolPropertiesMap protocols = qvariant_cast( + props[TP_QT_IFACE_CONNECTION_MANAGER + QLatin1String(".Protocols")]); + QVERIFY(protocols.contains(QLatin1String("myprotocol"))); + QVERIFY(!protocols.contains(QLatin1String("otherprotocol"))); + + qDebug() << "Introspecting CM"; + + ConnectionManagerPtr cliCM = ConnectionManager::create( + QLatin1String("testcm")); + PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); + connect(pr, SIGNAL(finished(Tp::PendingOperation*)), + SLOT(expectSuccessfulCall(Tp::PendingOperation*))); + QCOMPARE(mLoop->exec(), 0); + + QCOMPARE(cliCM->supportedProtocols().size(), 1); + QVERIFY(cliCM->hasProtocol(QLatin1String("myprotocol"))); + + PendingConnection *pc = cliCM->lowlevel()->requestConnection( + QLatin1String("myprotocol"), QVariantMap()); + connect(pc, SIGNAL(finished(Tp::PendingOperation*)), + SLOT(expectFailure(Tp::PendingOperation*))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); } void TestBaseCM::cleanup() -- cgit v1.2.3 From 11feef12ef5138c703f9974bbd9a35c670cfcc76 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Tue, 10 Apr 2012 20:44:48 +0300 Subject: tests-lib: Add a new TestThreadHelper class This class allows us to run parts of a unit test in a different thread context, while being in sync with the unit test flow. This is useful to run connection manager implementations in a different thread, to overcome the shortcomings of the QtDBus local-loop optimizations. --- tests/lib/CMakeLists.txt | 22 ++++++++++-- tests/lib/test-thread-helper.cpp | 36 +++++++++++++++++++ tests/lib/test-thread-helper.h | 77 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 tests/lib/test-thread-helper.cpp create mode 100644 tests/lib/test-thread-helper.h diff --git a/tests/lib/CMakeLists.txt b/tests/lib/CMakeLists.txt index 2a96336f..1755ddc3 100644 --- a/tests/lib/CMakeLists.txt +++ b/tests/lib/CMakeLists.txt @@ -1,9 +1,27 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}) +set(tp_qt_tests_SRCS + test.cpp + test-thread-helper.cpp +) + +set(tp_qt_tests_MOC_SRCS + test.h + test-thread-helper.h +) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_gen") -tpqt_generate_moc_i(test.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/test.h.moc.hpp) -add_library(tp-qt-tests test.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/test.h.moc.hpp) + +foreach(moc_src ${tp_qt_tests_MOC_SRCS}) + set(generated_file _gen/${moc_src}) + string(REPLACE ".h" ".h.moc.hpp" generated_file ${generated_file}) + tpqt_generate_moc_i(${CMAKE_CURRENT_SOURCE_DIR}/${moc_src} + ${CMAKE_CURRENT_BINARY_DIR}/${generated_file}) + list(APPEND tp_qt_tests_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${generated_file}) +endforeach(moc_src ${tp_qt_tests_MOC_SRCS}) + +add_library(tp-qt-tests ${tp_qt_tests_SRCS}) target_link_libraries(tp-qt-tests ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} telepathy-qt${QT_VERSION_MAJOR}) if(ENABLE_TP_GLIB_TESTS) diff --git a/tests/lib/test-thread-helper.cpp b/tests/lib/test-thread-helper.cpp new file mode 100644 index 00000000..d2148d2a --- /dev/null +++ b/tests/lib/test-thread-helper.cpp @@ -0,0 +1,36 @@ +#include "tests/lib/test-thread-helper.h" +#include + +TestThreadHelperBase::TestThreadHelperBase(ThreadObjectBase *threadObject) +{ + Q_ASSERT(threadObject); + + mThread = new QThread; + mThreadObject = threadObject; + mThreadObject->moveToThread(mThread); + + QEventLoop loop; + QObject::connect(mThread, SIGNAL(started()), &loop, SLOT(quit())); + QMetaObject::invokeMethod(mThread, "start"); + loop.exec(); +} + +TestThreadHelperBase::~TestThreadHelperBase() +{ + QMetaObject::invokeMethod(mThreadObject, "deleteLater"); + mThread->quit(); + mThread->wait(); + mThread->deleteLater(); + QCoreApplication::processEvents(); +} + +void TestThreadHelperBase::executeCallback() +{ + QEventLoop loop; + QObject::connect(mThreadObject, SIGNAL(callbackExecutionFinished()), + &loop, SLOT(quit())); + QMetaObject::invokeMethod(mThreadObject, "executeCallback"); + loop.exec(); +} + +#include "_gen/test-thread-helper.h.moc.hpp" diff --git a/tests/lib/test-thread-helper.h b/tests/lib/test-thread-helper.h new file mode 100644 index 00000000..3d483ed7 --- /dev/null +++ b/tests/lib/test-thread-helper.h @@ -0,0 +1,77 @@ +#ifndef _TelepathyQt_tests_lib_test_thread_helper_h_HEADER_GUARD_ +#define _TelepathyQt_tests_lib_test_thread_helper_h_HEADER_GUARD_ + +#include +#include +#include +#include + +class ThreadObjectBase : public QObject +{ + Q_OBJECT + +public Q_SLOTS: + virtual void executeCallback() = 0; + +Q_SIGNALS: + void callbackExecutionFinished(); +}; + +template +class ThreadObject : public ThreadObjectBase +{ +public: + typedef Tp::Callback1 Callback; + Callback mCallback; + + virtual void executeCallback() + { + Q_ASSERT(mCallback.isValid()); + Q_ASSERT(QThread::currentThread() != QCoreApplication::instance()->thread()); + + mCallback(mContext); + Q_EMIT callbackExecutionFinished(); + } + +private: + Context mContext; +}; + +class TestThreadHelperBase +{ +public: + virtual ~TestThreadHelperBase(); + +protected: + TestThreadHelperBase(ThreadObjectBase *threadObject); + void executeCallback(); + +protected: + QThread *mThread; + ThreadObjectBase *mThreadObject; +}; + +template +class TestThreadHelper : public TestThreadHelperBase +{ +public: + TestThreadHelper() + : TestThreadHelperBase(new ThreadObject()) + { } + + void executeCallback(typename ThreadObject::Callback const & cb) + { + static_cast*>(mThreadObject)->mCallback = cb; + TestThreadHelperBase::executeCallback(); + } +}; + +#define TEST_THREAD_HELPER_EXECUTE(helper, callback) \ + do { \ + (helper)->executeCallback(Tp::ptrFun(callback)); \ + if (QTest::currentTestFailed()) { \ + return; \ + } \ + } while(0) + +#endif // _TelepathyQt_tests_lib_test_thread_helper_h_HEADER_GUARD_ -- cgit v1.2.3 From 5bf254fc18c499f578f7863c7a954bae4c99fddb Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Tue, 10 Apr 2012 22:15:37 +0300 Subject: test-base-cm: Port to use TestThreadHelper --- tests/dbus/base-cm.cpp | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/tests/dbus/base-cm.cpp b/tests/dbus/base-cm.cpp index 3cc35e0f..b4809db9 100644 --- a/tests/dbus/base-cm.cpp +++ b/tests/dbus/base-cm.cpp @@ -1,4 +1,5 @@ #include +#include #define TP_QT_ENABLE_LOWLEVEL_API @@ -30,6 +31,9 @@ private Q_SLOTS: void cleanup(); void cleanupTestCase(); +private: + static void testNoProtocolsCreateCM(BaseConnectionManagerPtr &cm); + static void testProtocolsCreateCM(BaseConnectionManagerPtr &cm); }; void TestBaseCM::initTestCase() @@ -42,6 +46,16 @@ void TestBaseCM::init() initImpl(); } +void TestBaseCM::testNoProtocolsCreateCM(BaseConnectionManagerPtr &cm) +{ + cm = BaseConnectionManager::create(QLatin1String("testcm")); + Tp::DBusError err; + QVERIFY(cm->registerObject(&err)); + QVERIFY(!err.isValid()); + + QCOMPARE(cm->protocols().size(), 0); +} + void TestBaseCM::testNoProtocols() { qDebug() << "Introspecting non-existing CM"; @@ -55,13 +69,8 @@ void TestBaseCM::testNoProtocols() qDebug() << "Creating CM"; - BaseConnectionManagerPtr cm = BaseConnectionManager::create( - QLatin1String("testcm")); - Tp::DBusError err; - QVERIFY(cm->registerObject(&err)); - QVERIFY(!err.isValid()); - - QCOMPARE(cm->protocols().size(), 0); + TestThreadHelper helper; + TEST_THREAD_HELPER_EXECUTE(&helper, &testNoProtocolsCreateCM); qDebug() << "Introspecting new CM"; @@ -83,11 +92,9 @@ void TestBaseCM::testNoProtocols() QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); } -void TestBaseCM::testProtocols() +void TestBaseCM::testProtocolsCreateCM(BaseConnectionManagerPtr &cm) { - qDebug() << "Creating CM"; - - BaseConnectionManagerPtr cm = BaseConnectionManager::create(QLatin1String("testcm")); + cm = BaseConnectionManager::create(QLatin1String("testcm")); BaseProtocolPtr protocol = BaseProtocol::create(QLatin1String("myprotocol")); QVERIFY(!protocol.isNull()); @@ -121,6 +128,14 @@ void TestBaseCM::testProtocols() props[TP_QT_IFACE_CONNECTION_MANAGER + QLatin1String(".Protocols")]); QVERIFY(protocols.contains(QLatin1String("myprotocol"))); QVERIFY(!protocols.contains(QLatin1String("otherprotocol"))); +} + +void TestBaseCM::testProtocols() +{ + qDebug() << "Creating CM"; + + TestThreadHelper helper; + TEST_THREAD_HELPER_EXECUTE(&helper, &testProtocolsCreateCM); qDebug() << "Introspecting CM"; -- cgit v1.2.3 From aa817e46ab60120084e82926caf0c1cef8dcaacf Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Tue, 10 Apr 2012 23:04:30 +0300 Subject: TestThreadHelper: Start the thread after entering the event loop, as the code actually intended to do. --- tests/lib/test-thread-helper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/test-thread-helper.cpp b/tests/lib/test-thread-helper.cpp index d2148d2a..a977c7a5 100644 --- a/tests/lib/test-thread-helper.cpp +++ b/tests/lib/test-thread-helper.cpp @@ -1,5 +1,6 @@ #include "tests/lib/test-thread-helper.h" #include +#include TestThreadHelperBase::TestThreadHelperBase(ThreadObjectBase *threadObject) { @@ -11,7 +12,7 @@ TestThreadHelperBase::TestThreadHelperBase(ThreadObjectBase *threadObject) QEventLoop loop; QObject::connect(mThread, SIGNAL(started()), &loop, SLOT(quit())); - QMetaObject::invokeMethod(mThread, "start"); + QTimer::singleShot(0, mThread, SLOT(start())); loop.exec(); } -- cgit v1.2.3