File indexing completed on 2024-12-22 04:57:35
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0003 SPDX-FileContributor: Kevin Krammer <krake@kdab.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "mixedmaildirstore.h" 0009 0010 #include "filestore/collectionfetchjob.h" 0011 0012 #include "libmaildir/maildir.h" 0013 0014 #include <KMime/Message> 0015 0016 #include <QTemporaryDir> 0017 0018 #include <QSignalSpy> 0019 0020 #include <QDir> 0021 #include <QFileInfo> 0022 #include <QTest> 0023 0024 using namespace Akonadi; 0025 0026 static Collection::List collectionsFromSpy(QSignalSpy *spy) 0027 { 0028 Collection::List collections; 0029 0030 QListIterator<QList<QVariant>> it(*spy); 0031 while (it.hasNext()) { 0032 const QList<QVariant> invocation = it.next(); 0033 Q_ASSERT(invocation.count() == 1); 0034 0035 collections << invocation.first().value<Collection::List>(); 0036 } 0037 0038 return collections; 0039 } 0040 0041 class CollectionFetchTest : public QObject 0042 { 0043 Q_OBJECT 0044 0045 public: 0046 CollectionFetchTest() 0047 : QObject() 0048 , mStore(nullptr) 0049 , mDir(nullptr) 0050 { 0051 // for monitoring signals 0052 qRegisterMetaType<Akonadi::Collection::List>(); 0053 } 0054 0055 ~CollectionFetchTest() override 0056 { 0057 delete mStore; 0058 delete mDir; 0059 } 0060 0061 private: 0062 MixedMaildirStore *mStore = nullptr; 0063 QTemporaryDir *mDir = nullptr; 0064 0065 private Q_SLOTS: 0066 void init(); 0067 void cleanup(); 0068 void testEmptyDir(); 0069 void testMixedTree(); 0070 }; 0071 0072 void CollectionFetchTest::init() 0073 { 0074 mStore = new MixedMaildirStore; 0075 0076 mDir = new QTemporaryDir; 0077 QVERIFY(mDir->isValid()); 0078 QVERIFY(QDir(mDir->path()).exists()); 0079 } 0080 0081 void CollectionFetchTest::cleanup() 0082 { 0083 delete mStore; 0084 mStore = nullptr; 0085 delete mDir; 0086 mDir = nullptr; 0087 } 0088 0089 void CollectionFetchTest::testEmptyDir() 0090 { 0091 mStore->setPath(mDir->path()); 0092 0093 FileStore::CollectionFetchJob *job = nullptr; 0094 QSignalSpy *spy = nullptr; 0095 Collection::List collections; 0096 0097 // test base fetch of top level collection 0098 job = mStore->fetchCollections(mStore->topLevelCollection(), FileStore::CollectionFetchJob::Base); 0099 0100 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0101 0102 QVERIFY(job->exec()); 0103 QCOMPARE(job->error(), 0); 0104 QCOMPARE(spy->count(), 1); 0105 0106 collections = collectionsFromSpy(spy); 0107 QCOMPARE(collections.count(), 1); 0108 QCOMPARE(collections.first(), mStore->topLevelCollection()); 0109 QCOMPARE(job->collections(), collections); 0110 0111 // test first level fetch of top level collection 0112 job = mStore->fetchCollections(mStore->topLevelCollection(), FileStore::CollectionFetchJob::FirstLevel); 0113 0114 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0115 0116 QVERIFY(job->exec()); 0117 QCOMPARE(job->error(), 0); 0118 QCOMPARE(spy->count(), 0); 0119 0120 collections = collectionsFromSpy(spy); 0121 QCOMPARE(collections.count(), 0); 0122 QCOMPARE(job->collections(), collections); 0123 0124 // test recursive fetch of top level collection 0125 job = mStore->fetchCollections(mStore->topLevelCollection(), FileStore::CollectionFetchJob::Recursive); 0126 0127 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0128 0129 QVERIFY(job->exec()); 0130 QCOMPARE(job->error(), 0); 0131 QCOMPARE(spy->count(), 0); 0132 0133 collections = collectionsFromSpy(spy); 0134 QCOMPARE(collections.count(), 0); 0135 QCOMPARE(job->collections(), collections); 0136 0137 // test fail of base fetching non existent collection 0138 Collection collection; 0139 collection.setName(QStringLiteral("collection")); 0140 collection.setRemoteId(QStringLiteral("collection")); 0141 collection.setParentCollection(mStore->topLevelCollection()); 0142 0143 job = mStore->fetchCollections(collection, FileStore::CollectionFetchJob::Base); 0144 0145 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0146 0147 QVERIFY(!job->exec()); 0148 QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext); 0149 QCOMPARE(spy->count(), 0); 0150 0151 collections = collectionsFromSpy(spy); 0152 QCOMPARE(collections.count(), 0); 0153 QCOMPARE(job->collections(), collections); 0154 0155 // test fail of first level fetching non existent collection 0156 job = mStore->fetchCollections(collection, FileStore::CollectionFetchJob::FirstLevel); 0157 0158 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0159 0160 QVERIFY(!job->exec()); 0161 QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext); 0162 QCOMPARE(spy->count(), 0); 0163 0164 collections = collectionsFromSpy(spy); 0165 QCOMPARE(collections.count(), 0); 0166 QCOMPARE(job->collections(), collections); 0167 0168 // test fail of recursive fetching non existent collection 0169 job = mStore->fetchCollections(collection, FileStore::CollectionFetchJob::FirstLevel); 0170 0171 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0172 0173 QVERIFY(!job->exec()); 0174 QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext); 0175 QCOMPARE(spy->count(), 0); 0176 0177 collections = collectionsFromSpy(spy); 0178 QCOMPARE(collections.count(), 0); 0179 QCOMPARE(job->collections(), collections); 0180 } 0181 0182 void CollectionFetchTest::testMixedTree() 0183 { 0184 QDir topDir(mDir->path()); 0185 0186 KPIM::Maildir topLevelMd(mDir->path(), true); 0187 QVERIFY(topLevelMd.isValid()); 0188 0189 KPIM::Maildir md1(topLevelMd.addSubFolder(QStringLiteral("collection1")), false); 0190 KPIM::Maildir md1_2(md1.addSubFolder(QStringLiteral("collection1_2")), false); 0191 KPIM::Maildir md1_2_1(md1_2.addSubFolder(QStringLiteral("collection1_2_1")), false); 0192 0193 // simulate second level mbox in maildir parent 0194 QFileInfo fileInfo1_1(KPIM::Maildir::subDirPathForFolderPath(md1.path()), QStringLiteral("collection1_1")); 0195 QFile file1_1(fileInfo1_1.absoluteFilePath()); 0196 file1_1.open(QIODevice::WriteOnly); 0197 file1_1.close(); 0198 QVERIFY(fileInfo1_1.exists()); 0199 0200 QFileInfo subDirInfo1_1(KPIM::Maildir::subDirPathForFolderPath(fileInfo1_1.absoluteFilePath())); 0201 QVERIFY(topDir.mkpath(subDirInfo1_1.absoluteFilePath())); 0202 KPIM::Maildir md1_1(subDirInfo1_1.absoluteFilePath(), true); 0203 KPIM::Maildir md1_1_1(md1_1.addSubFolder(QStringLiteral("collection1_1_1")), false); 0204 0205 // simulate third level mbox in mbox parent 0206 QFileInfo fileInfo1_1_2(md1_1.path(), QStringLiteral("collection1_1_2")); 0207 QFile file1_1_2(fileInfo1_1_2.absoluteFilePath()); 0208 file1_1_2.open(QIODevice::WriteOnly); 0209 file1_1_2.close(); 0210 QVERIFY(fileInfo1_1_2.exists()); 0211 0212 KPIM::Maildir md2(topLevelMd.addSubFolder(QStringLiteral("collection2")), false); 0213 0214 // simulate first level mbox 0215 QFileInfo fileInfo3(mDir->path(), QStringLiteral("collection3")); 0216 QFile file3(fileInfo3.absoluteFilePath()); 0217 file3.open(QIODevice::WriteOnly); 0218 file3.close(); 0219 QVERIFY(fileInfo3.exists()); 0220 0221 // simulate first level mbox with subtree 0222 QFileInfo fileInfo4(mDir->path(), QStringLiteral("collection4")); 0223 QFile file4(fileInfo4.absoluteFilePath()); 0224 file4.open(QIODevice::WriteOnly); 0225 file4.close(); 0226 QVERIFY(fileInfo4.exists()); 0227 0228 QFileInfo subDirInfo4(KPIM::Maildir::subDirPathForFolderPath(fileInfo4.absoluteFilePath())); 0229 QVERIFY(topDir.mkpath(subDirInfo4.absoluteFilePath())); 0230 0231 KPIM::Maildir md4(subDirInfo4.absoluteFilePath(), true); 0232 KPIM::Maildir md4_1(md4.addSubFolder(QStringLiteral("collection4_1")), false); 0233 0234 // simulate second level mbox in mbox parent 0235 QFileInfo fileInfo4_2(subDirInfo4.absoluteFilePath(), QStringLiteral("collection4_2")); 0236 QFile file4_2(fileInfo4_2.absoluteFilePath()); 0237 file4_2.open(QIODevice::WriteOnly); 0238 file4_2.close(); 0239 QVERIFY(fileInfo4_2.exists()); 0240 0241 QSet<QString> firstLevelNames; 0242 firstLevelNames << md1.name() << md2.name() << fileInfo3.fileName() << fileInfo4.fileName(); 0243 0244 QSet<QString> secondLevelNames; 0245 secondLevelNames << md1_2.name() << md4_1.name() << fileInfo1_1.fileName() << fileInfo4_2.fileName(); 0246 0247 QSet<QString> thirdLevelNames; 0248 thirdLevelNames << md1_1_1.name() << fileInfo1_1_2.fileName() << md1_2_1.name(); 0249 0250 mStore->setPath(mDir->path()); 0251 // mDir = 0; 0252 0253 FileStore::CollectionFetchJob *job = nullptr; 0254 QSignalSpy *spy = nullptr; 0255 Collection::List collections; 0256 0257 // test base fetch of top level collection 0258 job = mStore->fetchCollections(mStore->topLevelCollection(), FileStore::CollectionFetchJob::Base); 0259 0260 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0261 0262 QVERIFY(job->exec()); 0263 QCOMPARE(job->error(), 0); 0264 QCOMPARE(spy->count(), 1); 0265 0266 collections = collectionsFromSpy(spy); 0267 QCOMPARE(collections.count(), 1); 0268 QCOMPARE(collections.first(), mStore->topLevelCollection()); 0269 QCOMPARE(job->collections(), collections); 0270 0271 // test first level fetch of top level collection 0272 job = mStore->fetchCollections(mStore->topLevelCollection(), FileStore::CollectionFetchJob::FirstLevel); 0273 0274 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0275 0276 QVERIFY(job->exec()); 0277 QCOMPARE(job->error(), 0); 0278 QVERIFY(!spy->isEmpty()); 0279 0280 collections = collectionsFromSpy(spy); 0281 QCOMPARE(collections.count(), firstLevelNames.count()); 0282 QCOMPARE(job->collections(), collections); 0283 0284 for (const Collection &collection : std::as_const(collections)) { 0285 QVERIFY(!collection.remoteId().isEmpty()); 0286 QCOMPARE(collection.remoteId(), collection.name()); 0287 QCOMPARE(collection.contentMimeTypes(), QStringList() << Collection::mimeType() << KMime::Message::mimeType()); 0288 0289 QCOMPARE(collection.rights(), 0290 Collection::CanCreateItem | Collection::CanChangeItem | Collection::CanDeleteItem | Collection::CanCreateCollection 0291 | Collection::CanChangeCollection | Collection::CanDeleteCollection); 0292 0293 QCOMPARE(collection.parentCollection(), mStore->topLevelCollection()); 0294 QVERIFY(firstLevelNames.contains(collection.name())); 0295 } 0296 0297 // test recursive fetch of top level collection 0298 job = mStore->fetchCollections(mStore->topLevelCollection(), FileStore::CollectionFetchJob::Recursive); 0299 0300 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0301 0302 QVERIFY(job->exec()); 0303 QCOMPARE(job->error(), 0); 0304 QVERIFY(!spy->isEmpty()); 0305 0306 collections = collectionsFromSpy(spy); 0307 QCOMPARE(collections.count(), firstLevelNames.count() + secondLevelNames.count() + thirdLevelNames.count()); 0308 QCOMPARE(job->collections(), collections); 0309 0310 for (const Collection &collection : std::as_const(collections)) { 0311 QVERIFY(!collection.remoteId().isEmpty()); 0312 QCOMPARE(collection.remoteId(), collection.name()); 0313 QCOMPARE(collection.contentMimeTypes(), QStringList() << Collection::mimeType() << KMime::Message::mimeType()); 0314 0315 QCOMPARE(collection.rights(), 0316 Collection::CanCreateItem | Collection::CanChangeItem | Collection::CanDeleteItem | Collection::CanCreateCollection 0317 | Collection::CanChangeCollection | Collection::CanDeleteCollection); 0318 0319 if (firstLevelNames.contains(collection.name())) { 0320 QCOMPARE(collection.parentCollection(), mStore->topLevelCollection()); 0321 } else if (secondLevelNames.contains(collection.name())) { 0322 QVERIFY(firstLevelNames.contains(collection.parentCollection().name())); 0323 QCOMPARE(collection.parentCollection().parentCollection(), mStore->topLevelCollection()); 0324 } else if (thirdLevelNames.contains(collection.name())) { 0325 QVERIFY(secondLevelNames.contains(collection.parentCollection().name())); 0326 QCOMPARE(collection.parentCollection().parentCollection().parentCollection(), mStore->topLevelCollection()); 0327 } 0328 } 0329 0330 // test base fetching all collections 0331 for (const Collection &collection : std::as_const(collections)) { 0332 job = mStore->fetchCollections(collection, FileStore::CollectionFetchJob::Base); 0333 0334 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0335 0336 QVERIFY(job->exec()); 0337 QCOMPARE(job->error(), 0); 0338 QCOMPARE(spy->count(), 1); 0339 0340 const Collection::List list = collectionsFromSpy(spy); 0341 QCOMPARE(list.count(), 1); 0342 QCOMPARE(list.first(), collection); 0343 QCOMPARE(job->collections(), list); 0344 0345 const Collection col = list.first(); 0346 QVERIFY(!col.remoteId().isEmpty()); 0347 QCOMPARE(col.remoteId(), col.name()); 0348 QCOMPARE(col.contentMimeTypes(), QStringList() << Collection::mimeType() << KMime::Message::mimeType()); 0349 0350 QCOMPARE(col.rights(), 0351 Collection::CanCreateItem | Collection::CanChangeItem | Collection::CanDeleteItem | Collection::CanCreateCollection 0352 | Collection::CanChangeCollection | Collection::CanDeleteCollection); 0353 } 0354 0355 // test first level fetching all collections 0356 for (const Collection &collection : std::as_const(collections)) { 0357 job = mStore->fetchCollections(collection, FileStore::CollectionFetchJob::FirstLevel); 0358 0359 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0360 0361 QVERIFY(job->exec()); 0362 QCOMPARE(job->error(), 0); 0363 0364 const Collection::List list = collectionsFromSpy(spy); 0365 QCOMPARE(job->collections(), list); 0366 0367 for (const Collection &childCollection : list) { 0368 QCOMPARE(childCollection.parentCollection(), collection); 0369 0370 QVERIFY(!childCollection.remoteId().isEmpty()); 0371 QCOMPARE(childCollection.remoteId(), childCollection.name()); 0372 QCOMPARE(childCollection.contentMimeTypes(), QStringList() << Collection::mimeType() << KMime::Message::mimeType()); 0373 0374 QCOMPARE(childCollection.rights(), 0375 Collection::CanCreateItem | Collection::CanChangeItem | Collection::CanDeleteItem | Collection::CanCreateCollection 0376 | Collection::CanChangeCollection | Collection::CanDeleteCollection); 0377 } 0378 0379 if (firstLevelNames.contains(collection.name())) { 0380 for (const Collection &childCollection : list) { 0381 QVERIFY(secondLevelNames.contains(childCollection.name())); 0382 } 0383 } else if (secondLevelNames.contains(collection.name())) { 0384 for (const Collection &childCollection : list) { 0385 QVERIFY(thirdLevelNames.contains(childCollection.name())); 0386 } 0387 if (collection.name() == md1_2.name()) { 0388 QCOMPARE(list.count(), 1); 0389 QCOMPARE(list.first().name(), md1_2_1.name()); 0390 } else if (collection.name() == fileInfo1_1.fileName()) { 0391 QCOMPARE(list.count(), 2); 0392 } 0393 } else { 0394 QCOMPARE(list.count(), 0); 0395 } 0396 } 0397 0398 // test recursive fetching all collections 0399 for (const Collection &collection : std::as_const(collections)) { 0400 job = mStore->fetchCollections(collection, FileStore::CollectionFetchJob::Recursive); 0401 0402 spy = new QSignalSpy(job, &FileStore::CollectionFetchJob::collectionsReceived); 0403 0404 QVERIFY(job->exec()); 0405 QCOMPARE(job->error(), 0); 0406 0407 const Collection::List list = collectionsFromSpy(spy); 0408 QCOMPARE(job->collections(), list); 0409 0410 for (const Collection &childCollection : list) { 0411 QVERIFY(childCollection.parentCollection() == collection || childCollection.parentCollection().parentCollection() == collection); 0412 QVERIFY(!childCollection.remoteId().isEmpty()); 0413 QCOMPARE(childCollection.remoteId(), childCollection.name()); 0414 QCOMPARE(childCollection.contentMimeTypes(), QStringList() << Collection::mimeType() << KMime::Message::mimeType()); 0415 0416 QCOMPARE(childCollection.rights(), 0417 Collection::CanCreateItem | Collection::CanChangeItem | Collection::CanDeleteItem | Collection::CanCreateCollection 0418 | Collection::CanChangeCollection | Collection::CanDeleteCollection); 0419 } 0420 0421 if (firstLevelNames.contains(collection.name())) { 0422 for (const Collection &childCollection : list) { 0423 QVERIFY(secondLevelNames.contains(childCollection.name()) || thirdLevelNames.contains(childCollection.name())); 0424 } 0425 } else if (secondLevelNames.contains(collection.name())) { 0426 for (const Collection &childCollection : list) { 0427 QVERIFY(thirdLevelNames.contains(childCollection.name())); 0428 } 0429 if (collection.name() == md1_2.name()) { 0430 QCOMPARE(list.count(), 1); 0431 QCOMPARE(list.first().name(), md1_2_1.name()); 0432 } else if (collection.name() == fileInfo1_1.fileName()) { 0433 QCOMPARE(list.count(), 2); 0434 } 0435 } else { 0436 QCOMPARE(list.count(), 0); 0437 } 0438 } 0439 } 0440 0441 QTEST_MAIN(CollectionFetchTest) 0442 0443 #include "collectionfetchtest.moc"