1 #include <QtCore/QDebug>
2 #include <QtCore/QTimer>
3 #include <QtDBus/QtDBus>
4 #include <QtTest/QtTest>
5 
6 #include <QDateTime>
7 #include <QString>
8 #include <QVariantMap>
9 
10 #define TP_QT_ENABLE_LOWLEVEL_API
11 
12 #include <TelepathyQt/Account>
13 #include <TelepathyQt/AccountManager>
14 #include <TelepathyQt/ChannelClassSpec>
15 #include <TelepathyQt/Client>
16 #include <TelepathyQt/ConnectionLowlevel>
17 #include <TelepathyQt/ContactManager>
18 #include <TelepathyQt/ContactMessenger>
19 #include <TelepathyQt/Debug>
20 #include <TelepathyQt/Message>
21 #include <TelepathyQt/MessageContentPart>
22 #include <TelepathyQt/PendingAccount>
23 #include <TelepathyQt/PendingContacts>
24 #include <TelepathyQt/PendingReady>
25 #include <TelepathyQt/PendingSendMessage>
26 #include <TelepathyQt/TextChannel>
27 #include <TelepathyQt/Types>
28 
29 #include <telepathy-glib/cm-message.h>
30 #include <telepathy-glib/debug.h>
31 
32 #include <glib-object.h>
33 #include <dbus/dbus-glib.h>
34 
35 #include <tests/lib/glib/contacts-conn.h>
36 #include <tests/lib/glib/echo2/chan.h>
37 #include <tests/lib/test.h>
38 
39 using namespace Tp;
40 using namespace Tp::Client;
41 
42 class TestContactMessenger;
43 
44 class CDMessagesAdaptor : public QDBusAbstractAdaptor
45 {
46     Q_OBJECT
47     Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelDispatcher.Interface.Messages1")
48     Q_CLASSINFO("D-Bus Introspection", ""
49 "  <interface name=\"org.freedesktop.Telepathy.ChannelDispatcher.Interface.Messages1\" >\n"
50 "    <method name=\"SendMessage\" >\n"
51 "      <arg name=\"Account\" type=\"o\" direction=\"in\" />\n"
52 "      <arg name=\"TargetID\" type=\"s\" direction=\"in\" />\n"
53 "      <arg name=\"Message\" type=\"aa{sv}\" direction=\"in\" />\n"
54 "      <arg name=\"Flags\" type=\"u\" direction=\"in\" />\n"
55 "      <arg name=\"Token\" type=\"s\" direction=\"out\" />\n"
56 "    </method>\n"
57 "  </interface>\n"
58         "")
59 
60 public:
CDMessagesAdaptor(const QDBusConnection & bus,TestContactMessenger * test,QObject * parent)61     CDMessagesAdaptor(const QDBusConnection &bus, TestContactMessenger *test, QObject *parent)
62         : QDBusAbstractAdaptor(parent),
63         test(test),
64         mBus(bus)
65     {
66     }
67 
68 
~CDMessagesAdaptor()69     virtual ~CDMessagesAdaptor()
70     {
71     }
72 
setSimulatedSendError(const QString & error)73     void setSimulatedSendError(const QString &error)
74     {
75         mSimulatedSendError = error;
76     }
77 
78 public Q_SLOTS: // Methods
79     QString SendMessage(const QDBusObjectPath &account,
80             const QString &targetID, const Tp::MessagePartList &message,
81             uint flags);
82 
83 private:
84 
85     TestContactMessenger *test;
86     QDBusConnection mBus;
87     QString mSimulatedSendError;
88 };
89 
90 class AccountAdaptor : public QDBusAbstractAdaptor
91 {
92     Q_OBJECT
93     Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Account")
94     Q_CLASSINFO("D-Bus Introspection", ""
95 "  <interface name=\"org.freedesktop.Telepathy.Account\" >\n"
96 "    <property name=\"Interfaces\" type=\"as\" access=\"read\" />\n"
97 "    <property name=\"Connection\" type=\"o\" access=\"read\" />\n"
98 "    <signal name=\"AccountPropertyChanged\" >\n"
99 "      <arg name=\"Properties\" type=\"a{sv}\" />\n"
100 "    </signal>\n"
101 "  </interface>\n"
102         "")
103 
104     Q_PROPERTY(QDBusObjectPath Connection READ Connection)
105     Q_PROPERTY(QStringList Interfaces READ Interfaces)
106 
107 public:
AccountAdaptor(QObject * parent)108     AccountAdaptor(QObject *parent)
109         : QDBusAbstractAdaptor(parent), mConnection(QLatin1String("/"))
110     {
111     }
112 
~AccountAdaptor()113     virtual ~AccountAdaptor()
114     {
115     }
116 
setConnection(QString conn)117     void setConnection(QString conn)
118     {
119         if (conn.isEmpty()) {
120             conn = QLatin1String("/");
121         }
122 
123         mConnection = QDBusObjectPath(conn);
124         QVariantMap props;
125         props.insert(QLatin1String("Connection"), QVariant::fromValue(mConnection));
126         Q_EMIT AccountPropertyChanged(props);
127     }
128 
129 public: // Properties
Connection() const130     inline QDBusObjectPath Connection() const
131     {
132         return mConnection;
133     }
134 
Interfaces() const135     inline QStringList Interfaces() const
136     {
137         return QStringList();
138     }
139 
140 Q_SIGNALS: // Signals
141     void AccountPropertyChanged(const QVariantMap &properties);
142 
143 private:
144     QDBusObjectPath mConnection;
145 };
146 
147 class Dispatcher : public QObject, public QDBusContext
148 {
149     Q_OBJECT;
150 
151 public:
Dispatcher(QObject * parent)152     Dispatcher(QObject *parent)
153         : QObject(parent)
154     {
155     }
156 
~Dispatcher()157     ~Dispatcher()
158     {
159     }
160 };
161 
162 class TestContactMessenger : public Test
163 {
164     Q_OBJECT
165 
166 public:
TestContactMessenger(QObject * parent=0)167     TestContactMessenger(QObject *parent = 0)
168         : Test(parent),
169           mCDMessagesAdaptor(0), mAccountAdaptor(0),
170           // service side (telepathy-glib)
171           mConnService(0), mBaseConnService(0), mContactRepo(0),
172           mSendFinished(false), mGotMessageSent(false)
173     { }
174 
175 protected Q_SLOTS:
176     void expectPendingContactsFinished(Tp::PendingOperation *op);
177     void onSendFinished(Tp::PendingOperation *);
178     void onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags,
179             const QString &sentMessageToken, const Tp::TextChannelPtr &channel);
180     void onMessageReceived(const Tp::ReceivedMessage &message,
181             const Tp::TextChannelPtr &channel);
182 
183 private Q_SLOTS:
184     void initTestCase();
185     void init();
186 
187     void testNoSupport();
188     void testObserverRegistration();
189     void testSimpleSend();
190     void testReceived();
191     void testReceivedFromContact();
192 
193     void cleanup();
194     void cleanupTestCase();
195 
196 private:
197 
198     friend class CDMessagesAdaptor;
199 
200     QList<ClientObserverInterface *> ourObservers();
201 
202     CDMessagesAdaptor *mCDMessagesAdaptor;
203     AccountAdaptor *mAccountAdaptor;
204     QString mAccountBusName, mAccountPath;
205 
206     AccountManagerPtr mAM;
207     AccountPtr mAccount;
208     ConnectionPtr mConn;
209     TextChannelPtr mChan;
210 
211     TpTestsContactsConnection *mConnService;
212     TpBaseConnection *mBaseConnService;
213     TpHandleRepoIface *mContactRepo;
214     ExampleEcho2Channel *mMessagesChanService;
215 
216     QString mConnName;
217     QString mConnPath;
218     QString mMessagesChanPath;
219 
220     bool mSendFinished, mGotMessageSent, mGotMessageReceived;
221     QString mSendError, mSendToken, mMessageSentText, mMessageSentToken, mMessageSentChannel;
222     QString mMessageReceivedText;
223     ChannelPtr mMessageReceivedChan;
224 
225     QList<ContactPtr> mContacts;
226 };
227 
SendMessage(const QDBusObjectPath & account,const QString & targetID,const MessagePartList & message,uint flags)228 QString CDMessagesAdaptor::SendMessage(const QDBusObjectPath &account,
229         const QString &targetID, const MessagePartList &message,
230         uint flags)
231 {
232     if (!mSimulatedSendError.isEmpty()) {
233         dynamic_cast<QDBusContext *>(QObject::parent())->sendErrorReply(mSimulatedSendError,
234                 QLatin1String("Let's pretend this interface and method don't exist, shall we?"));
235         return QString();
236     }
237 
238     /*
239      * Sadly, the QDBus local-loop "optimization" prevents us from correctly waiting for the
240      * ObserveChannels call to return, and consequently prevents us from knowing when we can call
241      * Send, knowing that the observer has connected to the message sent signal.
242      *
243      * The real MC doesn't have this limitation because it actually really calls and waits our
244      * ObserveChannels method to finish, unlike dear QDBus here.
245      */
246     QList<ClientObserverInterface *> observers = test->ourObservers();
247     Q_FOREACH(ClientObserverInterface *iface, observers) {
248         ChannelDetails chan = { QDBusObjectPath(test->mChan->objectPath()), test->mChan->immutableProperties() };
249         QDBusPendingCallWatcher *watcher =
250             new QDBusPendingCallWatcher(iface->ObserveChannels(
251                 QDBusObjectPath(test->mAccount->objectPath()),
252                 QDBusObjectPath(test->mChan->connection()->objectPath()),
253                 ChannelDetailsList() << chan,
254                 QDBusObjectPath(QLatin1String("/")),
255                 Tp::ObjectPathList(),
256                 QVariantMap()));
257 
258         connect(watcher,
259                     SIGNAL(finished(QDBusPendingCallWatcher*)),
260                     test->mLoop,
261                     SLOT(quit()));
262         test->mLoop->exec();
263         QDBusPendingReply<void> reply = *watcher;
264         qDebug() << reply.error(); // Always gives out "local-loop messages can't have delayed replies"
265 
266         delete watcher;
267     }
268 
269     qDebug() << "Calling send"; // And this is always called before the observer manages to connect to messageSent. Bummer.
270 
271     PendingSendMessage *msg = test->mChan->send(message, static_cast<MessageSendingFlags>(flags));
272     connect(msg,
273             SIGNAL(finished(Tp::PendingOperation*)),
274             test,
275             SLOT(expectSuccessfulCall(Tp::PendingOperation*)));
276     test->mLoop->exec();
277     return msg->sentMessageToken();
278 }
279 
expectPendingContactsFinished(PendingOperation * op)280 void TestContactMessenger::expectPendingContactsFinished(PendingOperation *op)
281 {
282     TEST_VERIFY_OP(op);
283 
284     PendingContacts *pending = qobject_cast<PendingContacts *>(op);
285     mContacts = pending->contacts();
286     mLoop->exit(0);
287 }
288 
onSendFinished(Tp::PendingOperation * op)289 void TestContactMessenger::onSendFinished(Tp::PendingOperation *op)
290 {
291     PendingSendMessage *msg = qobject_cast<PendingSendMessage *>(op);
292     QVERIFY(msg != NULL);
293 
294     if (msg->isValid()) {
295         qDebug() << "Send succeeded, got token" << msg->sentMessageToken();
296         mSendToken = msg->sentMessageToken();
297     } else {
298         qDebug() << "Send failed, got error" << msg->errorName();
299         mSendError = msg->errorName();
300     }
301 
302     mSendFinished = true;
303 }
304 
onMessageSent(const Tp::Message & message,Tp::MessageSendingFlags flags,const QString & sentMessageToken,const Tp::TextChannelPtr & channel)305 void TestContactMessenger::onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags,
306         const QString &sentMessageToken, const Tp::TextChannelPtr &channel)
307 {
308     qDebug() << "Got ContactMessenger::messageSent()";
309 
310     mGotMessageSent = true;
311     mMessageSentToken = sentMessageToken;
312     mMessageSentText = message.text();
313 }
314 
onMessageReceived(const Tp::ReceivedMessage & message,const Tp::TextChannelPtr & channel)315 void TestContactMessenger::onMessageReceived(const Tp::ReceivedMessage &message,
316         const Tp::TextChannelPtr &channel)
317 {
318     qDebug() << "Got ContactMessenger::messageReceived()";
319 
320     mGotMessageReceived = true;
321     mMessageReceivedText = message.text();
322     mMessageReceivedChan = channel;
323 }
324 
initTestCase()325 void TestContactMessenger::initTestCase()
326 {
327     initTestCaseImpl();
328 
329     g_type_init();
330     g_set_prgname("contact-messenger");
331     tp_debug_set_flags("all");
332     dbus_g_bus_get(DBUS_BUS_STARTER, 0);
333 
334     QDBusConnection bus = QDBusConnection::sessionBus();
335     QString channelDispatcherBusName = TP_QT_IFACE_CHANNEL_DISPATCHER;
336     QString channelDispatcherPath = QLatin1String("/org/freedesktop/Telepathy/ChannelDispatcher");
337     Dispatcher *dispatcher = new Dispatcher(this);
338     mCDMessagesAdaptor = new CDMessagesAdaptor(bus, this, dispatcher);
339     QVERIFY(bus.registerService(channelDispatcherBusName));
340     QVERIFY(bus.registerObject(channelDispatcherPath, dispatcher));
341 
342     mAccountBusName = TP_QT_IFACE_ACCOUNT_MANAGER;
343     mAccountPath = QLatin1String("/org/freedesktop/Telepathy/Account/simple/simple/account");
344     QObject *acc = new QObject(this);
345 
346     mAccountAdaptor = new AccountAdaptor(acc);
347 
348     QVERIFY(bus.registerService(mAccountBusName));
349     QVERIFY(bus.registerObject(mAccountPath, acc));
350 
351     mAccount = Account::create(mAccountBusName, mAccountPath);
352     QVERIFY(connect(mAccount->becomeReady(),
353                     SIGNAL(finished(Tp::PendingOperation *)),
354                     SLOT(expectSuccessfulCall(Tp::PendingOperation *))));
355     QCOMPARE(mLoop->exec(), 0);
356     QCOMPARE(mAccount->isReady(), true);
357 
358     QCOMPARE(mAccount->supportsRequestHints(), false);
359     QCOMPARE(mAccount->requestsSucceedWithChannel(), false);
360 
361     mConnService = TP_TESTS_CONTACTS_CONNECTION(g_object_new(
362             TP_TESTS_TYPE_CONTACTS_CONNECTION,
363             "account", "me@example.com",
364             "protocol", "example",
365             NULL));
366     QVERIFY(mConnService != 0);
367     mBaseConnService = TP_BASE_CONNECTION(mConnService);
368     QVERIFY(mBaseConnService != 0);
369 
370     gchar *name, *connPath;
371     GError *error = NULL;
372 
373     QVERIFY(tp_base_connection_register(mBaseConnService,
374                 "example", &name, &connPath, &error));
375     QVERIFY(error == 0);
376 
377     QVERIFY(name != 0);
378     QVERIFY(connPath != 0);
379 
380     mConnName = QLatin1String(name);
381     mConnPath = QLatin1String(connPath);
382 
383     g_free(name);
384     g_free(connPath);
385 
386     mAccountAdaptor->setConnection(mConnPath);
387 
388     mConn = Connection::create(mConnName, mConnPath,
389             ChannelFactory::create(QDBusConnection::sessionBus()),
390             ContactFactory::create());
391     QCOMPARE(mConn->isReady(), false);
392 
393     QVERIFY(connect(mConn->lowlevel()->requestConnect(),
394                     SIGNAL(finished(Tp::PendingOperation*)),
395                     SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
396     QCOMPARE(mLoop->exec(), 0);
397     QCOMPARE(mConn->isReady(), true);
398     QCOMPARE(static_cast<uint>(mConn->status()),
399             static_cast<uint>(ConnectionStatusConnected));
400 
401     mContactRepo = tp_base_connection_get_handles(mBaseConnService,
402             TP_HANDLE_TYPE_CONTACT);
403     guint handle = tp_handle_ensure(mContactRepo, "Ann", 0, 0);
404 
405     mMessagesChanPath = mConnPath + QLatin1String("/MessagesChannel");
406     QByteArray chanPath = mMessagesChanPath.toLatin1();
407     mMessagesChanService = EXAMPLE_ECHO_2_CHANNEL(g_object_new(
408                 EXAMPLE_TYPE_ECHO_2_CHANNEL,
409                 "connection", mConnService,
410                 "object-path", chanPath.data(),
411                 "handle", handle,
412                 NULL));
413 
414     QVariantMap immutableProperties;
415     immutableProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"),
416             QLatin1String("ann"));
417     mChan = TextChannel::create(mConn, mMessagesChanPath, immutableProperties);
418     QVERIFY(connect(mChan->becomeReady(),
419                 SIGNAL(finished(Tp::PendingOperation *)),
420                 SLOT(expectSuccessfulCall(Tp::PendingOperation *))));
421     QCOMPARE(mLoop->exec(), 0);
422 }
423 
init()424 void TestContactMessenger::init()
425 {
426     initImpl();
427 
428     mSendFinished = false;
429     mGotMessageSent = false;
430     mGotMessageReceived = false;
431     mCDMessagesAdaptor->setSimulatedSendError(QString());
432 }
433 
testNoSupport()434 void TestContactMessenger::testNoSupport()
435 {
436     // We should give a descriptive error message if the CD doesn't actually support sending
437     // messages using the new API. NotImplemented should probably be documented for the
438     // sendMessage() methods as an indication that the CD implementation needs to be upgraded.
439 
440     ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann"));
441     QVERIFY(!messenger.isNull());
442 
443     mCDMessagesAdaptor->setSimulatedSendError(TP_QT_DBUS_ERROR_UNKNOWN_METHOD);
444 
445     PendingSendMessage *pendingSend = messenger->sendMessage(QLatin1String("Hi!"));
446     QVERIFY(pendingSend != NULL);
447 
448     QVERIFY(connect(pendingSend,
449                 SIGNAL(finished(Tp::PendingOperation*)),
450                 SLOT(expectFailure(Tp::PendingOperation*))));
451     QCOMPARE(mLoop->exec(), 0);
452     QVERIFY(pendingSend->isFinished());
453     QVERIFY(!pendingSend->isValid());
454 
455     QCOMPARE(pendingSend->errorName(), TP_QT_ERROR_NOT_IMPLEMENTED);
456 
457     // Let's try using the other sendMessage overload similarly as well
458 
459     Message m(ChannelTextMessageTypeAction, QLatin1String("is testing!"));
460 
461     pendingSend = messenger->sendMessage(m.parts());
462     QVERIFY(pendingSend != NULL);
463 
464     QVERIFY(connect(pendingSend,
465                 SIGNAL(finished(Tp::PendingOperation*)),
466                 SLOT(expectFailure(Tp::PendingOperation*))));
467     QCOMPARE(mLoop->exec(), 0);
468     QVERIFY(pendingSend->isFinished());
469     QVERIFY(!pendingSend->isValid());
470 
471     QCOMPARE(pendingSend->errorName(), TP_QT_ERROR_NOT_IMPLEMENTED);
472 }
473 
testObserverRegistration()474 void TestContactMessenger::testObserverRegistration()
475 {
476     ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann"));
477 
478     // At this point, there should be a registered observer for the relevant channel class on our
479     // unique name
480 
481     QList<ClientObserverInterface *> observers = ourObservers();
482     QVERIFY(!observers.empty());
483 
484     Q_FOREACH(ClientObserverInterface *observer, observers) {
485         // It shouldn't have recover == true, as it shouldn't be activatable at all, and hence recovery
486         // doesn't make sense for it
487         bool recover;
488         QVERIFY(waitForProperty(observer->requestPropertyRecover(), &recover));
489         QCOMPARE(recover, true);
490     }
491 
492     // If we destroy our messenger (which is the last/only one for that ID), the observers should go
493     // away, at least in a few mainloop iterations
494     messenger.reset();
495 
496     QVERIFY(ourObservers().empty());
497 }
498 
testSimpleSend()499 void TestContactMessenger::testSimpleSend()
500 {
501     ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann"));
502 
503     QVERIFY(connect(messenger->sendMessage(QLatin1String("Hi!")),
504             SIGNAL(finished(Tp::PendingOperation*)),
505             SLOT(onSendFinished(Tp::PendingOperation*))));
506 
507     while (!mSendFinished) {
508         mLoop->processEvents();
509     }
510 
511     QVERIFY(mSendError.isEmpty());
512 }
513 
testReceived()514 void TestContactMessenger::testReceived()
515 {
516     ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann"));
517 
518     QVERIFY(connect(messenger.data(),
519             SIGNAL(messageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)),
520             SLOT(onMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr))));
521 
522     QList<ClientObserverInterface *> observers = ourObservers();
523     Q_FOREACH(ClientObserverInterface *iface, observers) {
524         ChannelDetails chan = { QDBusObjectPath(mChan->objectPath()), mChan->immutableProperties() };
525         iface->ObserveChannels(
526                 QDBusObjectPath(mAccount->objectPath()),
527                 QDBusObjectPath(mChan->connection()->objectPath()),
528                 ChannelDetailsList() << chan,
529                 QDBusObjectPath(QLatin1String("/")),
530                 Tp::ObjectPathList(),
531                 QVariantMap());
532     }
533 
534     guint handle = tp_handle_ensure(mContactRepo, "Ann", 0, 0);
535     TpMessage *msg = tp_cm_message_new_text(mBaseConnService, handle, TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, "Hi!");
536 
537     tp_message_mixin_take_received(G_OBJECT(mMessagesChanService), msg);
538 
539     while (!mGotMessageReceived) {
540         mLoop->processEvents();
541     }
542 
543     QCOMPARE(mMessageReceivedText, QString::fromLatin1("Hi!"));
544     QCOMPARE(mMessageReceivedChan->objectPath(), mChan->objectPath());
545 }
546 
testReceivedFromContact()547 void TestContactMessenger::testReceivedFromContact()
548 {
549     QVERIFY(connect(mAccount->connection()->contactManager()->contactsForIdentifiers(
550                         QStringList() << QLatin1String("Ann")),
551                     SIGNAL(finished(Tp::PendingOperation*)),
552                     SLOT(expectPendingContactsFinished(Tp::PendingOperation*))));
553     QCOMPARE(mLoop->exec(), 0);
554 
555     ContactPtr ann = mContacts.first();
556     ContactMessengerPtr messenger = ContactMessenger::create(mAccount, ann);
557 
558     QVERIFY(connect(messenger.data(),
559             SIGNAL(messageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)),
560             SLOT(onMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr))));
561 
562     QList<ClientObserverInterface *> observers = ourObservers();
563     Q_FOREACH(ClientObserverInterface *iface, observers) {
564         ChannelDetails chan = { QDBusObjectPath(mChan->objectPath()), mChan->immutableProperties() };
565         iface->ObserveChannels(
566                 QDBusObjectPath(mAccount->objectPath()),
567                 QDBusObjectPath(mChan->connection()->objectPath()),
568                 ChannelDetailsList() << chan,
569                 QDBusObjectPath(QLatin1String("/")),
570                 Tp::ObjectPathList(),
571                 QVariantMap());
572     }
573 
574     guint handle = tp_handle_ensure(mContactRepo, "Ann", 0, 0);
575     TpMessage *msg = tp_cm_message_new_text(mBaseConnService, handle, TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, "Hi!");
576 
577     tp_message_mixin_take_received(G_OBJECT(mMessagesChanService), msg);
578 
579     while (!mGotMessageReceived) {
580         mLoop->processEvents();
581     }
582 
583     QCOMPARE(mMessageReceivedText, QString::fromLatin1("Hi!"));
584     QCOMPARE(mMessageReceivedChan->objectPath(), mChan->objectPath());
585 }
586 
587 
cleanup()588 void TestContactMessenger::cleanup()
589 {
590     mMessageReceivedChan.reset();
591 
592     cleanupImpl();
593 }
594 
cleanupTestCase()595 void TestContactMessenger::cleanupTestCase()
596 {
597     if (mConn) {
598         // Disconnect and wait for the readiness change
599         QVERIFY(connect(mConn->lowlevel()->requestDisconnect(),
600                         SIGNAL(finished(Tp::PendingOperation*)),
601                         SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
602         QCOMPARE(mLoop->exec(), 0);
603 
604         if (mConn->isValid()) {
605             QVERIFY(connect(mConn.data(),
606                             SIGNAL(invalidated(Tp::DBusProxy *,
607                                                const QString &, const QString &)),
608                             mLoop,
609                             SLOT(quit())));
610             QCOMPARE(mLoop->exec(), 0);
611         }
612     }
613 
614     mChan.reset();
615 
616     if (mMessagesChanService != 0) {
617         g_object_unref(mMessagesChanService);
618         mMessagesChanService = 0;
619     }
620 
621     if (mConnService != 0) {
622         mBaseConnService = 0;
623         g_object_unref(mConnService);
624         mConnService = 0;
625     }
626 
627     cleanupTestCaseImpl();
628 }
629 
ourObservers()630 QList<ClientObserverInterface *> TestContactMessenger::ourObservers()
631 {
632     QStringList registeredNames =
633         QDBusConnection::sessionBus().interface()->registeredServiceNames();
634     QList<ClientObserverInterface *> observers;
635 
636     Q_FOREACH (QString name, registeredNames) {
637         if (!name.startsWith(QLatin1String("org.freedesktop.Telepathy.Client."))) {
638             continue;
639         }
640 
641         if (QDBusConnection::sessionBus().interface()->serviceOwner(name).value() !=
642                 QDBusConnection::sessionBus().baseService()) {
643             continue;
644         }
645 
646         QString path = QLatin1Char('/') + name;
647         path.replace(QLatin1Char('.'), QLatin1Char('/'));
648 
649         ClientInterface client(name, path);
650         QStringList ifaces;
651         if (!waitForProperty(client.requestPropertyInterfaces(), &ifaces)) {
652             continue;
653         }
654 
655         if (!ifaces.contains(TP_QT_IFACE_CLIENT_OBSERVER)) {
656             continue;
657         }
658 
659         ClientObserverInterface *observer = new ClientObserverInterface(name, path, this);
660 
661         ChannelClassList filter;
662         if (!waitForProperty(observer->requestPropertyObserverChannelFilter(), &filter)) {
663             continue;
664         }
665 
666         Q_FOREACH (ChannelClassSpec spec, filter) {
667             if (spec.isSubsetOf(ChannelClassSpec::textChat())) {
668                 observers.push_back(observer);
669                 qDebug() << "Found our observer" << name << '\n';
670                 break;
671             }
672         }
673     }
674 
675     return observers;
676 }
677 
678 QTEST_MAIN(TestContactMessenger)
679 #include "_gen/contact-messenger.cpp.moc.hpp"
680