1 #include <QtCore/QDebug>
2 #include <QtCore/QTimer>
3 #include <QtDBus/QtDBus>
4 #include <QtTest/QtTest>
5
6 #include <cstring>
7
8 #include <QDateTime>
9 #include <QString>
10 #include <QVariantMap>
11
12 #define TP_QT_ENABLE_LOWLEVEL_API
13
14 #include <TelepathyQt/Account>
15 #include <TelepathyQt/ChannelClassSpec>
16 #include <TelepathyQt/Client>
17 #include <TelepathyQt/ConnectionLowlevel>
18 #include <TelepathyQt/Debug>
19 #include <TelepathyQt/PendingReady>
20 #include <TelepathyQt/SimpleCallObserver>
21 #include <TelepathyQt/SimpleObserver>
22 #include <TelepathyQt/SimpleTextObserver>
23 #include <TelepathyQt/StreamedMediaChannel>
24 #include <TelepathyQt/TextChannel>
25 #include <TelepathyQt/Types>
26
27 #include <telepathy-glib/cm-message.h>
28 #include <telepathy-glib/debug.h>
29
30 #include <glib-object.h>
31 #include <dbus/dbus-glib.h>
32
33 #include <tests/lib/glib/contacts-conn.h>
34 #include <tests/lib/glib/echo2/chan.h>
35 #include <tests/lib/glib/callable/media-channel.h>
36 #include <tests/lib/test.h>
37
38 using namespace Tp;
39 using namespace Tp::Client;
40
41 class TestSimpleObserver;
42
43 namespace
44 {
45
channels(const QList<TextChannelPtr> & channels)46 QList<ChannelPtr> channels(const QList<TextChannelPtr> &channels)
47 {
48 QList<ChannelPtr> ret;
49 Q_FOREACH (const TextChannelPtr &channel, channels) {
50 ret << channel;
51 }
52 return ret;
53 }
54
channels(const QList<StreamedMediaChannelPtr> & channels)55 QList<ChannelPtr> channels(const QList<StreamedMediaChannelPtr> &channels)
56 {
57 QList<ChannelPtr> ret;
58 Q_FOREACH (const StreamedMediaChannelPtr &channel, channels) {
59 ret << channel;
60 }
61 return ret;
62 }
63
64 }
65
66 class AccountAdaptor : public QDBusAbstractAdaptor
67 {
68 Q_OBJECT
69 Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Account")
70 Q_CLASSINFO("D-Bus Introspection", ""
71 " <interface name=\"org.freedesktop.Telepathy.Account\" >\n"
72 " <property name=\"Interfaces\" type=\"as\" access=\"read\" />\n"
73 " <property name=\"Connection\" type=\"o\" access=\"read\" />\n"
74 " <signal name=\"AccountPropertyChanged\" >\n"
75 " <arg name=\"Properties\" type=\"a{sv}\" />\n"
76 " </signal>\n"
77 " </interface>\n"
78 "")
79
80 Q_PROPERTY(QDBusObjectPath Connection READ Connection)
81 Q_PROPERTY(QStringList Interfaces READ Interfaces)
82
83 public:
AccountAdaptor(QObject * parent)84 AccountAdaptor(QObject *parent)
85 : QDBusAbstractAdaptor(parent), mConnection(QLatin1String("/"))
86 {
87 }
88
~AccountAdaptor()89 virtual ~AccountAdaptor()
90 {
91 }
92
setConnection(QString conn)93 void setConnection(QString conn)
94 {
95 if (conn.isEmpty()) {
96 conn = QLatin1String("/");
97 }
98
99 mConnection = QDBusObjectPath(conn);
100 QVariantMap props;
101 props.insert(QLatin1String("Connection"), QVariant::fromValue(mConnection));
102 Q_EMIT AccountPropertyChanged(props);
103 }
104
105 public: // Properties
Connection() const106 inline QDBusObjectPath Connection() const
107 {
108 return mConnection;
109 }
110
Interfaces() const111 inline QStringList Interfaces() const
112 {
113 return QStringList();
114 }
115
116 Q_SIGNALS: // Signals
117 void AccountPropertyChanged(const QVariantMap &properties);
118
119 private:
120 QDBusObjectPath mConnection;
121 };
122
123 class Dispatcher : public QObject, public QDBusContext
124 {
125 Q_OBJECT;
126
127 public:
Dispatcher(QObject * parent)128 Dispatcher(QObject *parent)
129 : QObject(parent)
130 {
131 }
132
~Dispatcher()133 ~Dispatcher()
134 {
135 }
136 };
137
138 class TestSimpleObserver : public Test
139 {
140 Q_OBJECT
141
142 public:
TestSimpleObserver(QObject * parent=0)143 TestSimpleObserver(QObject *parent = 0)
144 : Test(parent),
145 mChannelsCount(0), mSMChannelsCount(0)
146 {
147 std::memset(mMessagesChanServices, 0, sizeof(mMessagesChanServices));
148 std::memset(mCallableChanServices, 0, sizeof(mCallableChanServices));
149 }
150
151 protected Q_SLOTS:
152 void onObserverNewChannels(const QList<Tp::ChannelPtr> &channels);
153 void onObserverChannelInvalidated(const Tp::ChannelPtr &channel,
154 const QString &errorName, const QString &errorMessage);
155 void onObserverStreamedMediaCallStarted(
156 const Tp::StreamedMediaChannelPtr &channel);
157 void onObserverStreamedMediaCallEnded(
158 const Tp::StreamedMediaChannelPtr &channel,
159 const QString &errorMessage, const QString &errorName);
160
161 private Q_SLOTS:
162 void initTestCase();
163 void init();
164
165 void testObserverRegistration();
166 void testCrossTalk();
167
168 void cleanup();
169 void cleanupTestCase();
170
171 private:
172 QMap<QString, QString> ourObservers();
173
174 AccountPtr mAccounts[2];
175
176 struct ConnInfo {
ConnInfoTestSimpleObserver::ConnInfo177 ConnInfo()
178 : connService(0), baseConnService(0), contactRepo(0)
179 {
180 }
181
182 TpTestsContactsConnection *connService;
183 TpBaseConnection *baseConnService;
184 ConnectionPtr conn;
185 TpHandleRepoIface *contactRepo;
186 };
187 ConnInfo mConns[2];
188
189 QStringList mContacts;
190
191 ExampleEcho2Channel *mMessagesChanServices[2];
192 TextChannelPtr mTextChans[2];
193
194 ExampleCallableMediaChannel *mCallableChanServices[2];
195 StreamedMediaChannelPtr mSMChans[2];
196
197 int mChannelsCount;
198 int mSMChannelsCount;
199 };
200
onObserverNewChannels(const QList<Tp::ChannelPtr> & channels)201 void TestSimpleObserver::onObserverNewChannels(const QList<Tp::ChannelPtr> &channels)
202 {
203 QVERIFY(channels.size() == 1);
204 mChannelsCount += channels.size();
205 }
206
onObserverChannelInvalidated(const Tp::ChannelPtr & channel,const QString & errorName,const QString & errorMessage)207 void TestSimpleObserver::onObserverChannelInvalidated(const Tp::ChannelPtr &channel,
208 const QString &errorName, const QString &errorMessage)
209 {
210 QVERIFY(!channel.isNull());
211 mChannelsCount -= 1;
212 }
213
onObserverStreamedMediaCallStarted(const Tp::StreamedMediaChannelPtr & channel)214 void TestSimpleObserver::onObserverStreamedMediaCallStarted(
215 const Tp::StreamedMediaChannelPtr &channel)
216 {
217 QVERIFY(!channel.isNull());
218 mSMChannelsCount++;
219 }
220
onObserverStreamedMediaCallEnded(const Tp::StreamedMediaChannelPtr & channel,const QString & errorMessage,const QString & errorName)221 void TestSimpleObserver::onObserverStreamedMediaCallEnded(const Tp::StreamedMediaChannelPtr &channel,
222 const QString &errorMessage, const QString &errorName)
223 {
224 QVERIFY(!channel.isNull());
225 mSMChannelsCount--;
226 }
227
initTestCase()228 void TestSimpleObserver::initTestCase()
229 {
230 initTestCaseImpl();
231
232 g_type_init();
233 g_set_prgname("simple-observer");
234 tp_debug_set_flags("all");
235 dbus_g_bus_get(DBUS_BUS_STARTER, 0);
236
237 QDBusConnection bus = QDBusConnection::sessionBus();
238 QString channelDispatcherBusName = TP_QT_IFACE_CHANNEL_DISPATCHER;
239 QString channelDispatcherPath = QLatin1String("/org/freedesktop/Telepathy/ChannelDispatcher");
240 Dispatcher *dispatcher = new Dispatcher(this);
241 QVERIFY(bus.registerService(channelDispatcherBusName));
242 QVERIFY(bus.registerObject(channelDispatcherPath, dispatcher));
243
244 mContacts << QLatin1String("alice") << QLatin1String("bob");
245
246 // Create 2 accounts to be used by the tests:
247 // - each account contains a connection, a text channel and a SM channel setup:
248 // - the channels for the first account have alice as target and;
249 // - the channels for the second account have bob as target
250 for (int i = 0; i < 2; ++i) {
251 // setup account
252 QString accountBusName = TP_QT_IFACE_ACCOUNT_MANAGER;
253 QString accountPath = QLatin1String("/org/freedesktop/Telepathy/Account/simple/account/") +
254 QString::number(i);
255
256 QObject *adaptorObject = new QObject(this);
257 AccountAdaptor *accountAdaptor = new AccountAdaptor(adaptorObject);
258 QVERIFY(bus.registerService(accountBusName));
259 QVERIFY(bus.registerObject(accountPath, adaptorObject));
260
261 AccountPtr acc = Account::create(accountBusName, accountPath);
262 QVERIFY(connect(acc->becomeReady(),
263 SIGNAL(finished(Tp::PendingOperation *)),
264 SLOT(expectSuccessfulCall(Tp::PendingOperation *))));
265 QCOMPARE(mLoop->exec(), 0);
266 QCOMPARE(acc->isReady(), true);
267 QCOMPARE(acc->supportsRequestHints(), false);
268 QCOMPARE(acc->requestsSucceedWithChannel(), false);
269 mAccounts[i] = acc;
270
271 // setup conn
272 TpTestsContactsConnection *connService = TP_TESTS_CONTACTS_CONNECTION(
273 g_object_new(TP_TESTS_TYPE_CONTACTS_CONNECTION,
274 "account", "me@example.com",
275 "protocol", "example",
276 NULL));
277 QVERIFY(connService != 0);
278 TpBaseConnection *baseConnService = TP_BASE_CONNECTION(connService);
279 QVERIFY(baseConnService != 0);
280
281 gchar *connName, *connPath;
282 GError *error = NULL;
283
284 QString name(QLatin1String("example") + QString::number(i));
285 QVERIFY(tp_base_connection_register(baseConnService,
286 name.toLatin1().constData(), &connName, &connPath, &error));
287 QVERIFY(error == 0);
288
289 QVERIFY(connName != 0);
290 QVERIFY(connPath != 0);
291
292 ConnectionPtr conn = Connection::create(QLatin1String(connName), QLatin1String(connPath),
293 ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create());
294 QCOMPARE(conn->isReady(), false);
295
296 accountAdaptor->setConnection(QLatin1String(connPath));
297
298 QVERIFY(connect(conn->lowlevel()->requestConnect(),
299 SIGNAL(finished(Tp::PendingOperation*)),
300 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
301 QCOMPARE(mLoop->exec(), 0);
302 QCOMPARE(conn->isReady(), true);
303 QCOMPARE(conn->status(), ConnectionStatusConnected);
304
305 TpHandleRepoIface *contactRepo = tp_base_connection_get_handles(baseConnService,
306 TP_HANDLE_TYPE_CONTACT);
307
308 mConns[i].connService = connService;
309 mConns[i].baseConnService = baseConnService;
310 mConns[i].conn = conn;
311 mConns[i].contactRepo = contactRepo;
312
313 // setup channels
314 guint handle = tp_handle_ensure(contactRepo, mContacts[i].toLatin1().constData(), 0, 0);
315
316 QString messagesChanPath = QLatin1String(connPath) +
317 QLatin1String("/MessagesChannel/") + QString::number(i);
318 mMessagesChanServices[i] = EXAMPLE_ECHO_2_CHANNEL(g_object_new(
319 EXAMPLE_TYPE_ECHO_2_CHANNEL,
320 "connection", connService,
321 "object-path", messagesChanPath.toLatin1().constData(),
322 "handle", handle,
323 NULL));
324
325 QVariantMap immutableProperties;
326 immutableProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), mContacts[i]);
327 mTextChans[i] = TextChannel::create(conn, messagesChanPath, immutableProperties);
328 QVERIFY(connect(mTextChans[i]->becomeReady(),
329 SIGNAL(finished(Tp::PendingOperation *)),
330 SLOT(expectSuccessfulCall(Tp::PendingOperation *))));
331 QCOMPARE(mLoop->exec(), 0);
332
333 QString callableChanPath = QLatin1String(connPath) +
334 QLatin1String("/CallableChannel/") + QString::number(i);
335 mCallableChanServices[i] = EXAMPLE_CALLABLE_MEDIA_CHANNEL(g_object_new(
336 EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL,
337 "connection", connService,
338 "object-path", callableChanPath.toLatin1().constData(),
339 "handle", handle,
340 NULL));
341
342 immutableProperties.clear();
343 immutableProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), mContacts[i]);
344 mSMChans[i] = StreamedMediaChannel::create(conn, callableChanPath, immutableProperties);
345 QVERIFY(connect(mSMChans[i]->becomeReady(),
346 SIGNAL(finished(Tp::PendingOperation *)),
347 SLOT(expectSuccessfulCall(Tp::PendingOperation *))));
348 QCOMPARE(mLoop->exec(), 0);
349
350 g_free(connName);
351 g_free(connPath);
352 }
353 }
354
init()355 void TestSimpleObserver::init()
356 {
357 initImpl();
358 }
359
testObserverRegistration()360 void TestSimpleObserver::testObserverRegistration()
361 {
362 QVERIFY(ourObservers().isEmpty());
363
364 QList<SimpleObserverPtr> observers;
365 QList<SimpleTextObserverPtr> textObservers;
366 QList<SimpleCallObserverPtr> callObservers;
367 int numRegisteredObservers = 0;
368 // Observers should be shared by bus and channel class, meaning that
369 // the following code should register only 4 observers:
370 // - one for text chat rooms
371 // - one for text chats
372 // - one for incoming/outgoing calls
373 // - one for incoming calls (incoming)
374 //
375 // The Simple*Observer instances are added to the lists observers/textObservers/callObservers,
376 // so they don't get deleted (refcount == 0) when out of scope
377 for (int i = 0; i < 2; ++i) {
378 AccountPtr acc = mAccounts[i];
379
380 for (int j = 0; j < 2; ++j) {
381 QString contact = mContacts[j];
382
383 if (i == 0 && j == 0) {
384 numRegisteredObservers = 1;
385 }
386
387 // on first run the following code should register an observer for text chat rooms,
388 // on consecutive runs it should use the already registered observer for text chat rooms
389 SimpleObserverPtr observer = SimpleObserver::create(acc,
390 ChannelClassSpec::textChatroom(), contact);
391 QCOMPARE(observer->account(), acc);
392 QVERIFY(observer->channelFilter().size() == 1);
393 QVERIFY(observer->channelFilter().contains(ChannelClassSpec::textChatroom()));
394 QCOMPARE(observer->contactIdentifier(), contact);
395 QVERIFY(observer->extraChannelFeatures().isEmpty());
396 QVERIFY(observer->channels().isEmpty());
397 observers.append(observer);
398 QCOMPARE(ourObservers().size(), numRegisteredObservers);
399
400 // the following code should always reuse the observer for text chat rooms already
401 // created.
402 QList<ChannelClassFeatures> extraChannelFeatures;
403 extraChannelFeatures.append(QPair<ChannelClassSpec, Features>(
404 ChannelClassSpec::textChatroom(), Channel::FeatureCore));
405 observer = SimpleObserver::create(acc,
406 ChannelClassSpec::textChatroom(), contact, extraChannelFeatures);
407 QCOMPARE(observer->account(), acc);
408 QVERIFY(observer->channelFilter().size() == 1);
409 QVERIFY(observer->channelFilter().contains(ChannelClassSpec::textChatroom()));
410 QCOMPARE(observer->contactIdentifier(), contact);
411 QCOMPARE(observer->extraChannelFeatures(), extraChannelFeatures);
412 QVERIFY(observer->channels().isEmpty());
413 observers.append(observer);
414 QCOMPARE(ourObservers().size(), numRegisteredObservers);
415
416 if (i == 0 && j == 0) {
417 numRegisteredObservers = 2;
418 }
419
420 // on first run the following code should register an observer for text chats,
421 // on consecutive runs it should use the already registered observer for text chats
422 SimpleTextObserverPtr textObserver = SimpleTextObserver::create(acc, contact);
423 QCOMPARE(textObserver->account(), acc);
424 QCOMPARE(textObserver->contactIdentifier(), contact);
425 QVERIFY(textObserver->textChats().isEmpty());
426 textObservers.append(textObserver);
427 QCOMPARE(ourObservers().size(), numRegisteredObservers);
428
429 // the following code should always reuse the observer for text chats already
430 // created.
431 textObserver = SimpleTextObserver::create(acc, contact);
432 QCOMPARE(textObserver->account(), acc);
433 QCOMPARE(textObserver->contactIdentifier(), contact);
434 QVERIFY(textObserver->textChats().isEmpty());
435 textObservers.append(textObserver);
436 QCOMPARE(ourObservers().size(), numRegisteredObservers);
437
438 if (i == 0 && j == 0) {
439 numRegisteredObservers = 3;
440 }
441
442 // on first run the following code should register an observer for incoming/outgoing
443 // calls, on consecutive runs it should use the already registered observer for
444 // incoming/outgoing calls
445 SimpleCallObserverPtr callObserver = SimpleCallObserver::create(acc, contact);
446 QCOMPARE(callObserver->account(), acc);
447 QCOMPARE(callObserver->contactIdentifier(), contact);
448 QCOMPARE(callObserver->direction(), SimpleCallObserver::CallDirectionBoth);
449 QVERIFY(callObserver->streamedMediaCalls().isEmpty());
450 callObservers.append(callObserver);
451 QCOMPARE(ourObservers().size(), numRegisteredObservers);
452
453 if (i == 0 && j == 0) {
454 numRegisteredObservers = 4;
455 }
456
457 // on first run the following code should register an observer for incoming calls,
458 // on consecutive runs it should use the already registered observer for incoming calls
459 callObserver = SimpleCallObserver::create(acc, contact,
460 SimpleCallObserver::CallDirectionIncoming);
461 QCOMPARE(callObserver->account(), acc);
462 QCOMPARE(callObserver->contactIdentifier(), contact);
463 QCOMPARE(callObserver->direction(), SimpleCallObserver::CallDirectionIncoming);
464 QVERIFY(callObserver->streamedMediaCalls().isEmpty());
465 callObservers.append(callObserver);
466 QCOMPARE(ourObservers().size(), numRegisteredObservers);
467 }
468 }
469
470 // deleting all SimpleObserver instances (text chat room) should unregister 1 observer
471 observers.clear();
472 QCOMPARE(ourObservers().size(), 3);
473 // deleting all SimpleTextObserver instances should unregister 1 observer
474 textObservers.clear();
475 QCOMPARE(ourObservers().size(), 2);
476 // deleting all SimpleCallObserver instances should unregister 2 observers
477 callObservers.clear();
478 QVERIFY(ourObservers().isEmpty());
479 }
480
testCrossTalk()481 void TestSimpleObserver::testCrossTalk()
482 {
483 SimpleObserverPtr observers[2];
484 SimpleTextObserverPtr textObservers[2];
485 SimpleTextObserverPtr textObserversNoContact[2];
486 SimpleCallObserverPtr callObservers[2];
487 SimpleCallObserverPtr callObserversNoContact[2];
488
489 for (int i = 0; i < 2; ++i) {
490 AccountPtr acc = mAccounts[i];
491 observers[i] = SimpleObserver::create(acc,
492 ChannelClassSpec::textChat(), mContacts[i]);
493 QVERIFY(connect(observers[i].data(), SIGNAL(newChannels(QList<Tp::ChannelPtr>)),
494 SLOT(onObserverNewChannels(QList<Tp::ChannelPtr>))));
495 QVERIFY(connect(observers[i].data(),
496 SIGNAL(channelInvalidated(Tp::ChannelPtr,QString,QString)),
497 SLOT(onObserverChannelInvalidated(Tp::ChannelPtr,QString,QString))));
498
499 // SimpleTextObserver::messageSent/Received is already tested in contact-messenger test
500 textObservers[i] = SimpleTextObserver::create(acc, mContacts[i]);
501 textObserversNoContact[i] = SimpleTextObserver::create(acc);
502
503 callObservers[i] = SimpleCallObserver::create(acc, mContacts[i]);
504 QVERIFY(connect(callObservers[i].data(), SIGNAL(streamedMediaCallStarted(Tp::StreamedMediaChannelPtr)),
505 SLOT(onObserverStreamedMediaCallStarted(Tp::StreamedMediaChannelPtr))));
506 QVERIFY(connect(callObservers[i].data(), SIGNAL(streamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)),
507 SLOT(onObserverStreamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString))));
508 callObserversNoContact[i] = SimpleCallObserver::create(acc);
509 }
510
511 QMap<QString, QString> ourObserversMap = ourObservers();
512 QMap<QString, QString>::const_iterator it = ourObserversMap.constBegin();
513 QMap<QString, QString>::const_iterator end = ourObserversMap.constEnd();
514 for (; it != end; ++it) {
515 ClientObserverInterface *observerIface = new ClientObserverInterface(
516 it.key(), it.value(), this);
517
518 ChannelClassList observerFilter;
519 if (!waitForProperty(observerIface->requestPropertyObserverChannelFilter(),
520 &observerFilter)) {
521 continue;
522 }
523
524 for (int i = 0; i < 2; ++i) {
525 Q_FOREACH (const ChannelClassSpec &spec, observerFilter) {
526 // only call ObserveChannels for text chat channels on observers that support text
527 // chat
528 if (spec.isSubsetOf(ChannelClassSpec::textChat())) {
529 ChannelDetails textChan = {
530 QDBusObjectPath(mTextChans[i]->objectPath()),
531 mTextChans[i]->immutableProperties()
532 };
533 observerIface->ObserveChannels(
534 QDBusObjectPath(mAccounts[i]->objectPath()),
535 QDBusObjectPath(mTextChans[i]->connection()->objectPath()),
536 ChannelDetailsList() << textChan,
537 QDBusObjectPath(QLatin1String("/")),
538 Tp::ObjectPathList(),
539 QVariantMap());
540 break;
541 }
542 }
543
544 Q_FOREACH (const ChannelClassSpec &spec, observerFilter) {
545 // only call ObserveChannels for SM channels on observers that support SM channels
546 if (spec.isSubsetOf(ChannelClassSpec::streamedMediaCall())) {
547 ChannelDetails smChan = {
548 QDBusObjectPath(mSMChans[i]->objectPath()),
549 mSMChans[i]->immutableProperties()
550 };
551 observerIface->ObserveChannels(
552 QDBusObjectPath(mAccounts[i]->objectPath()),
553 QDBusObjectPath(mSMChans[i]->connection()->objectPath()),
554 ChannelDetailsList() << smChan,
555 QDBusObjectPath(QLatin1String("/")),
556 Tp::ObjectPathList(),
557 QVariantMap());
558 break;
559 }
560 }
561 }
562 }
563
564 // due to QtDBus limitation, we cannot wait for ObserveChannels to finish properly before
565 // proceeding, so we have to wait till all observers receive the channels
566 while (observers[0]->channels().isEmpty() ||
567 observers[1]->channels().isEmpty() ||
568 textObservers[0]->textChats().isEmpty() ||
569 textObservers[1]->textChats().isEmpty() ||
570 textObserversNoContact[0]->textChats().isEmpty() ||
571 textObserversNoContact[1]->textChats().isEmpty() ||
572 callObservers[0]->streamedMediaCalls().isEmpty() ||
573 callObservers[1]->streamedMediaCalls().isEmpty() ||
574 callObserversNoContact[0]->streamedMediaCalls().isEmpty() ||
575 callObserversNoContact[1]->streamedMediaCalls().isEmpty()) {
576 mLoop->processEvents();
577 }
578
579 QCOMPARE(mChannelsCount, 2);
580 QCOMPARE(mSMChannelsCount, 2);
581
582 QCOMPARE(observers[0]->channels().size(), 1);
583 QCOMPARE(textObservers[0]->textChats().size(), 1);
584 QCOMPARE(textObserversNoContact[0]->textChats().size(), 1);
585 QCOMPARE(callObservers[0]->streamedMediaCalls().size(), 1);
586 QCOMPARE(callObserversNoContact[0]->streamedMediaCalls().size(), 1);
587 QCOMPARE(observers[1]->channels().size(), 1);
588 QCOMPARE(textObservers[1]->textChats().size(), 1);
589 QCOMPARE(textObserversNoContact[1]->textChats().size(), 1);
590 QCOMPARE(callObservers[1]->streamedMediaCalls().size(), 1);
591 QCOMPARE(callObserversNoContact[1]->streamedMediaCalls().size(), 1);
592
593 QVERIFY(textObservers[0]->textChats() != textObservers[1]->textChats());
594 QVERIFY(textObserversNoContact[0]->textChats() != textObserversNoContact[1]->textChats());
595 QCOMPARE(textObservers[0]->textChats(), textObserversNoContact[0]->textChats());
596 QCOMPARE(textObservers[1]->textChats(), textObserversNoContact[1]->textChats());
597
598 QVERIFY(callObservers[0]->streamedMediaCalls() != callObservers[1]->streamedMediaCalls());
599 QVERIFY(callObservers[0]->streamedMediaCalls() != callObserversNoContact[1]->streamedMediaCalls());
600 QCOMPARE(callObservers[0]->streamedMediaCalls(), callObserversNoContact[0]->streamedMediaCalls());
601 QCOMPARE(callObservers[1]->streamedMediaCalls(), callObserversNoContact[1]->streamedMediaCalls());
602
603 QCOMPARE(observers[0]->channels(), channels(textObservers[0]->textChats()));
604 QVERIFY(observers[0]->channels() != channels(textObservers[1]->textChats()));
605 QVERIFY(observers[0]->channels() != channels(callObservers[0]->streamedMediaCalls()));
606 QVERIFY(observers[0]->channels() != channels(callObservers[1]->streamedMediaCalls()));
607 QVERIFY(observers[1]->channels() != channels(textObservers[0]->textChats()));
608 QCOMPARE(observers[1]->channels(), channels(textObservers[1]->textChats()));
609 QVERIFY(observers[1]->channels() != channels(callObservers[0]->streamedMediaCalls()));
610 QVERIFY(observers[1]->channels() != channels(callObservers[1]->streamedMediaCalls()));
611
612 QVERIFY(channels(callObservers[0]->streamedMediaCalls()) != channels(textObservers[0]->textChats()));
613 QVERIFY(channels(callObservers[0]->streamedMediaCalls()) != channels(textObservers[1]->textChats()));
614 QVERIFY(channels(callObservers[1]->streamedMediaCalls()) != channels(textObservers[0]->textChats()));
615 QVERIFY(channels(callObservers[1]->streamedMediaCalls()) != channels(textObservers[1]->textChats()));
616
617 QCOMPARE(observers[0]->channels().first()->objectPath(), mTextChans[0]->objectPath());
618 QCOMPARE(observers[1]->channels().first()->objectPath(), mTextChans[1]->objectPath());
619 QCOMPARE(textObservers[0]->textChats().first()->objectPath(), mTextChans[0]->objectPath());
620 QCOMPARE(textObservers[1]->textChats().first()->objectPath(), mTextChans[1]->objectPath());
621 QCOMPARE(textObserversNoContact[0]->textChats().first()->objectPath(), mTextChans[0]->objectPath());
622 QCOMPARE(textObserversNoContact[1]->textChats().first()->objectPath(), mTextChans[1]->objectPath());
623 QCOMPARE(callObservers[0]->streamedMediaCalls().first()->objectPath(), mSMChans[0]->objectPath());
624 QCOMPARE(callObservers[1]->streamedMediaCalls().first()->objectPath(), mSMChans[1]->objectPath());
625
626 // invalidate channels
627 for (int i = 0; i < 2; ++i) {
628 if (mMessagesChanServices[i] != 0) {
629 g_object_unref(mMessagesChanServices[i]);
630 mMessagesChanServices[i] = 0;
631 }
632
633 if (mCallableChanServices[i] != 0) {
634 g_object_unref(mCallableChanServices[i]);
635 mCallableChanServices[i] = 0;
636 }
637 }
638
639 while (!observers[0]->channels().isEmpty() ||
640 !observers[1]->channels().isEmpty() ||
641 !textObservers[0]->textChats().isEmpty() ||
642 !textObservers[1]->textChats().isEmpty() ||
643 !textObserversNoContact[0]->textChats().isEmpty() ||
644 !textObserversNoContact[1]->textChats().isEmpty() ||
645 !callObservers[0]->streamedMediaCalls().isEmpty() ||
646 !callObservers[1]->streamedMediaCalls().isEmpty() ||
647 !callObserversNoContact[0]->streamedMediaCalls().isEmpty() ||
648 !callObserversNoContact[1]->streamedMediaCalls().isEmpty()) {
649 mLoop->processEvents();
650 }
651
652 QCOMPARE(mChannelsCount, 0);
653 QCOMPARE(mSMChannelsCount, 0);
654 }
655
cleanup()656 void TestSimpleObserver::cleanup()
657 {
658 cleanupImpl();
659 }
660
cleanupTestCase()661 void TestSimpleObserver::cleanupTestCase()
662 {
663 for (int i = 0; i < 2; ++i) {
664 if (!mConns[i].conn) {
665 continue;
666 }
667
668 if (mConns[i].conn->requestedFeatures().contains(Connection::FeatureCore)) {
669 QVERIFY(mConns[i].connService != NULL);
670
671 if (TP_BASE_CONNECTION(mConns[i].connService)->status != TP_CONNECTION_STATUS_DISCONNECTED) {
672 tp_base_connection_change_status(TP_BASE_CONNECTION(mConns[i].connService),
673 TP_CONNECTION_STATUS_DISCONNECTED,
674 TP_CONNECTION_STATUS_REASON_REQUESTED);
675 }
676
677 while (mConns[i].conn->isValid()) {
678 mLoop->processEvents();
679 }
680
681 }
682 mConns[i].conn.reset();
683
684 mTextChans[i].reset();
685 mSMChans[i].reset();
686
687 if (mMessagesChanServices[i] != 0) {
688 g_object_unref(mMessagesChanServices[i]);
689 mMessagesChanServices[i] = 0;
690 }
691
692 if (mCallableChanServices[i] != 0) {
693 g_object_unref(mCallableChanServices[i]);
694 mCallableChanServices[i] = 0;
695 }
696
697 if (mConns[i].connService != 0) {
698 mConns[i].baseConnService = 0;
699 g_object_unref(mConns[i].connService);
700 mConns[i].connService = 0;
701 }
702 }
703
704 cleanupTestCaseImpl();
705 }
706
ourObservers()707 QMap<QString, QString> TestSimpleObserver::ourObservers()
708 {
709 QStringList registeredNames =
710 QDBusConnection::sessionBus().interface()->registeredServiceNames();
711 QMap<QString, QString> observers;
712
713 Q_FOREACH (QString name, registeredNames) {
714 if (!name.startsWith(QLatin1String("org.freedesktop.Telepathy.Client.TpQtSO"))) {
715 continue;
716 }
717
718 if (QDBusConnection::sessionBus().interface()->serviceOwner(name).value() !=
719 QDBusConnection::sessionBus().baseService()) {
720 continue;
721 }
722
723 QString path = QLatin1Char('/') + name;
724 path.replace(QLatin1Char('.'), QLatin1Char('/'));
725
726 ClientInterface client(name, path);
727 QStringList ifaces;
728 if (!waitForProperty(client.requestPropertyInterfaces(), &ifaces)) {
729 continue;
730 }
731
732 if (!ifaces.contains(TP_QT_IFACE_CLIENT_OBSERVER)) {
733 continue;
734 }
735
736 observers.insert(name, path);
737 }
738
739 return observers;
740 }
741
742 QTEST_MAIN(TestSimpleObserver)
743 #include "_gen/simple-observer.cpp.moc.hpp"
744