File indexing completed on 2024-12-22 05:00:55
0001 /* 0002 SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "../unifiedmailboxmanager.h" 0008 #include "../common.h" 0009 #include "../unifiedmailbox.h" 0010 0011 #include <KConfigGroup> 0012 #include <KSharedConfig> 0013 0014 #include <Akonadi/CollectionCreateJob> 0015 #include <Akonadi/CollectionDeleteJob> 0016 #include <Akonadi/CollectionFetchJob> 0017 #include <Akonadi/CollectionFetchScope> 0018 #include <Akonadi/CollectionModifyJob> 0019 #include <Akonadi/ItemCreateJob> 0020 #include <Akonadi/ItemDeleteJob> 0021 #include <Akonadi/ItemModifyJob> 0022 #include <Akonadi/ItemMoveJob> 0023 #include <Akonadi/SpecialCollectionAttribute> 0024 #include <akonadi/qtest_akonadi.h> 0025 0026 #include <QTest> 0027 0028 #include <chrono> 0029 #include <memory> 0030 0031 using namespace std::chrono; 0032 using namespace std::chrono_literals; 0033 0034 namespace 0035 { 0036 #define AKVERIFY_RET(statement, ret) \ 0037 do { \ 0038 if (!QTest::qVerify(static_cast<bool>(statement), #statement, "", __FILE__, __LINE__)) { \ 0039 return ret; \ 0040 } \ 0041 } while (false) 0042 0043 #define AKCOMPARE_RET(actual, expected, ret) \ 0044 do { \ 0045 if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) { \ 0046 return ret; \ 0047 } \ 0048 } while (false) 0049 0050 Akonadi::Collection collectionForId(qint64 id) 0051 { 0052 auto fetch = new Akonadi::CollectionFetchJob(Akonadi::Collection(id), Akonadi::CollectionFetchJob::Base); 0053 fetch->fetchScope().fetchAttribute<Akonadi::SpecialCollectionAttribute>(); 0054 AKVERIFY_RET(fetch->exec(), {}); 0055 const auto cols = fetch->collections(); 0056 AKCOMPARE_RET(cols.count(), 1, {}); 0057 return cols.first(); 0058 } 0059 0060 Akonadi::Collection collectionForRid(const QString &rid) 0061 { 0062 auto fetch = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive); 0063 fetch->fetchScope().fetchAttribute<Akonadi::SpecialCollectionAttribute>(); 0064 fetch->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); 0065 AKVERIFY_RET(fetch->exec(), {}); 0066 const auto cols = fetch->collections(); 0067 auto colIt = std::find_if(cols.cbegin(), cols.cend(), [&rid](const Akonadi::Collection &col) { 0068 return col.remoteId() == rid; 0069 }); 0070 AKVERIFY_RET(colIt != cols.cend(), {}); 0071 return *colIt; 0072 } 0073 0074 // A kingdom and a horse for std::optional! 0075 std::unique_ptr<UnifiedMailbox> createUnifiedMailbox(const QString &id, const QString &name, const QStringList &sourceRids) 0076 { 0077 auto mailbox = std::make_unique<UnifiedMailbox>(); 0078 mailbox->setId(id); 0079 mailbox->setName(name); 0080 mailbox->setIcon(QStringLiteral("dummy-icon")); 0081 for (const auto &srcRid : sourceRids) { 0082 const auto srcCol = collectionForRid(srcRid); 0083 AKVERIFY_RET(srcCol.isValid(), {}); 0084 mailbox->addSourceCollection(srcCol.id()); 0085 } 0086 return mailbox; 0087 } 0088 0089 class EntityDeleter 0090 { 0091 public: 0092 ~EntityDeleter() 0093 { 0094 while (!cols.isEmpty()) { 0095 if (!(new Akonadi::CollectionDeleteJob(cols.takeFirst()))->exec()) { 0096 QFAIL("Failed to cleanup collection!"); 0097 } 0098 } 0099 while (!items.isEmpty()) { 0100 if (!(new Akonadi::ItemDeleteJob(items.takeFirst()))->exec()) { 0101 QFAIL("Failed to cleanup Item"); 0102 } 0103 } 0104 } 0105 0106 EntityDeleter &operator<<(const Akonadi::Collection &col) 0107 { 0108 cols.push_back(col); 0109 return *this; 0110 } 0111 0112 EntityDeleter &operator<<(const Akonadi::Item &item) 0113 { 0114 items.push_back(item); 0115 return *this; 0116 } 0117 0118 private: 0119 Akonadi::Collection::List cols; 0120 Akonadi::Item::List items; 0121 }; 0122 0123 Akonadi::Collection createCollection(const QString &name, const Akonadi::Collection &parent, EntityDeleter &deleter) 0124 { 0125 Akonadi::Collection col; 0126 col.setName(name); 0127 col.setParentCollection(parent); 0128 col.setVirtual(true); 0129 auto createCol = new Akonadi::CollectionCreateJob(col); 0130 AKVERIFY_RET(createCol->exec(), {}); 0131 col = createCol->collection(); 0132 if (col.isValid()) { 0133 deleter << col; 0134 } 0135 return col; 0136 } 0137 } // namespace 0138 0139 class UnifiedMailboxManagerTest : public QObject 0140 { 0141 Q_OBJECT 0142 0143 private Q_SLOTS: 0144 0145 void initTestCase() 0146 { 0147 AkonadiTest::checkTestIsIsolated(); 0148 } 0149 0150 void testCreateDefaultBoxes() 0151 { 0152 // Setup 0153 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0154 const auto boxesGroup = kcfg->group(QStringLiteral("UnifiedMailboxes")); 0155 UnifiedMailboxManager manager(kcfg); 0156 0157 // Make sure the config is empty 0158 QVERIFY(boxesGroup.groupList().empty()); 0159 0160 // Call loadBoxes and wait for it to finish 0161 bool loadingDone = false; 0162 manager.loadBoxes([&loadingDone]() { 0163 loadingDone = true; 0164 }); 0165 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0166 0167 // Check all the three boxes were created 0168 bool success; 0169 const auto verifyBox = [&manager, &success](const QString &id, int numSources) { 0170 success = false; 0171 auto boxIt = std::find_if(manager.begin(), manager.end(), [&id](const UnifiedMailboxManager::Entry &e) { 0172 return e.second->id() == id; 0173 }); 0174 QVERIFY(boxIt != manager.end()); 0175 const auto &box = boxIt->second; 0176 const auto sourceCollections = box->sourceCollections(); 0177 QCOMPARE(sourceCollections.size(), numSources); 0178 for (auto source : sourceCollections) { 0179 auto col = collectionForId(source); 0180 QVERIFY(col.isValid()); 0181 QVERIFY(col.hasAttribute<Akonadi::SpecialCollectionAttribute>()); 0182 QCOMPARE(col.attribute<Akonadi::SpecialCollectionAttribute>()->collectionType(), id.toLatin1()); 0183 } 0184 success = true; 0185 }; 0186 verifyBox(Common::InboxBoxId, 2); 0187 QVERIFY(success); 0188 verifyBox(Common::SentBoxId, 2); 0189 QVERIFY(success); 0190 verifyBox(Common::DraftsBoxId, 1); 0191 QVERIFY(success); 0192 0193 // Check boxes were written to config - we don't check the contents of 0194 // the group, testing UnifiedMailbox serialization is done in other tests 0195 QVERIFY(boxesGroup.groupList().size() == 3); 0196 QVERIFY(boxesGroup.hasGroup(Common::InboxBoxId)); 0197 QVERIFY(boxesGroup.hasGroup(Common::SentBoxId)); 0198 QVERIFY(boxesGroup.hasGroup(Common::DraftsBoxId)); 0199 } 0200 0201 void testAddingNewMailbox() 0202 { 0203 // Setup 0204 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0205 const auto boxesGroup = kcfg->group(QStringLiteral("UnifiedMailboxes")); 0206 UnifiedMailboxManager manager(kcfg); 0207 Akonadi::ChangeRecorder &recorder = manager.changeRecorder(); 0208 0209 // Nothing should be monitored as of now 0210 QVERIFY(recorder.collectionsMonitored().isEmpty()); 0211 0212 // Create a new unified mailbox and passit to the manager 0213 auto mailbox = createUnifiedMailbox(QStringLiteral("Test1"), QStringLiteral("Test 1"), {QStringLiteral("res1_inbox")}); 0214 QVERIFY(mailbox); 0215 const auto sourceCol = mailbox->sourceCollections().values().first(); 0216 manager.insertBox(std::move(mailbox)); 0217 0218 // Now manager should have one unified mailbox and monitor all of its 0219 // source collections 0220 QCOMPARE(std::distance(manager.begin(), manager.end()), 1l); 0221 QCOMPARE(recorder.collectionsMonitored().size(), 1); 0222 QCOMPARE(recorder.collectionsMonitored().at(0).id(), sourceCol); 0223 QVERIFY(manager.unifiedMailboxForSource(sourceCol) != nullptr); 0224 0225 // But nothing should bne written in the config yet 0226 QVERIFY(!boxesGroup.groupList().contains(QLatin1StringView("Test1"))); 0227 0228 // Now write to the config file and check it's actually there - we don't test 0229 // the contents of the group, UnifiedMailbox serialization has its own test 0230 manager.saveBoxes(); 0231 QVERIFY(boxesGroup.hasGroup(QLatin1StringView("Test1"))); 0232 } 0233 0234 void testRemoveMailbox() 0235 { 0236 // Setup 0237 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0238 auto boxesGroup = kcfg->group(QStringLiteral("UnifiedMailboxes")); 0239 auto mailbox = createUnifiedMailbox(QStringLiteral("Test1"), QStringLiteral("Test 1"), {QStringLiteral("res1_foo"), QStringLiteral("res2_foo")}); 0240 QVERIFY(mailbox); 0241 auto group = boxesGroup.group(mailbox->id()); 0242 mailbox->save(group); 0243 0244 UnifiedMailboxManager manager(kcfg); 0245 Akonadi::ChangeRecorder &recorder = manager.changeRecorder(); 0246 0247 // Nothing should be monitored right now 0248 QVERIFY(recorder.collectionsMonitored().isEmpty()); 0249 0250 // Load the config 0251 bool loadingDone = false; 0252 manager.loadBoxes([&loadingDone]() { 0253 loadingDone = true; 0254 }); 0255 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0256 0257 // Now the box should be loaded and its source collections monitored 0258 QCOMPARE(std::distance(manager.begin(), manager.end()), 1l); 0259 QCOMPARE(recorder.collectionsMonitored().count(), 2); 0260 const auto srcCols = mailbox->sourceCollections().values(); 0261 QCOMPARE(srcCols.count(), 2); 0262 QVERIFY(recorder.collectionsMonitored().contains(Akonadi::Collection(srcCols[0]))); 0263 QVERIFY(recorder.collectionsMonitored().contains(Akonadi::Collection(srcCols[1]))); 0264 0265 // Now remove the box 0266 manager.removeBox(mailbox->id()); 0267 0268 // Manager should have no boxes and no source collections should be monitored 0269 QVERIFY(manager.begin() == manager.end()); 0270 QVERIFY(recorder.collectionsMonitored().isEmpty()); 0271 0272 // But the box still exists in the config 0273 QVERIFY(boxesGroup.hasGroup(mailbox->id())); 0274 0275 // Save the new state 0276 manager.saveBoxes(); 0277 0278 // And now it should be gone from the config file as well 0279 QVERIFY(!boxesGroup.hasGroup(mailbox->id())); 0280 } 0281 0282 void testDiscoverBoxCollections() 0283 { 0284 // Setup 0285 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0286 auto boxesGroup = kcfg->group(QStringLiteral("UnifiedMailboxes")); 0287 UnifiedMailboxManager manager(kcfg); 0288 EntityDeleter deleter; 0289 const auto inbox = createUnifiedMailbox(Common::InboxBoxId, QStringLiteral("Inbox"), {QStringLiteral("res1_inbox"), QStringLiteral("res2_inbox")}); 0290 auto boxGroup = boxesGroup.group(inbox->id()); 0291 inbox->save(boxGroup); 0292 const auto sentBox = createUnifiedMailbox(Common::SentBoxId, QStringLiteral("Sent"), {QStringLiteral("res1_sent"), QStringLiteral("res2_sent")}); 0293 boxGroup = boxesGroup.group(sentBox->id()); 0294 sentBox->save(boxGroup); 0295 0296 const Akonadi::Collection parentCol = collectionForRid(Common::AgentIdentifier); 0297 QVERIFY(parentCol.isValid()); 0298 0299 const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol, deleter); 0300 QVERIFY(inboxBoxCol.isValid()); 0301 0302 const auto sentBoxCol = createCollection(Common::SentBoxId, parentCol, deleter); 0303 QVERIFY(sentBoxCol.isValid()); 0304 0305 // Load from config 0306 bool loadingDone = false; 0307 manager.loadBoxes([&loadingDone]() { 0308 loadingDone = true; 0309 }); 0310 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0311 0312 // Now the boxes should be loaded and we should be able to access them 0313 // by IDs of collections that represent them. The collections should also 0314 // be set for each box. 0315 auto box = manager.unifiedMailboxFromCollection(inboxBoxCol); 0316 QVERIFY(box != nullptr); 0317 QCOMPARE(box->collectionId(), inboxBoxCol.id()); 0318 0319 box = manager.unifiedMailboxFromCollection(sentBoxCol); 0320 QVERIFY(box != nullptr); 0321 QCOMPARE(box->collectionId(), sentBoxCol.id()); 0322 } 0323 0324 void testItemAddedToSourceCollection() 0325 { 0326 // Setup 0327 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0328 UnifiedMailboxManager manager(kcfg); 0329 EntityDeleter deleter; 0330 0331 const auto parentCol = collectionForRid(Common::AgentIdentifier); 0332 QVERIFY(parentCol.isValid()); 0333 0334 const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol, deleter); 0335 QVERIFY(inboxBoxCol.isValid()); 0336 0337 // Load boxes - config is empty so this will create the default Boxes and 0338 // assign the Inboxes from Knuts to it 0339 bool loadingDone = true; 0340 manager.loadBoxes([&loadingDone]() { 0341 loadingDone = true; 0342 }); 0343 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0344 0345 // Now discover collections for the created boxes 0346 loadingDone = false; 0347 manager.discoverBoxCollections([&loadingDone]() { 0348 loadingDone = true; 0349 }); 0350 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0351 0352 // Get one of the source collections for Inbox 0353 const auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); 0354 QVERIFY(inboxSourceCol.isValid()); 0355 0356 // Setup up a monitor to to be notified when an item gets linked into 0357 // the unified mailbox collection 0358 Akonadi::Monitor monitor; 0359 monitor.setCollectionMonitored(inboxBoxCol); 0360 QSignalSpy itemLinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsLinked); 0361 QVERIFY(QSignalSpy(&monitor, &Akonadi::Monitor::monitorReady).wait()); 0362 0363 // Add a new Item into the source collection 0364 Akonadi::Item item; 0365 item.setMimeType(QStringLiteral("application/octet-stream")); 0366 item.setParentCollection(inboxSourceCol); 0367 item.setPayload(QByteArray{"Hello world!"}); 0368 auto createItem = new Akonadi::ItemCreateJob(item, inboxSourceCol, this); 0369 AKVERIFYEXEC(createItem); 0370 item = createItem->item(); 0371 deleter << item; 0372 0373 // Then wait for ItemLinked notification as the Manager has linked the new Item 0374 // to the dest collection 0375 QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); 0376 const auto linkedItems = itemLinkedSignalSpy.at(0).at(0).value<Akonadi::Item::List>(); 0377 QCOMPARE(linkedItems.size(), 1); 0378 QCOMPARE(linkedItems.at(0), item); 0379 const auto linkedCol = itemLinkedSignalSpy.at(0).at(1).value<Akonadi::Collection>(); 0380 QCOMPARE(linkedCol, inboxBoxCol); 0381 } 0382 0383 void testItemMovedFromSourceCollection() 0384 { 0385 // Setup 0386 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0387 UnifiedMailboxManager manager(kcfg); 0388 EntityDeleter deleter; 0389 0390 const auto parentCol = collectionForRid(Common::AgentIdentifier); 0391 QVERIFY(parentCol.isValid()); 0392 0393 const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol, deleter); 0394 QVERIFY(inboxBoxCol.isValid()); 0395 0396 // Load boxes - config is empty so this will create the default Boxes and 0397 // assign the Inboxes from Knuts to it 0398 bool loadingDone = true; 0399 manager.loadBoxes([&loadingDone]() { 0400 loadingDone = true; 0401 }); 0402 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0403 0404 // Now discover collections for the created boxes 0405 loadingDone = false; 0406 manager.discoverBoxCollections([&loadingDone]() { 0407 loadingDone = true; 0408 }); 0409 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0410 0411 // Get one of the source collections for Inbox 0412 const auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); 0413 QVERIFY(inboxSourceCol.isValid()); 0414 0415 // Setup up a monitor to to be notified when an item gets linked into 0416 // the unified mailbox collection 0417 Akonadi::Monitor monitor; 0418 monitor.setCollectionMonitored(inboxBoxCol); 0419 QSignalSpy itemLinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsLinked); 0420 QSignalSpy itemUnlinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsUnlinked); 0421 QVERIFY(QSignalSpy(&monitor, &Akonadi::Monitor::monitorReady).wait()); 0422 0423 // Add a new Item into the source collection 0424 Akonadi::Item item; 0425 item.setMimeType(QStringLiteral("application/octet-stream")); 0426 item.setParentCollection(inboxSourceCol); 0427 item.setPayload(QByteArray{"Hello world!"}); 0428 auto createItem = new Akonadi::ItemCreateJob(item, inboxSourceCol, this); 0429 AKVERIFYEXEC(createItem); 0430 item = createItem->item(); 0431 deleter << item; 0432 0433 // Waity for the item to be linked 0434 QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); 0435 0436 const auto destinationCol = collectionForRid(QStringLiteral("res1_foo")); 0437 QVERIFY(destinationCol.isValid()); 0438 0439 // Now move the Item to an unmonitored collection 0440 auto move = new Akonadi::ItemMoveJob(item, destinationCol, this); 0441 AKVERIFYEXEC(move); 0442 0443 QTRY_COMPARE(itemUnlinkedSignalSpy.size(), 1); 0444 const auto unlinkedItems = itemUnlinkedSignalSpy.at(0).at(0).value<Akonadi::Item::List>(); 0445 QCOMPARE(unlinkedItems.size(), 1); 0446 QCOMPARE(unlinkedItems.first(), item); 0447 const auto unlinkedCol = itemUnlinkedSignalSpy.at(0).at(1).value<Akonadi::Collection>(); 0448 QCOMPARE(unlinkedCol, inboxBoxCol); 0449 } 0450 0451 void testItemMovedBetweenSourceCollections() 0452 { 0453 // Setup 0454 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0455 UnifiedMailboxManager manager(kcfg); 0456 EntityDeleter deleter; 0457 0458 const auto parentCol = collectionForRid(Common::AgentIdentifier); 0459 QVERIFY(parentCol.isValid()); 0460 0461 const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol, deleter); 0462 QVERIFY(inboxBoxCol.isValid()); 0463 0464 const auto draftsBoxCol = createCollection(Common::DraftsBoxId, parentCol, deleter); 0465 QVERIFY(draftsBoxCol.isValid()); 0466 0467 // Load boxes - config is empty so this will create the default Boxes and 0468 // assign the Inboxes from Knuts to it 0469 bool loadingDone = true; 0470 manager.loadBoxes([&loadingDone]() { 0471 loadingDone = true; 0472 }); 0473 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0474 0475 // Now discover collections for the created boxes 0476 loadingDone = false; 0477 manager.discoverBoxCollections([&loadingDone]() { 0478 loadingDone = true; 0479 }); 0480 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0481 0482 // Get one of the source collections for Inbox and Drafts 0483 const auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); 0484 QVERIFY(inboxSourceCol.isValid()); 0485 const auto draftsSourceCol = collectionForRid(QStringLiteral("res1_drafts")); 0486 QVERIFY(draftsSourceCol.isValid()); 0487 0488 // Setup up a monitor to to be notified when an item gets linked into 0489 // the unified mailbox collection 0490 Akonadi::Monitor monitor; 0491 monitor.setCollectionMonitored(inboxBoxCol); 0492 monitor.setCollectionMonitored(draftsBoxCol); 0493 QSignalSpy itemLinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsLinked); 0494 QSignalSpy itemUnlinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsUnlinked); 0495 QVERIFY(QSignalSpy(&monitor, &Akonadi::Monitor::monitorReady).wait()); 0496 0497 // Add a new Item into the source Inbox collection 0498 Akonadi::Item item; 0499 item.setMimeType(QStringLiteral("application/octet-stream")); 0500 item.setParentCollection(inboxSourceCol); 0501 item.setPayload(QByteArray{"Hello world!"}); 0502 auto createItem = new Akonadi::ItemCreateJob(item, inboxSourceCol, this); 0503 AKVERIFYEXEC(createItem); 0504 item = createItem->item(); 0505 deleter << item; 0506 0507 // Waity for the item to be linked 0508 QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); 0509 itemLinkedSignalSpy.clear(); 0510 0511 // Now move the Item to another Unified mailbox's source collection 0512 auto move = new Akonadi::ItemMoveJob(item, draftsSourceCol, this); 0513 AKVERIFYEXEC(move); 0514 0515 QTRY_COMPARE(itemUnlinkedSignalSpy.size(), 1); 0516 const auto unlinkedItems = itemUnlinkedSignalSpy.at(0).at(0).value<Akonadi::Item::List>(); 0517 QCOMPARE(unlinkedItems.size(), 1); 0518 QCOMPARE(unlinkedItems.first(), item); 0519 const auto unlinkedCol = itemUnlinkedSignalSpy.at(0).at(1).value<Akonadi::Collection>(); 0520 QCOMPARE(unlinkedCol, inboxBoxCol); 0521 0522 QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); 0523 const auto linkedItems = itemLinkedSignalSpy.at(0).at(0).value<Akonadi::Item::List>(); 0524 QCOMPARE(linkedItems.size(), 1); 0525 QCOMPARE(linkedItems.first(), item); 0526 const auto linkedCol = itemLinkedSignalSpy.at(0).at(1).value<Akonadi::Collection>(); 0527 QCOMPARE(linkedCol, draftsBoxCol); 0528 } 0529 0530 void testSourceCollectionRemoved() 0531 { 0532 // Setup 0533 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0534 UnifiedMailboxManager manager(kcfg); 0535 auto &changeRecorder = manager.changeRecorder(); 0536 QSignalSpy crRemovedSpy(&changeRecorder, &Akonadi::Monitor::collectionRemoved); 0537 EntityDeleter deleter; 0538 0539 const auto parentCol = collectionForRid(Common::AgentIdentifier); 0540 QVERIFY(parentCol.isValid()); 0541 0542 const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol, deleter); 0543 QVERIFY(inboxBoxCol.isValid()); 0544 0545 // Load boxes - config is empty so this will create the default Boxes and 0546 // assign the Inboxes from Knuts to it 0547 bool loadingDone = true; 0548 manager.loadBoxes([&loadingDone]() { 0549 loadingDone = true; 0550 }); 0551 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0552 0553 // Now discover collections for the created boxes 0554 loadingDone = false; 0555 manager.discoverBoxCollections([&loadingDone]() { 0556 loadingDone = true; 0557 }); 0558 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0559 0560 auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); 0561 QVERIFY(inboxSourceCol.isValid()); 0562 auto delJob = new Akonadi::CollectionDeleteJob(inboxSourceCol, this); 0563 AKVERIFYEXEC(delJob); 0564 0565 // Wait for the change recorder to be notified 0566 QVERIFY(crRemovedSpy.wait()); 0567 crRemovedSpy.clear(); 0568 // and then wait a little bit more to give the Manager time to process the event 0569 QTest::qWait(0); 0570 0571 auto inboxBox = manager.unifiedMailboxFromCollection(inboxBoxCol); 0572 QVERIFY(inboxBox); 0573 QVERIFY(!inboxBox->sourceCollections().contains(inboxSourceCol.id())); 0574 QVERIFY(!changeRecorder.collectionsMonitored().contains(inboxSourceCol)); 0575 QVERIFY(!manager.unifiedMailboxForSource(inboxSourceCol.id())); 0576 0577 // Lets removed the other source collection now, that should remove the unified box completely 0578 inboxSourceCol = collectionForRid(QStringLiteral("res2_inbox")); 0579 QVERIFY(inboxSourceCol.isValid()); 0580 delJob = new Akonadi::CollectionDeleteJob(inboxSourceCol, this); 0581 AKVERIFYEXEC(delJob); 0582 0583 // Wait for the change recorder once again 0584 QVERIFY(crRemovedSpy.wait()); 0585 QTest::qWait(0); 0586 0587 QVERIFY(!manager.unifiedMailboxFromCollection(inboxBoxCol)); 0588 QVERIFY(!changeRecorder.collectionsMonitored().contains(inboxSourceCol)); 0589 QVERIFY(!manager.unifiedMailboxForSource(inboxSourceCol.id())); 0590 } 0591 0592 void testSpecialSourceCollectionCreated() 0593 { 0594 // TODO: this does not work yet: we only monitor collections that we are 0595 // interested in, we don't monitor other collections 0596 } 0597 0598 void testSpecialSourceCollectionDemoted() 0599 { 0600 // Setup 0601 auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); 0602 UnifiedMailboxManager manager(kcfg); 0603 auto &changeRecorder = manager.changeRecorder(); 0604 QSignalSpy crChangedSpy(&changeRecorder, qOverload<const Akonadi::Collection &, const QSet<QByteArray> &>(&Akonadi::Monitor::collectionChanged)); 0605 EntityDeleter deleter; 0606 0607 const auto parentCol = collectionForRid(Common::AgentIdentifier); 0608 QVERIFY(parentCol.isValid()); 0609 0610 const auto sentBoxCol = createCollection(Common::SentBoxId, parentCol, deleter); 0611 QVERIFY(sentBoxCol.isValid()); 0612 0613 // Load boxes - config is empty so this will create the default Boxes and 0614 // assign the Inboxes from Knuts to it 0615 bool loadingDone = true; 0616 manager.loadBoxes([&loadingDone]() { 0617 loadingDone = true; 0618 }); 0619 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0620 0621 // Now discover collections for the created boxes 0622 loadingDone = false; 0623 manager.discoverBoxCollections([&loadingDone]() { 0624 loadingDone = true; 0625 }); 0626 QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); 0627 0628 auto sentSourceCol = collectionForRid(QStringLiteral("res1_sent")); 0629 QVERIFY(sentSourceCol.isValid()); 0630 sentSourceCol.removeAttribute<Akonadi::SpecialCollectionAttribute>(); 0631 auto modify = new Akonadi::CollectionModifyJob(sentSourceCol, this); 0632 AKVERIFYEXEC(modify); 0633 0634 // Wait for the change recorder to be notified 0635 QVERIFY(crChangedSpy.wait()); 0636 crChangedSpy.clear(); 0637 // and then wait a little bit more to give the Manager time to process the event 0638 QTest::qWait(0); 0639 0640 auto sourceBox = manager.unifiedMailboxFromCollection(sentBoxCol); 0641 QVERIFY(sourceBox); 0642 QVERIFY(!sourceBox->sourceCollections().contains(sentSourceCol.id())); 0643 QVERIFY(!changeRecorder.collectionsMonitored().contains(sentSourceCol)); 0644 QVERIFY(!manager.unifiedMailboxForSource(sentSourceCol.id())); 0645 0646 // Lets demote the other source collection now, that should remove the unified box completely 0647 sentSourceCol = collectionForRid(QStringLiteral("res2_sent")); 0648 QVERIFY(sentSourceCol.isValid()); 0649 sentSourceCol.attribute<Akonadi::SpecialCollectionAttribute>()->setCollectionType("drafts"); 0650 modify = new Akonadi::CollectionModifyJob(sentSourceCol, this); 0651 AKVERIFYEXEC(modify); 0652 0653 // Wait for the change recorder once again 0654 QVERIFY(crChangedSpy.wait()); 0655 QTest::qWait(0); 0656 0657 // There's no more Sent unified box 0658 QVERIFY(!manager.unifiedMailboxFromCollection(sentBoxCol)); 0659 0660 // The collection is still monitored: it belongs to the Drafts special box now! 0661 QVERIFY(changeRecorder.collectionsMonitored().contains(sentSourceCol)); 0662 QVERIFY(manager.unifiedMailboxForSource(sentSourceCol.id())); 0663 } 0664 }; 0665 0666 QTEST_AKONADIMAIN(UnifiedMailboxManagerTest) 0667 0668 #include "unifiedmailboxmanagertest.moc"