diff options
| author | Dario Freddi <dario.freddi@collabora.com> | 2011-11-03 22:02:55 +0100 |
|---|---|---|
| committer | Dario Freddi <dario.freddi@collabora.com> | 2012-07-03 11:11:21 +0200 |
| commit | 767c9c758e23115a79e8904851d836d1dc2ae503 (patch) | |
| tree | 0e5266b418db109619a75192b405771bbd5d589c | |
| parent | 0c8db3e3a3e6769ae6bb60df81522bf577d29892 (diff) | |
dbus-tubes: Add an initial version of the DBus Tubes autotest. It's mostly a copy-paste from the STube one, to allow testing similar features
in a similar ways. At the moment, the test is not functional, but compiles and passes the first basic steps.
| -rw-r--r-- | tests/dbus/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | tests/dbus/dbus-tube-chan.cpp | 695 |
2 files changed, 696 insertions, 0 deletions
diff --git a/tests/dbus/CMakeLists.txt b/tests/dbus/CMakeLists.txt index 4df270ee..3ef6e639 100644 --- a/tests/dbus/CMakeLists.txt +++ b/tests/dbus/CMakeLists.txt @@ -74,6 +74,7 @@ if(ENABLE_TP_GLIB_TESTS) tpqt_add_dbus_unit_test(StreamTubeHandlers stream-tube-handlers tp-glib-tests tp-qt-tests-glib-helpers) if(ENABLE_TP_GLIB_GIO_TESTS) tpqt_add_dbus_unit_test(StreamTubeChannel stream-tube-chan tp-glib-tests tp-qt-tests-glib-helpers) + tpqt_add_dbus_unit_test(DBusTubeChannel dbus-tube-chan tp-glib-tests tp-qt-tests-glib-helpers) endif(ENABLE_TP_GLIB_GIO_TESTS) endif (ENABLE_TESTS_WITH_RACES_IN_QT_4_6) diff --git a/tests/dbus/dbus-tube-chan.cpp b/tests/dbus/dbus-tube-chan.cpp new file mode 100644 index 00000000..abc4fc6c --- /dev/null +++ b/tests/dbus/dbus-tube-chan.cpp @@ -0,0 +1,695 @@ +#include <tests/lib/test.h> + +#include <tests/lib/glib-helpers/test-conn-helper.h> + +#include <tests/lib/glib/simple-conn.h> +#include <tests/lib/glib/dbus-tube-chan.h> + +#include <TelepathyQt/Connection> +#include <TelepathyQt/IncomingDBusTubeChannel> +#include <TelepathyQt/OutgoingDBusTubeChannel> +#include <TelepathyQt/PendingReady> +#include <TelepathyQt/PendingDBusTubeConnection> +#include <TelepathyQt/ReferencedHandles> +#include <TelepathyQt/DBusTubeChannel> + +#include <telepathy-glib/telepathy-glib.h> + +#include <QHostAddress> +#include <QLocalServer> +#include <QLocalSocket> +#include <QTcpServer> +#include <QTcpSocket> + +#include <stdio.h> + +using namespace Tp; + +namespace +{ + +struct TestContext +{ + bool withContact; + TpSocketAddressType addressType; + TpSocketAccessControl accessControl; +}; + +TestContext contexts[] = { + { FALSE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, + { FALSE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_CREDENTIALS }, + + { TRUE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, + { TRUE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_CREDENTIALS }, + + { FALSE, (TpSocketAddressType) NUM_TP_SOCKET_ADDRESS_TYPES, (TpSocketAccessControl) NUM_TP_SOCKET_ACCESS_CONTROLS } +}; + +void destroySocketControlList(gpointer data) +{ + g_array_free((GArray *) data, TRUE); +} + +GHashTable *createSupportedSocketTypesHash(TpSocketAddressType addressType, + TpSocketAccessControl accessControl) +{ + GHashTable *ret; + GArray *tab; + + ret = g_hash_table_new_full(NULL, NULL, NULL, destroySocketControlList); + + tab = g_array_sized_new(FALSE, FALSE, sizeof(TpSocketAccessControl), 1); + g_array_append_val(tab, accessControl); + + g_hash_table_insert(ret, GUINT_TO_POINTER(addressType), tab); + + return ret; +} + +} + +class TestDBusTubeChan : public Test +{ + Q_OBJECT + +public: + TestDBusTubeChan(QObject *parent = 0) + : Test(parent), + mConn(0), mChanService(0), + mGotLocalConnection(false), mGotRemoteConnection(false), + mGotSocketConnection(false), mGotConnectionClosed(false), + mOfferFinished(false), mRequiresCredentials(false), mCredentialByte(0) + { } + +protected Q_SLOTS: + void onBusNamesChanged(const QHash<ContactPtr,QString> &added, + const QList<ContactPtr> &removed); + void onNewSocketConnection(); + void onOfferFinished(Tp::PendingOperation *op); + void expectPendingTubeConnectionFinished(Tp::PendingOperation *op); + +private Q_SLOTS: + void initTestCase(); + void init(); + + void testCreation(); + void testAcceptTwice(); + void testAcceptSuccess(); + void testAcceptFail(); + void testOfferSuccess(); + void testOutgoingBusNameMonitoring(); + + void cleanup(); + void cleanupTestCase(); + +private: + + void createTubeChannel(bool requested, TpSocketAddressType addressType, + TpSocketAccessControl accessControl, bool withContact); + + TestConnHelper *mConn; + TpTestsDBusTubeChannel *mChanService; + DBusTubeChannelPtr mChan; + + uint mCurrentContext; + + QHash<ContactPtr, QString> mCurrentBusNames; + bool mGotLocalConnection; + bool mGotRemoteConnection; + bool mGotSocketConnection; + bool mGotConnectionClosed; + bool mOfferFinished; + bool mRequiresCredentials; + uchar mCredentialByte; + + QHostAddress mExpectedAddress; + uint mExpectedPort; + uint mExpectedHandle; + QString mExpectedId; +}; + +void TestDBusTubeChan::onBusNamesChanged(const QHash<ContactPtr, QString> &added, + const QList<ContactPtr> &removed) +{ + for (QHash<ContactPtr, QString>::const_iterator i = added.constBegin(); + i != added.constEnd(); ++i) { + mCurrentBusNames.insert(i.key(), i.value()); + } + Q_FOREACH (const ContactPtr &contact, removed) { + QVERIFY(mCurrentBusNames.contains(contact)); + mCurrentBusNames.remove(contact); + } + + QCOMPARE(mChan->busNames().size(), mCurrentBusNames.size()); +} + +void TestDBusTubeChan::onNewSocketConnection() +{ + qDebug() << "Got new socket connection"; + mGotSocketConnection = true; + mLoop->exit(0); +} + +void TestDBusTubeChan::onOfferFinished(Tp::PendingOperation *op) +{ + TEST_VERIFY_OP(op); + + mOfferFinished = true; + mLoop->exit(0); +} + +void TestDBusTubeChan::expectPendingTubeConnectionFinished(PendingOperation *op) +{ + TEST_VERIFY_OP(op); + + PendingDBusTubeConnection *pdt = qobject_cast<PendingDBusTubeConnection*>(op); + mRequiresCredentials = pdt->requiresCredentials(); + mCredentialByte = pdt->credentialByte(); + mLoop->exit(0); +} + +void TestDBusTubeChan::createTubeChannel(bool requested, + TpSocketAddressType addressType, + TpSocketAccessControl accessControl, + bool withContact) +{ + mChan.reset(); + mLoop->processEvents(); + tp_clear_object(&mChanService); + + /* Create service-side tube channel object */ + QString chanPath = QString(QLatin1String("%1/Channel")).arg(mConn->objectPath()); + + TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( + TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); + TpHandleRepoIface *roomRepo = tp_base_connection_get_handles( + TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_ROOM); + TpHandle handle; + GType type; + if (withContact) { + handle = tp_handle_ensure(contactRepo, "bob", NULL, NULL); + type = TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL; + } else { + handle = tp_handle_ensure(roomRepo, "#test", NULL, NULL); + type = TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL; + } + + TpHandle alfHandle = tp_handle_ensure(contactRepo, "alf", NULL, NULL); + + GArray *acontrols; + TpSocketAccessControl a; + if (accessControl != TP_SOCKET_ACCESS_CONTROL_LOCALHOST) { + acontrols = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); + + a = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; + acontrols = g_array_append_val (acontrols, a); + a = TP_SOCKET_ACCESS_CONTROL_CREDENTIALS; + acontrols = g_array_append_val (acontrols, a); + } else { + acontrols = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); + a = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; + acontrols = g_array_append_val (acontrols, a); + } + + mChanService = TP_TESTS_DBUS_TUBE_CHANNEL(g_object_new( + type, + "connection", mConn->service(), + "handle", handle, + "requested", requested, + "object-path", chanPath.toLatin1().constData(), + "supported-access-controls", acontrols, + "initiator-handle", alfHandle, + NULL)); + + /* Create client-side tube channel object */ + GHashTable *props; + g_object_get(mChanService, "channel-properties", &props, NULL); + + if (requested) { + mChan = OutgoingDBusTubeChannel::create(mConn->client(), chanPath, QVariantMap()); + } else { + mChan = IncomingDBusTubeChannel::create(mConn->client(), chanPath, QVariantMap()); + } + + g_hash_table_unref(props); + g_array_unref(acontrols); + + if (withContact) + tp_handle_unref(contactRepo, handle); + else + tp_handle_unref(roomRepo, handle); +} + +void TestDBusTubeChan::initTestCase() +{ + initTestCaseImpl(); + + g_type_init(); + g_set_prgname("dbus-tube-chan"); + tp_debug_set_flags("all"); + dbus_g_bus_get(DBUS_BUS_STARTER, 0); + + mConn = new TestConnHelper(this, + TP_TESTS_TYPE_SIMPLE_CONNECTION, + "account", "me@example.com", + "protocol", "example", + NULL); + QCOMPARE(mConn->connect(), true); +} + +void TestDBusTubeChan::init() +{ + initImpl(); + + mCurrentContext = -1; + + mGotLocalConnection = false; + mGotRemoteConnection = false; + mGotConnectionClosed = false; + mGotSocketConnection = false; + mOfferFinished = false; + mRequiresCredentials = false; + mCredentialByte = 0; + + mExpectedAddress = QHostAddress(); + mExpectedPort = -1; + mExpectedHandle = -1; + mExpectedId = QString(); +} + +void TestDBusTubeChan::testCreation() +{ + /* Outgoing tube */ + createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_UNIX, + TP_SOCKET_ACCESS_CONTROL_LOCALHOST, true); + QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->isReady(OutgoingDBusTubeChannel::FeatureCore), true); + QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), false); + QCOMPARE(mChan->state(), TubeChannelStateNotOffered); + QCOMPARE(mChan->parameters().isEmpty(), true); + QCOMPARE(mChan->serviceName(), QLatin1String("com.test.Test")); + QCOMPARE(mChan->supportsCredentials(), false); + QCOMPARE(mChan->busNames().isEmpty(), true); + QCOMPARE(mChan->address(), QString()); + + /* incoming tube */ + createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, + TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); + QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); + QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), false); + QCOMPARE(mChan->state(), TubeChannelStateLocalPending); + QCOMPARE(mChan->parameters().isEmpty(), false); + QCOMPARE(mChan->parameters().size(), 1); + QCOMPARE(mChan->parameters().contains(QLatin1String("badger")), true); + QCOMPARE(mChan->parameters().value(QLatin1String("badger")), QVariant(42)); + QCOMPARE(mChan->serviceName(), QLatin1String("com.test.Test")); + QCOMPARE(mChan->supportsCredentials(), false); + QCOMPARE(mChan->busNames().isEmpty(), true); + QCOMPARE(mChan->address(), QString()); +} + +void TestDBusTubeChan::testAcceptTwice() +{ + /* incoming tube */ + createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, + TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); + QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore | + DBusTubeChannel::FeatureBusNameMonitoring), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); + QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), true); + QCOMPARE(mChan->state(), TubeChannelStateLocalPending); + + IncomingDBusTubeChannelPtr chan = IncomingDBusTubeChannelPtr::qObjectCast(mChan); + QVERIFY(connect(chan->acceptTube(), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->state(), TubeChannelStateOpen); + + /* try to re-accept the tube */ + QVERIFY(connect(chan->acceptTube(), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectFailure(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->state(), TubeChannelStateOpen); +} + +void TestDBusTubeChan::testAcceptSuccess() +{ + /* incoming tube */ + for (int i = 0; contexts[i].addressType != NUM_TP_SOCKET_ADDRESS_TYPES; i++) { + /* as we run several tests here, let's init/cleanup properly */ + init(); + + qDebug() << "Testing context:" << i; + mCurrentContext = i; + + createTubeChannel(false, contexts[i].addressType, + contexts[i].accessControl, contexts[i].withContact); + QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore | + DBusTubeChannel::FeatureBusNameMonitoring), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); + QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), true); + QCOMPARE(mChan->state(), TubeChannelStateLocalPending); + + mGotLocalConnection = false; + QVERIFY(connect(mChan.data(), + SIGNAL(busNamesChanged(QHash<ContactPtr,QString>,QList<ContactPtr>)), + SLOT(onBusNamesChanged(QHash<ContactPtr,QString>,QList<ContactPtr>)))); + + bool requiresCredentials = ((contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS) ? + true : false); + + IncomingDBusTubeChannelPtr chan = IncomingDBusTubeChannelPtr::qObjectCast(mChan); + if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { + QVERIFY(connect(chan->acceptTube(requiresCredentials), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectPendingTubeConnectionFinished(Tp::PendingOperation *)))); + } else { + // Should never happen + QVERIFY(false); + } + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->state(), TubeChannelStateOpen); + QCOMPARE(mRequiresCredentials, requiresCredentials); + + if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { + qDebug() << "Connecting to bus" << mChan->address(); + + QDBusConnection conn(QLatin1String("tmp")); + + if (contexts[i].withContact) { + conn = QDBusConnection::connectToPeer(mChan->address(), mChan->serviceName()); + } else { + conn = QDBusConnection::connectToBus(mChan->address(), mChan->serviceName()); + } + +// if (requiresCredentials) { +// qDebug() << "Sending credential byte" << mCredentialByte; +// socket->write(reinterpret_cast<const char*>(&mCredentialByte), 1); +// } + + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(conn.isConnected(), true); + qDebug() << "Connected to host"; + } else { + QVERIFY(false); + } + +// mGotConnectionClosed = false; +// QVERIFY(connect(mChan.data(), +// SIGNAL(connectionClosed(uint,QString,QString)), +// SLOT(onConnectionClosed(uint,QString,QString)))); +// tp_tests_dbus_tube_channel_last_connection_disconnected(mChanService, +// TP_ERROR_STR_DISCONNECTED); +// QCOMPARE(mLoop->exec(), 0); +// QCOMPARE(mGotConnectionClosed, true); + + /* as we run several tests here, let's init/cleanup properly */ + cleanup(); + } +} + +void TestDBusTubeChan::testAcceptFail() +{ + /* incoming tube */ + createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, + TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); + QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore | + DBusTubeChannel::FeatureBusNameMonitoring), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); + QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), true); + QCOMPARE(mChan->state(), TubeChannelStateLocalPending); + + /* when accept is called the channel will be closed service side */ +// tp_tests_dbus_tube_channel_set_close_on_accept (mChanService, TRUE); + + /* calling accept should fail */ + IncomingDBusTubeChannelPtr chan = IncomingDBusTubeChannelPtr::qObjectCast(mChan); + QVERIFY(connect(chan->acceptTube(), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectFailure(Tp::PendingOperation *)))); + + QCOMPARE(mLoop->exec(), 0); + + QCOMPARE(mChan->isValid(), false); + + /* trying to accept again should fail immediately */ + QVERIFY(connect(chan->acceptTube(), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectFailure(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); +} + +void TestDBusTubeChan::testOfferSuccess() +{ + /* incoming tube */ + for (int i = 0; contexts[i].addressType != NUM_TP_SOCKET_ADDRESS_TYPES; i++) { + /* as we run several tests here, let's init/cleanup properly */ + init(); + + qDebug() << "Testing context:" << i; + mCurrentContext = i; + + createTubeChannel(true, contexts[i].addressType, + contexts[i].accessControl, contexts[i].withContact); + QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore | + DBusTubeChannel::FeatureBusNameMonitoring), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mChan->isReady(OutgoingDBusTubeChannel::FeatureCore), true); + QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), true); + QCOMPARE(mChan->state(), TubeChannelStateNotOffered); + QCOMPARE(mChan->parameters().isEmpty(), true); + + mGotRemoteConnection = false; + QVERIFY(connect(mChan.data(), + SIGNAL(busNamesChanged(QHash<ContactPtr,QString>,QList<ContactPtr>)), + SLOT(onBusNamesChanged(QHash<ContactPtr,QString>,QList<ContactPtr>)))); + + bool requiresCredentials = ((contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS) ? + true : false); + + mExpectedHandle = -1; + mExpectedId = QString(); + + mOfferFinished = false; + mGotSocketConnection = false; + OutgoingDBusTubeChannelPtr chan = OutgoingDBusTubeChannelPtr::qObjectCast(mChan); + QVariantMap offerParameters; + offerParameters.insert(QLatin1String("mushroom"), 44); + if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { + QVERIFY(connect(chan->offerTube(offerParameters, requiresCredentials), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(onOfferFinished(Tp::PendingOperation *)))); + } else { + QVERIFY(false); + } + + while (mChan->state() != TubeChannelStateRemotePending) { + mLoop->processEvents(); + } + + QCOMPARE(mGotSocketConnection, false); + + // A client now connects to the tube + if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { +// qDebug() << "Connecting to host" << localServer->fullServerName(); +// localSocket = new QLocalSocket(this); +// localSocket->connectToServer(localServer->fullServerName()); + } else { + QVERIFY(false); + } + + QCOMPARE(mGotSocketConnection, false); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mGotSocketConnection, true); + + /* simulate CM when peer connects */ + GValue *connParam = 0; + mCredentialByte = 0; + switch (contexts[i].accessControl) { + case TP_SOCKET_ACCESS_CONTROL_LOCALHOST: + connParam = tp_g_value_slice_new_static_string(""); + break; + + case TP_SOCKET_ACCESS_CONTROL_CREDENTIALS: + { +// mCredentialByte = g_random_int_range(0, G_MAXUINT8); +// +// localSocket->write(reinterpret_cast<const char*>(&mCredentialByte), 1); +// connParam = tp_g_value_slice_new_byte(mCredentialByte); + } + break; + + default: + Q_ASSERT(false); + } + + TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( + TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); + TpHandle bobHandle = tp_handle_ensure(contactRepo, "bob", NULL, NULL); +// tp_tests_dbus_tube_channel_peer_connected_no_stream(mChanService, +// connParam, bobHandle); + + tp_g_value_slice_free(connParam); + + mExpectedHandle = bobHandle; + mExpectedId = QLatin1String("bob"); + + QCOMPARE(mChan->state(), TubeChannelStateRemotePending); + + while (!mOfferFinished) { + QCOMPARE(mLoop->exec(), 0); + } + + QCOMPARE(mChan->state(), TubeChannelStateOpen); + QCOMPARE(mChan->parameters().isEmpty(), false); + QCOMPARE(mChan->parameters().size(), 1); + QCOMPARE(mChan->parameters().contains(QLatin1String("mushroom")), true); + QCOMPARE(mChan->parameters().value(QLatin1String("mushroom")), QVariant(44)); + + if (!mGotRemoteConnection) { + QCOMPARE(mLoop->exec(), 0); + } + + QCOMPARE(mGotRemoteConnection, true); + + qDebug() << "Connected to host"; + + mGotConnectionClosed = false; +// tp_tests_dbus_tube_channel_last_connection_disconnected(mChanService, +// TP_ERROR_STR_DISCONNECTED); + QCOMPARE(mLoop->exec(), 0); + QCOMPARE(mGotConnectionClosed, true); + + /* let the internal OutgoingDBusTubeChannel::onConnectionClosed slot be called before + * checking the data for that connection */ + mLoop->processEvents(); + + QCOMPARE(chan->busNames().isEmpty(), true); + + /* as we run several tests here, let's init/cleanup properly */ + cleanup(); + } +} + +void TestDBusTubeChan::testOutgoingBusNameMonitoring() +{ + mCurrentContext = 3; // should point to the room, IPv4, AC port one + createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); + QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore | + DBusTubeChannel::FeatureBusNameMonitoring), + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); + QCOMPARE(mLoop->exec(), 0); + + QVERIFY(connect(mChan.data(), + SIGNAL(busNamesChanged(QHash<ContactPtr,QString>,QList<ContactPtr>)), + SLOT(onBusNamesChanged(QHash<ContactPtr,QString>,QList<ContactPtr>)))); + + OutgoingDBusTubeChannelPtr chan = OutgoingDBusTubeChannelPtr::qObjectCast(mChan); + QVERIFY(connect(chan->offerTube(QVariantMap()), // DISCARD + SIGNAL(finished(Tp::PendingOperation *)), + SLOT(onOfferFinished(Tp::PendingOperation *)))); + + while (mChan->state() != TubeChannelStateRemotePending) { + mLoop->processEvents(); + } + + /* simulate CM when peer connects */ + GValue *connParam = tp_g_value_slice_new_take_boxed( + TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4, + dbus_g_type_specialized_construct(TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4)); + + mExpectedAddress.setAddress(QLatin1String("127.0.0.1")); + mExpectedPort = 12345; + + dbus_g_type_struct_set(connParam, + 0, mExpectedAddress.toString().toLatin1().constData(), + 1, static_cast<quint16>(mExpectedPort), + G_MAXUINT); + + // Simulate a peer connection from someone we don't have a prebuilt contact for yet, and + // immediately drop it + TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( + TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); + TpHandle handle = tp_handle_ensure(contactRepo, "YouHaventSeenMeYet", NULL, NULL); + + mExpectedHandle = handle; + mExpectedId = QLatin1String("youhaventseenmeyet"); + +// tp_tests_stream_tube_channel_peer_connected_no_stream(mChanService, +// connParam, handle); +// tp_tests_stream_tube_channel_last_connection_disconnected(mChanService, +// TP_ERROR_STR_DISCONNECTED); + tp_g_value_slice_free(connParam); + + // Test that we get newConnection first and only then connectionClosed, unlike how the code has + // been for a long time, queueing newConnection events and emitting connectionClosed directly + while (!mOfferFinished || !mGotRemoteConnection) { + QVERIFY(!mGotConnectionClosed || !mOfferFinished); + QCOMPARE(mLoop->exec(), 0); + } + + QCOMPARE(mChan->busNames().size(), 1); + + // The connectionClosed emission should finally exit the main loop + QCOMPARE(mLoop->exec(), 0); + QVERIFY(mGotConnectionClosed); + + QCOMPARE(mChan->busNames().size(), 0); +} + +void TestDBusTubeChan::cleanup() +{ + cleanupImpl(); + + if (mChan && mChan->isValid()) { + qDebug() << "waiting for the channel to become invalidated"; + + QVERIFY(connect(mChan.data(), + SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), + mLoop, + SLOT(quit()))); + tp_base_channel_close(TP_BASE_CHANNEL(mChanService)); + QCOMPARE(mLoop->exec(), 0); + } + + mChan.reset(); + + if (mChanService != 0) { + g_object_unref(mChanService); + mChanService = 0; + } + + mLoop->processEvents(); +} + +void TestDBusTubeChan::cleanupTestCase() +{ + QCOMPARE(mConn->disconnect(), true); + delete mConn; + + cleanupTestCaseImpl(); +} + +QTEST_MAIN(TestDBusTubeChan) +#include "_gen/dbus-tube-chan.cpp.moc.hpp" |
