1 #include <QtCore/QDebug>
2 #include <QtCore/QTimer>
3
4 #include <QtDBus/QtDBus>
5
6 #include <QtTest/QtTest>
7
8 #define TP_QT_ENABLE_LOWLEVEL_API
9
10 #include <TelepathyQt/ChannelFactory>
11 #include <TelepathyQt/Connection>
12 #include <TelepathyQt/ConnectionLowlevel>
13 #include <TelepathyQt/Contact>
14 #include <TelepathyQt/ContactFactory>
15 #include <TelepathyQt/ContactManager>
16 #include <TelepathyQt/PendingContacts>
17 #include <TelepathyQt/PendingReady>
18 #include <TelepathyQt/Debug>
19
20 #include <telepathy-glib/debug.h>
21
22 #include <tests/lib/glib/contactlist2/conn.h>
23 #include <tests/lib/test.h>
24
25 using namespace Tp;
26
27 class TestConnRosterGroups : public Test
28 {
29 Q_OBJECT
30
31 public:
TestConnRosterGroups(QObject * parent=0)32 TestConnRosterGroups(QObject *parent = 0)
33 : Test(parent), mConnService(0),
34 mContactsAddedToGroup(0), mContactsRemovedFromGroup(0)
35 { }
36
37 private:
38 void causeCongestion(const ConnectionPtr &conn, const ContactPtr &contact);
39
40 protected Q_SLOTS:
41 void onGroupAdded(const QString &group);
42 void onGroupRemoved(const QString &group);
43 void onContactAddedToGroup(const QString &group);
44 void onContactRemovedFromGroup(const QString &group);
45 void expectConnInvalidated();
46 void expectContact(Tp::PendingOperation*);
47 void exitOnStateSuccess(Tp::ContactListState);
48
49 private Q_SLOTS:
50 void initTestCase();
51 void init();
52
53 void testGroupsAfterStateChange();
54 void testIntrospectAfterStateChange();
55 void testRosterGroups();
56 void testNotADeathTrap();
57
58 void cleanup();
59 void cleanupTestCase();
60
61 private:
62 QString mConnName, mConnPath;
63 ExampleContactListConnection *mConnService;
64 ConnectionPtr mConn;
65 ContactPtr mContact;
66
67 QString mGroupAdded;
68 QString mGroupRemoved;
69 int mContactsAddedToGroup;
70 int mContactsRemovedFromGroup;
71 bool mConnInvalidated;
72 };
73
causeCongestion(const ConnectionPtr & conn,const ContactPtr & contact)74 void TestConnRosterGroups::causeCongestion(const ConnectionPtr &conn, const ContactPtr &contact)
75 {
76 // Cause some congestion in the roster events queue so we can check that it doesn't cause
77 // inconsistent event reordering
78 for (int i = 0; i < 5; i++) {
79 QString name = QString(QLatin1String("Rush%1")).arg(i);
80 conn->contactManager()->addGroup(name);
81 conn->contactManager()->addContactsToGroup(name, QList<ContactPtr>() << contact);
82 contact->requestPresenceSubscription();
83 contact->removePresenceSubscription();
84 conn->contactManager()->removeGroup(name);
85 }
86 }
87
onGroupAdded(const QString & group)88 void TestConnRosterGroups::onGroupAdded(const QString &group)
89 {
90 if (group.startsWith(QLatin1String("Rush"))) {
91 return;
92 }
93
94 mGroupAdded = group;
95 }
96
onGroupRemoved(const QString & group)97 void TestConnRosterGroups::onGroupRemoved(const QString &group)
98 {
99 if (group.startsWith(QLatin1String("Rush"))) {
100 return;
101 }
102
103 mGroupRemoved = group;
104 }
105
onContactAddedToGroup(const QString & group)106 void TestConnRosterGroups::onContactAddedToGroup(const QString &group)
107 {
108 if (group.startsWith(QLatin1String("Rush"))) {
109 return;
110 }
111
112 mContactsAddedToGroup++;
113 }
114
onContactRemovedFromGroup(const QString & group)115 void TestConnRosterGroups::onContactRemovedFromGroup(const QString &group)
116 {
117 if (group.startsWith(QLatin1String("Rush"))) {
118 return;
119 }
120
121 mContactsRemovedFromGroup++;
122 }
123
expectConnInvalidated()124 void TestConnRosterGroups::expectConnInvalidated()
125 {
126 mConnInvalidated = true;
127 mLoop->exit(0);
128 }
129
expectContact(Tp::PendingOperation * op)130 void TestConnRosterGroups::expectContact(Tp::PendingOperation *op)
131 {
132 PendingContacts *contacts = qobject_cast<PendingContacts *>(op);
133 QVERIFY(contacts != 0);
134
135 QVERIFY(contacts->isValid());
136 QCOMPARE(contacts->contacts().length(), 1);
137
138 mContact = contacts->contacts()[0];
139
140 mLoop->exit(0);
141 }
142
exitOnStateSuccess(Tp::ContactListState state)143 void TestConnRosterGroups::exitOnStateSuccess(Tp::ContactListState state)
144 {
145 qDebug() << "got contact list state" << state;
146
147 if (state == ContactListStateSuccess) {
148 mLoop->exit(0);
149 }
150 }
151
initTestCase()152 void TestConnRosterGroups::initTestCase()
153 {
154 initTestCaseImpl();
155
156 g_type_init();
157 g_set_prgname("conn-roster-groups");
158 tp_debug_set_flags("all");
159 dbus_g_bus_get(DBUS_BUS_STARTER, 0);
160 }
161
init()162 void TestConnRosterGroups::init()
163 {
164 gchar *name;
165 gchar *connPath;
166 GError *error = 0;
167
168 mConnService = EXAMPLE_CONTACT_LIST_CONNECTION(g_object_new(
169 EXAMPLE_TYPE_CONTACT_LIST_CONNECTION,
170 "account", "me@example.com",
171 "simulation-delay", 0,
172 "protocol", "example-contact-list",
173 NULL));
174 QVERIFY(mConnService != 0);
175 QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService),
176 "foo", &name, &connPath, &error));
177 QVERIFY(error == 0);
178
179 QVERIFY(name != 0);
180 QVERIFY(connPath != 0);
181
182 mConnName = QLatin1String(name);
183 mConnPath = QLatin1String(connPath);
184
185 g_free(name);
186 g_free(connPath);
187 initImpl();
188
189 mConnInvalidated = false;
190 }
191
testGroupsAfterStateChange()192 void TestConnRosterGroups::testGroupsAfterStateChange()
193 {
194 // Create a conn and make the roster groups related features ready
195 mConn = Connection::create(mConnName, mConnPath,
196 ChannelFactory::create(QDBusConnection::sessionBus()),
197 ContactFactory::create());
198
199 ContactManagerPtr contactManager = mConn->contactManager();
200
201 Features features = Features() << Connection::FeatureRoster << Connection::FeatureRosterGroups;
202 QVERIFY(connect(mConn->becomeReady(features),
203 SIGNAL(finished(Tp::PendingOperation*)),
204 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
205 QCOMPARE(mLoop->exec(), 0);
206 QCOMPARE(mConn->isReady(Connection::FeatureRoster), true);
207 QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true);
208
209 // Now start connecting it, and wait for the ContactManager state to turn to Success
210 QVERIFY(connect(contactManager.data(),
211 SIGNAL(stateChanged(Tp::ContactListState)),
212 SLOT(exitOnStateSuccess(Tp::ContactListState))));
213
214 mConn->lowlevel()->requestConnect();
215
216 QCOMPARE(mLoop->exec(), 0);
217 QCOMPARE(static_cast<uint>(contactManager->state()),
218 static_cast<uint>(ContactListStateSuccess));
219
220 // The conn should be valid and have the roster groups features ready when it emits Success
221 QVERIFY(mConn->isValid());
222 QCOMPARE(mConn->isReady(Connection::FeatureRoster), true);
223 QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true);
224
225 // We should have all the group data downloaded now, check for that
226 QStringList expectedGroups;
227 expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones")
228 << QLatin1String("Montreal");
229 expectedGroups.sort();
230 QStringList groups = contactManager->allKnownGroups();
231 groups.sort();
232 QCOMPARE(groups, expectedGroups);
233
234 // Cambridge
235 {
236 QStringList expectedContacts;
237 expectedContacts << QLatin1String("geraldine@example.com")
238 << QLatin1String("helen@example.com")
239 << QLatin1String("guillaume@example.com")
240 << QLatin1String("sjoerd@example.com");
241 expectedContacts.sort();
242 QStringList contacts;
243 Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Cambridge"))) {
244 contacts << contact->id();
245 }
246 contacts.sort();
247 QCOMPARE(contacts, expectedContacts);
248 }
249
250 // Francophones
251 {
252 QStringList expectedContacts;
253 expectedContacts << QLatin1String("olivier@example.com")
254 << QLatin1String("geraldine@example.com")
255 << QLatin1String("guillaume@example.com");
256 expectedContacts.sort();
257 QStringList contacts;
258 Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Francophones"))) {
259 contacts << contact->id();
260 }
261 contacts.sort();
262 QCOMPARE(contacts, expectedContacts);
263 }
264
265 // Montreal
266 {
267 QStringList expectedContacts;
268 expectedContacts << QLatin1String("olivier@example.com");
269 expectedContacts.sort();
270 QStringList contacts;
271 Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Montreal"))) {
272 contacts << contact->id();
273 }
274 contacts.sort();
275 QCOMPARE(contacts, expectedContacts);
276 }
277 }
278
testIntrospectAfterStateChange()279 void TestConnRosterGroups::testIntrospectAfterStateChange()
280 {
281 // Create a conn and make the roster feature ready
282 mConn = Connection::create(mConnName, mConnPath,
283 ChannelFactory::create(QDBusConnection::sessionBus()),
284 ContactFactory::create());
285
286 ContactManagerPtr contactManager = mConn->contactManager();
287
288 Features features = Features() << Connection::FeatureRoster;
289 QVERIFY(connect(mConn->becomeReady(features),
290 SIGNAL(finished(Tp::PendingOperation*)),
291 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
292 QCOMPARE(mLoop->exec(), 0);
293 QCOMPARE(mConn->isReady(Connection::FeatureRoster), true);
294 QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), false);
295
296 // Now start connecting it, and wait for the ContactManager state to turn to Success
297 QVERIFY(connect(contactManager.data(),
298 SIGNAL(stateChanged(Tp::ContactListState)),
299 SLOT(exitOnStateSuccess(Tp::ContactListState))));
300
301 mConn->lowlevel()->requestConnect();
302
303 QCOMPARE(mLoop->exec(), 0);
304 QCOMPARE(static_cast<uint>(contactManager->state()),
305 static_cast<uint>(ContactListStateSuccess));
306
307 // The conn should be valid and have the roster feature ready when it emits Success, but not
308 // RosterGroups because we didn't request it
309 QVERIFY(mConn->isValid());
310 QCOMPARE(mConn->isReady(Connection::FeatureRoster), true);
311 QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), false);
312
313 // We should have roster contacts now, but no groups
314 QVERIFY(!contactManager->allKnownContacts().isEmpty());
315 QVERIFY(contactManager->allKnownGroups().isEmpty());
316
317 // Make RosterGroups ready too
318 features = Features() << Connection::FeatureRosterGroups;
319 QVERIFY(connect(mConn->becomeReady(features),
320 SIGNAL(finished(Tp::PendingOperation*)),
321 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
322 QCOMPARE(mLoop->exec(), 0);
323 QCOMPARE(mConn->isReady(Connection::FeatureRoster), true);
324 QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true);
325
326 // We should still have the contacts, and the state should be success
327 QVERIFY(!contactManager->allKnownContacts().isEmpty());
328 QCOMPARE(static_cast<uint>(contactManager->state()),
329 static_cast<uint>(ContactListStateSuccess));
330
331 // We should have all the group data downloaded now, check for that
332 QStringList expectedGroups;
333 expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones")
334 << QLatin1String("Montreal");
335 expectedGroups.sort();
336 QStringList groups = contactManager->allKnownGroups();
337 groups.sort();
338 QCOMPARE(groups, expectedGroups);
339
340 // Cambridge
341 {
342 QStringList expectedContacts;
343 expectedContacts << QLatin1String("geraldine@example.com")
344 << QLatin1String("helen@example.com")
345 << QLatin1String("guillaume@example.com")
346 << QLatin1String("sjoerd@example.com");
347 expectedContacts.sort();
348 QStringList contacts;
349 Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Cambridge"))) {
350 contacts << contact->id();
351 }
352 contacts.sort();
353 QCOMPARE(contacts, expectedContacts);
354 }
355 }
356
testRosterGroups()357 void TestConnRosterGroups::testRosterGroups()
358 {
359 mConn = Connection::create(mConnName, mConnPath,
360 ChannelFactory::create(QDBusConnection::sessionBus()),
361 ContactFactory::create());
362
363 QVERIFY(connect(mConn->lowlevel()->requestConnect(),
364 SIGNAL(finished(Tp::PendingOperation*)),
365 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
366 QCOMPARE(mLoop->exec(), 0);
367 QCOMPARE(mConn->isReady(), true);
368 QCOMPARE(mConn->status(), ConnectionStatusConnected);
369
370 Features features = Features() << Connection::FeatureRoster << Connection::FeatureRosterGroups
371 << Connection::FeatureSelfContact;
372 QVERIFY(connect(mConn->becomeReady(features),
373 SIGNAL(finished(Tp::PendingOperation*)),
374 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
375 QCOMPARE(mLoop->exec(), 0);
376 QCOMPARE(mConn->isReady(features), true);
377
378 QCOMPARE(static_cast<uint>(mConn->contactManager()->state()),
379 static_cast<uint>(ContactListStateSuccess));
380
381 ContactManagerPtr contactManager = mConn->contactManager();
382
383 QStringList expectedGroups;
384 expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones")
385 << QLatin1String("Montreal");
386 expectedGroups.sort();
387 QStringList groups = contactManager->allKnownGroups();
388 groups.sort();
389 QCOMPARE(groups, expectedGroups);
390
391 QString group(QLatin1String("foo"));
392 QVERIFY(contactManager->groupContacts(group).isEmpty());
393
394 causeCongestion(mConn, mConn->selfContact());
395
396 // add group foo
397 QVERIFY(connect(contactManager.data(),
398 SIGNAL(groupAdded(const QString&)),
399 SLOT(onGroupAdded(const QString&))));
400
401 causeCongestion(mConn, mConn->selfContact());
402
403 QVERIFY(connect(contactManager->addGroup(group),
404 SIGNAL(finished(Tp::PendingOperation*)),
405 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
406 QCOMPARE(mLoop->exec(), 0);
407 QVERIFY(!mGroupAdded.isEmpty());
408 QCOMPARE(mGroupAdded, group);
409
410 expectedGroups << group;
411 expectedGroups.sort();
412 groups = contactManager->allKnownGroups();
413 groups.sort();
414 QCOMPARE(groups, expectedGroups);
415
416 causeCongestion(mConn, mConn->selfContact());
417
418 // add Montreal contacts to group foo
419 Contacts contacts = contactManager->groupContacts(QLatin1String("Montreal"));
420 Q_FOREACH (const ContactPtr &contact, contacts) {
421 QVERIFY(connect(contact.data(),
422 SIGNAL(addedToGroup(const QString&)),
423 SLOT(onContactAddedToGroup(const QString&))));
424 }
425
426 causeCongestion(mConn, mConn->selfContact());
427
428 QVERIFY(connect(contactManager->addContactsToGroup(group, contacts.toList()),
429 SIGNAL(finished(Tp::PendingOperation*)),
430 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
431 QCOMPARE(mLoop->exec(), 0);
432 QCOMPARE(mContactsAddedToGroup, contacts.size());
433 Q_FOREACH (const ContactPtr &contact, contacts) {
434 QVERIFY(contact->groups().contains(group));
435 }
436
437 causeCongestion(mConn, mConn->selfContact());
438
439 // remove all contacts from group foo
440 contacts = contactManager->groupContacts(group);
441 Q_FOREACH (const ContactPtr &contact, contacts) {
442 QVERIFY(connect(contact.data(),
443 SIGNAL(removedFromGroup(const QString&)),
444 SLOT(onContactRemovedFromGroup(const QString&))));
445 }
446
447 causeCongestion(mConn, mConn->selfContact());
448
449 QVERIFY(connect(contactManager->removeContactsFromGroup(group, contacts.toList()),
450 SIGNAL(finished(Tp::PendingOperation*)),
451 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
452 QCOMPARE(mLoop->exec(), 0);
453 QCOMPARE(mContactsRemovedFromGroup, contacts.size());
454 Q_FOREACH (const ContactPtr &contact, contacts) {
455 QVERIFY(!contact->groups().contains(group));
456 }
457
458 causeCongestion(mConn, mConn->selfContact());
459
460 // remove group foo
461 QVERIFY(connect(contactManager.data(),
462 SIGNAL(groupRemoved(const QString&)),
463 SLOT(onGroupRemoved(const QString&))));
464
465 causeCongestion(mConn, mConn->selfContact());
466
467 QVERIFY(connect(contactManager->removeGroup(group),
468 SIGNAL(finished(Tp::PendingOperation*)),
469 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
470 QCOMPARE(mLoop->exec(), 0);
471 QVERIFY(!mGroupRemoved.isEmpty());
472 QCOMPARE(mGroupRemoved, group);
473
474 expectedGroups.removeOne(group);
475 expectedGroups.sort();
476 groups = contactManager->allKnownGroups();
477 groups.sort();
478 QCOMPARE(groups, expectedGroups);
479 }
480
481 /**
482 * Verify that ContactManager isn't a death-trap.
483 *
484 * Background: Connection::contactManager() used to unpredictably waver between NULL and the real
485 * manager when the connection was in the process of being disconnected / otherwise invalidated,
486 * which led to a great many segfaults, which was especially unfortunate considering the
487 * ContactManager methods didn't do much any checks at all.
488 */
testNotADeathTrap()489 void TestConnRosterGroups::testNotADeathTrap()
490 {
491 mConn = Connection::create(mConnName, mConnPath,
492 ChannelFactory::create(QDBusConnection::sessionBus()),
493 ContactFactory::create());
494 QCOMPARE(mConn->isReady(), false);
495
496 // Check that the contact manager doesn't crash, but returns an error (because the conn isn't
497 // ready)
498 QVERIFY(!mConn->contactManager().isNull());
499 QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()),
500 SIGNAL(finished(Tp::PendingOperation*)),
501 SLOT(expectFailure(Tp::PendingOperation*))));
502 QCOMPARE(mLoop->exec(), 0);
503
504 QVERIFY(connect(mConn->lowlevel()->requestConnect(),
505 SIGNAL(finished(Tp::PendingOperation*)),
506 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
507 QCOMPARE(mLoop->exec(), 0);
508 QCOMPARE(mConn->isReady(), true);
509 QCOMPARE(mConn->status(), ConnectionStatusConnected);
510
511 // As the conn is now ready, the contact building functions shouldn't return an error now
512 QVERIFY(!mConn->contactManager().isNull());
513
514 QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()),
515 SIGNAL(finished(Tp::PendingOperation*)),
516 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
517 QCOMPARE(mLoop->exec(), 0);
518
519 QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()),
520 SIGNAL(finished(Tp::PendingOperation*)),
521 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
522 QCOMPARE(mLoop->exec(), 0);
523
524 QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList<ContactPtr>(),
525 Features()),
526 SIGNAL(finished(Tp::PendingOperation*)),
527 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
528 QCOMPARE(mLoop->exec(), 0);
529
530 // In fact, let's build a contact for future use
531 QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(
532 QStringList() << QLatin1String("friendorfoe@example.com")),
533 SIGNAL(finished(Tp::PendingOperation*)),
534 SLOT(expectContact(Tp::PendingOperation*))));
535 QCOMPARE(mLoop->exec(), 0);
536 QVERIFY(mContact->id() == QLatin1String("friendorfoe@example.com"));
537
538 // Roster operations SHOULD still fail though, as FeatureRoster isn't ready
539 QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription(
540 QList<ContactPtr>() << mContact,
541 QLatin1String("I just want to see you fail")),
542 SIGNAL(finished(Tp::PendingOperation*)),
543 SLOT(expectFailure(Tp::PendingOperation*))));
544 QCOMPARE(mLoop->exec(), 0);
545
546 QVERIFY(connect(mConn->contactManager()->removePresenceSubscription(
547 QList<ContactPtr>() << mContact,
548 QLatin1String("I just want to see you fail")),
549 SIGNAL(finished(Tp::PendingOperation*)),
550 SLOT(expectFailure(Tp::PendingOperation*))));
551 QCOMPARE(mLoop->exec(), 0);
552
553 QVERIFY(connect(mConn->contactManager()->authorizePresencePublication(
554 QList<ContactPtr>() << mContact,
555 QLatin1String("I just want to see you fail")),
556 SIGNAL(finished(Tp::PendingOperation*)),
557 SLOT(expectFailure(Tp::PendingOperation*))));
558 QCOMPARE(mLoop->exec(), 0);
559
560 QVERIFY(connect(mConn->contactManager()->removePresencePublication(
561 QList<ContactPtr>() << mContact,
562 QLatin1String("I just want to see you fail")),
563 SIGNAL(finished(Tp::PendingOperation*)),
564 SLOT(expectFailure(Tp::PendingOperation*))));
565 QCOMPARE(mLoop->exec(), 0);
566
567 // Now, make Roster ready
568 Features features = Features() << Connection::FeatureRoster;
569 QVERIFY(connect(mConn->becomeReady(features),
570 SIGNAL(finished(Tp::PendingOperation*)),
571 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
572 QCOMPARE(mLoop->exec(), 0);
573 QCOMPARE(mConn->isReady(features), true);
574
575 causeCongestion(mConn, mContact);
576
577 // The roster functions should work now
578 QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription(
579 QList<ContactPtr>() << mContact,
580 QLatin1String("Please don't fail")),
581 SIGNAL(finished(Tp::PendingOperation*)),
582 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
583 QCOMPARE(mLoop->exec(), 0);
584
585 QVERIFY(mContact->subscriptionState() != Contact::PresenceStateNo);
586
587 causeCongestion(mConn, mContact);
588
589 QVERIFY(connect(mConn->contactManager()->removePresenceSubscription(
590 QList<ContactPtr>() << mContact,
591 QLatin1String("Please don't fail")),
592 SIGNAL(finished(Tp::PendingOperation*)),
593 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
594 QCOMPARE(mLoop->exec(), 0);
595
596 QCOMPARE(mContact->subscriptionState(), Contact::PresenceStateNo);
597
598 causeCongestion(mConn, mContact);
599
600 QVERIFY(connect(mConn->contactManager()->authorizePresencePublication(
601 QList<ContactPtr>() << mContact,
602 QLatin1String("Please don't fail")),
603 SIGNAL(finished(Tp::PendingOperation*)),
604 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
605 QCOMPARE(mLoop->exec(), 0);
606
607 causeCongestion(mConn, mContact);
608
609 QVERIFY(connect(mConn->contactManager()->removePresencePublication(
610 QList<ContactPtr>() << mContact,
611 QLatin1String("Please don't fail")),
612 SIGNAL(finished(Tp::PendingOperation*)),
613 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
614 QCOMPARE(mLoop->exec(), 0);
615
616 // ... but still not the RosterGroup ones
617 QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("Those who failed")),
618 SIGNAL(finished(Tp::PendingOperation*)),
619 SLOT(expectFailure(Tp::PendingOperation*))));
620 QCOMPARE(mLoop->exec(), 0);
621
622 QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("Those who failed")),
623 SIGNAL(finished(Tp::PendingOperation*)),
624 SLOT(expectFailure(Tp::PendingOperation*))));
625 QCOMPARE(mLoop->exec(), 0);
626
627 QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("Those who failed"),
628 QList<ContactPtr>() << mContact),
629 SIGNAL(finished(Tp::PendingOperation*)),
630 SLOT(expectFailure(Tp::PendingOperation*))));
631 QCOMPARE(mLoop->exec(), 0);
632
633 QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("Those who failed"),
634 QList<ContactPtr>() << mContact),
635 SIGNAL(finished(Tp::PendingOperation*)),
636 SLOT(expectFailure(Tp::PendingOperation*))));
637 QCOMPARE(mLoop->exec(), 0);
638
639 // Make RosterGroups ready too
640 features = Features() << Connection::FeatureRosterGroups;
641 QVERIFY(connect(mConn->becomeReady(features),
642 SIGNAL(finished(Tp::PendingOperation*)),
643 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
644 QCOMPARE(mLoop->exec(), 0);
645 QCOMPARE(mConn->isReady(features), true);
646
647 // Now that Core, Roster and RosterGroups are all ready, everything should work
648 QVERIFY(!mConn->contactManager().isNull());
649
650 QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()),
651 SIGNAL(finished(Tp::PendingOperation*)),
652 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
653 QCOMPARE(mLoop->exec(), 0);
654
655 QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()),
656 SIGNAL(finished(Tp::PendingOperation*)),
657 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
658 QCOMPARE(mLoop->exec(), 0);
659
660 QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList<ContactPtr>(),
661 Features()),
662 SIGNAL(finished(Tp::PendingOperation*)),
663 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
664 QCOMPARE(mLoop->exec(), 0);
665
666 causeCongestion(mConn, mContact);
667
668 QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription(
669 QList<ContactPtr>() << mContact,
670 QLatin1String("Please don't fail")),
671 SIGNAL(finished(Tp::PendingOperation*)),
672 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
673 QCOMPARE(mLoop->exec(), 0);
674
675 QVERIFY(mContact->subscriptionState() != Contact::PresenceStateNo);
676
677 causeCongestion(mConn, mContact);
678
679 QVERIFY(connect(mConn->contactManager()->removePresenceSubscription(
680 QList<ContactPtr>() << mContact,
681 QLatin1String("Please don't fail")),
682 SIGNAL(finished(Tp::PendingOperation*)),
683 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
684 QCOMPARE(mLoop->exec(), 0);
685
686 QCOMPARE(mContact->subscriptionState(), Contact::PresenceStateNo);
687
688 QVERIFY(connect(mConn->contactManager()->authorizePresencePublication(
689 QList<ContactPtr>() << mContact,
690 QLatin1String("Please don't fail")),
691 SIGNAL(finished(Tp::PendingOperation*)),
692 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
693 QCOMPARE(mLoop->exec(), 0);
694
695 QVERIFY(connect(mConn->contactManager()->removePresencePublication(
696 QList<ContactPtr>() << mContact,
697 QLatin1String("Please don't fail")),
698 SIGNAL(finished(Tp::PendingOperation*)),
699 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
700 QCOMPARE(mLoop->exec(), 0);
701
702 causeCongestion(mConn, mContact);
703
704 QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("My successful entourage")),
705 SIGNAL(finished(Tp::PendingOperation*)),
706 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
707 QCOMPARE(mLoop->exec(), 0);
708
709 QVERIFY(mConn->contactManager()->allKnownGroups().contains(QLatin1String("My successful entourage")));
710
711 causeCongestion(mConn, mContact);
712
713 QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("My successful entourage"),
714 QList<ContactPtr>() << mContact),
715 SIGNAL(finished(Tp::PendingOperation*)),
716 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
717 QCOMPARE(mLoop->exec(), 0);
718
719 QVERIFY(mConn->contactManager()->
720 groupContacts(QLatin1String("My successful entourage")).contains(mContact));
721
722 causeCongestion(mConn, mContact);
723
724 QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("My successful entourage"),
725 QList<ContactPtr>() << mContact),
726 SIGNAL(finished(Tp::PendingOperation*)),
727 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
728 QCOMPARE(mLoop->exec(), 0);
729
730 QVERIFY(!mConn->contactManager()->
731 groupContacts(QLatin1String("My successful entourage")).contains(mContact));
732
733 causeCongestion(mConn, mContact);
734
735 QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("My successful entourage")),
736 SIGNAL(finished(Tp::PendingOperation*)),
737 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
738 QCOMPARE(mLoop->exec(), 0);
739
740 QVERIFY(!mConn->contactManager()->allKnownGroups().contains(QLatin1String("My successful entourage")));
741
742 // Now, invalidate the connection by disconnecting it
743 QVERIFY(connect(mConn.data(),
744 SIGNAL(invalidated(Tp::DBusProxy *,
745 const QString &, const QString &)),
746 SLOT(expectConnInvalidated())));
747 mConn->lowlevel()->requestDisconnect();
748
749 // Check that contactManager doesn't go NULL in the process of the connection going invalidated
750 do {
751 QVERIFY(!mConn->contactManager().isNull());
752 mLoop->processEvents();
753 } while (!mConnInvalidated);
754
755 QVERIFY(!mConn->isValid());
756 QCOMPARE(mConn->status(), ConnectionStatusDisconnected);
757
758 // Now that the conn is invalidated NOTHING should work anymore
759 QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()),
760 SIGNAL(finished(Tp::PendingOperation*)),
761 SLOT(expectFailure(Tp::PendingOperation*))));
762 QCOMPARE(mLoop->exec(), 0);
763
764 QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()),
765 SIGNAL(finished(Tp::PendingOperation*)),
766 SLOT(expectFailure(Tp::PendingOperation*))));
767 QCOMPARE(mLoop->exec(), 0);
768
769 QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList<ContactPtr>(),
770 Features()),
771 SIGNAL(finished(Tp::PendingOperation*)),
772 SLOT(expectFailure(Tp::PendingOperation*))));
773 QCOMPARE(mLoop->exec(), 0);
774
775 QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription(QList<ContactPtr>(),
776 QLatin1String("You fail at life")),
777 SIGNAL(finished(Tp::PendingOperation*)),
778 SLOT(expectFailure(Tp::PendingOperation*))));
779 QCOMPARE(mLoop->exec(), 0);
780
781 QVERIFY(connect(mConn->contactManager()->removePresenceSubscription(QList<ContactPtr>(),
782 QLatin1String("You fail at life")),
783 SIGNAL(finished(Tp::PendingOperation*)),
784 SLOT(expectFailure(Tp::PendingOperation*))));
785 QCOMPARE(mLoop->exec(), 0);
786
787 QVERIFY(connect(mConn->contactManager()->authorizePresencePublication(QList<ContactPtr>(),
788 QLatin1String("You fail at life")),
789 SIGNAL(finished(Tp::PendingOperation*)),
790 SLOT(expectFailure(Tp::PendingOperation*))));
791 QCOMPARE(mLoop->exec(), 0);
792
793 QVERIFY(connect(mConn->contactManager()->removePresencePublication(QList<ContactPtr>(),
794 QLatin1String("You fail at life")),
795 SIGNAL(finished(Tp::PendingOperation*)),
796 SLOT(expectFailure(Tp::PendingOperation*))));
797 QCOMPARE(mLoop->exec(), 0);
798
799 QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("Future failures")),
800 SIGNAL(finished(Tp::PendingOperation*)),
801 SLOT(expectFailure(Tp::PendingOperation*))));
802 QCOMPARE(mLoop->exec(), 0);
803
804 QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("Future failures")),
805 SIGNAL(finished(Tp::PendingOperation*)),
806 SLOT(expectFailure(Tp::PendingOperation*))));
807 QCOMPARE(mLoop->exec(), 0);
808
809 QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("Future failures"),
810 QList<ContactPtr>() << mContact),
811 SIGNAL(finished(Tp::PendingOperation*)),
812 SLOT(expectFailure(Tp::PendingOperation*))));
813 QCOMPARE(mLoop->exec(), 0);
814
815 QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("Future failures"),
816 QList<ContactPtr>() << mContact),
817 SIGNAL(finished(Tp::PendingOperation*)),
818 SLOT(expectFailure(Tp::PendingOperation*))));
819 QCOMPARE(mLoop->exec(), 0);
820 }
821
cleanup()822 void TestConnRosterGroups::cleanup()
823 {
824 mContact.reset();
825
826 if (mConn && mConn->requestedFeatures().contains(Connection::FeatureCore)) {
827 QVERIFY(mConnService != NULL);
828
829 if (TP_BASE_CONNECTION(mConnService)->status != TP_CONNECTION_STATUS_DISCONNECTED) {
830 tp_base_connection_change_status(TP_BASE_CONNECTION(mConnService),
831 TP_CONNECTION_STATUS_DISCONNECTED,
832 TP_CONNECTION_STATUS_REASON_REQUESTED);
833 }
834
835 while (mConn->isValid()) {
836 mLoop->processEvents();
837 }
838
839 }
840 mConn.reset();
841
842 if (mConnService != 0) {
843 g_object_unref(mConnService);
844 mConnService = 0;
845 }
846
847 cleanupImpl();
848 }
849
cleanupTestCase()850 void TestConnRosterGroups::cleanupTestCase()
851 {
852 cleanupTestCaseImpl();
853 }
854
855 QTEST_MAIN(TestConnRosterGroups)
856 #include "_gen/conn-roster-groups.cpp.moc.hpp"
857