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