File indexing completed on 2024-05-12 05:26:23
0001 /* 0002 * Copyright (C) 2016 Christian Mollekopf <chrigi_1@fastmail.fm> 0003 * 0004 * This program is free software; you can redistribute it and/or modify 0005 * it under the terms of the GNU General Public License as published by 0006 * the Free Software Foundation; either version 2 of the License, or 0007 * (at your option) any later version. 0008 * 0009 * This program is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 * GNU General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU General Public License 0015 * along with this program; if not, write to the 0016 * Free Software Foundation, Inc., 0017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0018 */ 0019 #include "mailsynctest.h" 0020 0021 #include <QTest> 0022 0023 #include <QString> 0024 #include <KMime/Message> 0025 0026 #include "store.h" 0027 #include "resourcecontrol.h" 0028 #include "notifier.h" 0029 #include "notification.h" 0030 #include "log.h" 0031 #include "test.h" 0032 0033 using namespace Sink; 0034 using namespace Sink::ApplicationDomain; 0035 0036 static QByteArray newMessage(const QString &subject) 0037 { 0038 auto msg = KMime::Message::Ptr::create(); 0039 msg->subject(true)->fromUnicodeString(subject, "utf8"); 0040 msg->date(true)->setDateTime(QDateTime::currentDateTimeUtc()); 0041 msg->assemble(); 0042 return msg->encodedContent(true); 0043 } 0044 0045 0046 void MailSyncTest::initTestCase() 0047 { 0048 Test::initTest(); 0049 QVERIFY(isBackendAvailable()); 0050 resetTestEnvironment(); 0051 auto resource = createResource(); 0052 QVERIFY(!resource.identifier().isEmpty()); 0053 0054 VERIFYEXEC(Store::create(resource)); 0055 0056 mResourceInstanceIdentifier = resource.identifier(); 0057 //Load the capabilities 0058 resource = Store::readOne<Sink::ApplicationDomain::SinkResource>(Sink::Query{resource}); 0059 mCapabilities = resource.getCapabilities(); 0060 } 0061 0062 void MailSyncTest::cleanup() 0063 { 0064 VERIFYEXEC(ResourceControl::shutdown(mResourceInstanceIdentifier)); 0065 removeResourceFromDisk(mResourceInstanceIdentifier); 0066 } 0067 0068 void MailSyncTest::init() 0069 { 0070 VERIFYEXEC(ResourceControl::start(mResourceInstanceIdentifier)); 0071 } 0072 0073 void MailSyncTest::testListFolders() 0074 { 0075 int baseCount = 0; 0076 //First figure out how many folders we have by default 0077 { 0078 auto job = Store::fetchAll<Folder>(Query()) 0079 .then([&](const QList<Folder::Ptr> &folders) { 0080 QStringList names; 0081 for (const auto &folder : folders) { 0082 names << folder->getName(); 0083 } 0084 SinkTrace() << "base folder: " << names; 0085 baseCount = folders.size(); 0086 }); 0087 VERIFYEXEC(job); 0088 } 0089 0090 Sink::Query query; 0091 query.resourceFilter(mResourceInstanceIdentifier); 0092 query.request<Folder::Name>().request<Folder::SpecialPurpose>(); 0093 0094 // Ensure all local data is processed 0095 VERIFYEXEC(Store::synchronize(query)); 0096 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0097 0098 auto job = Store::fetchAll<Folder>(query).then([=](const QList<Folder::Ptr> &folders) { 0099 QStringList names; 0100 QHash<QByteArray, QByteArray> specialPurposeFolders; 0101 for (const auto &folder : folders) { 0102 names << folder->getName(); 0103 for (const auto &purpose : folder->getSpecialPurpose()) { 0104 specialPurposeFolders.insert(purpose, folder->identifier()); 0105 } 0106 } 0107 //Workaround for maildir 0108 if (names.contains("maildir1")) { 0109 names.removeAll("maildir1"); 0110 } 0111 if (mCapabilities.contains(ResourceCapabilities::Mail::drafts)) { 0112 QVERIFY(names.contains("Drafts")); 0113 names.removeAll("Drafts"); 0114 QVERIFY(specialPurposeFolders.contains(SpecialPurpose::Mail::drafts)); 0115 } 0116 if (mCapabilities.contains(ResourceCapabilities::Mail::trash)) { 0117 QVERIFY(names.contains("Trash")); 0118 names.removeAll("Trash"); 0119 QVERIFY(specialPurposeFolders.contains(SpecialPurpose::Mail::trash)); 0120 } 0121 auto set = QSet<QString>{"INBOX", "test"}; 0122 QCOMPARE(names.toSet(), set); 0123 }); 0124 VERIFYEXEC(job); 0125 } 0126 0127 void MailSyncTest::testListNewFolder() 0128 { 0129 Sink::Query query; 0130 query.resourceFilter(mResourceInstanceIdentifier); 0131 query.request<Folder::Name>(); 0132 0133 createFolder(QStringList() << "test2"); 0134 0135 // Ensure all local data is processed 0136 VERIFYEXEC(Store::synchronize(query)); 0137 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0138 0139 auto job = Store::fetchAll<Folder>(query).then([](const QList<Folder::Ptr> &folders) { 0140 QStringList names; 0141 for (const auto &folder : folders) { 0142 names << folder->getName(); 0143 } 0144 QVERIFY(names.contains("test2")); 0145 }); 0146 VERIFYEXEC(job); 0147 } 0148 0149 void MailSyncTest::testListRemovedFolder() 0150 { 0151 Sink::Query query; 0152 query.resourceFilter(mResourceInstanceIdentifier); 0153 query.request<Folder::Name>(); 0154 0155 VERIFYEXEC(Store::synchronize(query)); 0156 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0157 0158 removeFolder(QStringList() << "test2"); 0159 0160 // Ensure all local data is processed 0161 VERIFYEXEC(Store::synchronize(query)); 0162 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0163 0164 auto job = Store::fetchAll<Folder>(query).then([](const QList<Folder::Ptr> &folders) { 0165 QStringList names; 0166 for (const auto &folder : folders) { 0167 names << folder->getName(); 0168 } 0169 QVERIFY(!names.contains("test2")); 0170 }); 0171 VERIFYEXEC(job); 0172 } 0173 0174 void MailSyncTest::testListRemovedFullFolder() 0175 { 0176 createFolder({"testRemoval"}); 0177 createMessage({"testRemoval"}, newMessage("mailToRemove")); 0178 0179 Sink::Query query; 0180 query.resourceFilter(mResourceInstanceIdentifier); 0181 query.request<Folder::Name>(); 0182 0183 VERIFYEXEC(Store::synchronize(query)); 0184 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0185 QCOMPARE(Sink::Store::read<Folder>(Sink::Query{}.filter<Folder::Name>("testRemoval")).size(), 1); 0186 QCOMPARE(Sink::Store::read<Mail>(Sink::Query{}.filter<Mail::Subject>("mailToRemove")).size(), 1); 0187 0188 removeFolder({"testRemoval"}); 0189 0190 // Ensure all local data is processed 0191 VERIFYEXEC(Store::synchronize(query)); 0192 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0193 0194 QCOMPARE(Sink::Store::read<Folder>(Sink::Query{}.filter<Folder::Name>("testRemoval")).size(), 0); 0195 QCOMPARE(Sink::Store::read<Mail>(Sink::Query{}.filter<Mail::Subject>("mailToRemove")).size(), 0); 0196 } 0197 0198 void MailSyncTest::testListFolderHierarchy() 0199 { 0200 if (!mCapabilities.contains(ResourceCapabilities::Mail::folderhierarchy)) { 0201 QSKIP("Missing capability folder.hierarchy"); 0202 } 0203 Sink::Query query; 0204 query.resourceFilter(mResourceInstanceIdentifier); 0205 query.request<Folder::Name>().request<Folder::Parent>(); 0206 0207 createFolder(QStringList() << "test" << "sub"); 0208 0209 // Ensure all local data is processed 0210 VERIFYEXEC(Store::synchronize(query)); 0211 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0212 0213 auto job = Store::fetchAll<Folder>(query).then([=](const QList<Folder::Ptr> &folders) { 0214 QHash<QString, Folder::Ptr> map; 0215 for (const auto &folder : folders) { 0216 map.insert(folder->getName(), folder); 0217 } 0218 QStringList names; 0219 for (const auto &folder : folders) { 0220 names << folder->getName(); 0221 } 0222 0223 //Workaround for maildir 0224 if (names.contains("maildir1")) { 0225 names.removeAll("maildir1"); 0226 } 0227 if (mCapabilities.contains(ResourceCapabilities::Mail::drafts)) { 0228 QVERIFY(names.contains("Drafts")); 0229 names.removeAll("Drafts"); 0230 } 0231 if (mCapabilities.contains(ResourceCapabilities::Mail::trash)) { 0232 QVERIFY(names.contains("Trash")); 0233 names.removeAll("Trash"); 0234 } 0235 QCOMPARE(names.size(), 3); 0236 QCOMPARE(map.value("sub")->getParent(), map.value("test")->identifier()); 0237 }); 0238 VERIFYEXEC(job); 0239 } 0240 0241 void MailSyncTest::testListNewSubFolder() 0242 { 0243 if (!mCapabilities.contains(ResourceCapabilities::Mail::folderhierarchy)) { 0244 QSKIP("Missing capability mail.folderhierarchy"); 0245 } 0246 Sink::Query query; 0247 query.resourceFilter(mResourceInstanceIdentifier); 0248 query.request<Folder::Name>(); 0249 0250 createFolder(QStringList() << "test" << "sub1"); 0251 0252 // Ensure all local data is processed 0253 VERIFYEXEC(Store::synchronize(query)); 0254 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0255 0256 auto job = Store::fetchAll<Folder>(query).then([](const QList<Folder::Ptr> &folders) { 0257 QStringList names; 0258 for (const auto &folder : folders) { 0259 names << folder->getName(); 0260 } 0261 ASYNCVERIFY(names.contains("sub1")); 0262 return KAsync::null(); 0263 }); 0264 VERIFYEXEC(job); 0265 } 0266 0267 void MailSyncTest::testListRemovedSubFolder() 0268 { 0269 if (!mCapabilities.contains(ResourceCapabilities::Mail::folderhierarchy)) { 0270 QSKIP("Missing capability folder.hierarchy"); 0271 } 0272 Sink::Query query; 0273 query.resourceFilter(mResourceInstanceIdentifier); 0274 query.request<Folder::Name>(); 0275 0276 VERIFYEXEC(Store::synchronize(query)); 0277 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0278 0279 removeFolder(QStringList() << "test" << "sub1"); 0280 0281 // Ensure all local data is processed 0282 VERIFYEXEC(Store::synchronize(query)); 0283 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0284 0285 auto job = Store::fetchAll<Folder>(query).then([](const QList<Folder::Ptr> &folders) { 0286 QStringList names; 0287 for (const auto &folder : folders) { 0288 names << folder->getName(); 0289 } 0290 ASYNCVERIFY(!names.contains("sub1")); 0291 return KAsync::null(); 0292 }); 0293 VERIFYEXEC(job); 0294 } 0295 0296 void MailSyncTest::testListMails() 0297 { 0298 createMessage(QStringList() << "test", newMessage("This is a Subject.")); 0299 0300 Sink::Query query; 0301 query.resourceFilter(mResourceInstanceIdentifier); 0302 query.request<Mail::Subject>().request<Mail::MimeMessage>().request<Mail::Folder>().request<Mail::Date>(); 0303 0304 // Ensure all local data is processed 0305 VERIFYEXEC(Store::synchronize(query)); 0306 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0307 0308 auto job = Store::fetchAll<Mail>(query).then([](const QList<Mail::Ptr> &mails) { 0309 ASYNCCOMPARE(mails.size(), 1); 0310 auto mail = mails.first(); 0311 ASYNCVERIFY(mail->getSubject().startsWith(QString("This is a Subject."))); 0312 const auto data = mail->getMimeMessage(); 0313 ASYNCVERIFY(!data.isEmpty()); 0314 0315 KMime::Message m; 0316 m.setContent(KMime::CRLFtoLF(data)); 0317 m.parse(); 0318 ASYNCCOMPARE(mail->getSubject(), m.subject(true)->asUnicodeString()); 0319 ASYNCVERIFY(!mail->getFolder().isEmpty()); 0320 ASYNCVERIFY(mail->getDate().isValid()); 0321 return KAsync::null(); 0322 }); 0323 VERIFYEXEC(job); 0324 } 0325 0326 void MailSyncTest::testResyncMails() 0327 { 0328 Sink::Query query; 0329 query.resourceFilter(mResourceInstanceIdentifier); 0330 query.request<Mail::MimeMessage>(); 0331 query.request<Mail::Subject>(); 0332 0333 // Ensure all local data is processed 0334 VERIFYEXEC(Store::synchronize(query)); 0335 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0336 0337 // Ensure all local data is processed 0338 VERIFYEXEC(Store::synchronize(query)); 0339 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0340 0341 auto job = Store::fetchAll<Mail>(query).then([](const QList<Mail::Ptr> &mails) { 0342 ASYNCCOMPARE(mails.size(), 1); 0343 auto mail = mails.first(); 0344 ASYNCVERIFY(!mail->getSubject().isEmpty()); 0345 ASYNCVERIFY(!mail->getMimeMessage().isEmpty()); 0346 return KAsync::null(); 0347 }); 0348 VERIFYEXEC(job); 0349 } 0350 0351 void MailSyncTest::testFetchNewRemovedMessages() 0352 { 0353 Sink::Query query; 0354 query.resourceFilter(mResourceInstanceIdentifier); 0355 query.request<Mail::Subject>().request<Mail::MimeMessage>(); 0356 0357 // Ensure all local data is processed 0358 VERIFYEXEC(Store::synchronize(query)); 0359 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0360 0361 auto messageIdentifier = createMessage(QStringList() << "test", newMessage("Foobar")); 0362 0363 VERIFYEXEC(Store::synchronize(query)); 0364 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0365 0366 { 0367 auto job = Store::fetchAll<Mail>(query).then([](const QList<Mail::Ptr> &mails) { 0368 ASYNCCOMPARE(mails.size(), 2); 0369 return KAsync::null(); 0370 }); 0371 VERIFYEXEC(job); 0372 } 0373 0374 removeMessage(QStringList() << "test", messageIdentifier); 0375 0376 VERIFYEXEC(Store::synchronize(query)); 0377 VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); 0378 0379 { 0380 auto job = Store::fetchAll<Mail>(query).then([](const QList<Mail::Ptr> &mails) { 0381 ASYNCCOMPARE(mails.size(), 1); 0382 return KAsync::null(); 0383 }); 0384 VERIFYEXEC(job); 0385 } 0386 } 0387 0388 void MailSyncTest::testFlagChange() 0389 { 0390 Sink::Query syncScope; 0391 syncScope.resourceFilter(mResourceInstanceIdentifier); 0392 0393 Sink::Query query; 0394 query.resourceFilter(mResourceInstanceIdentifier); 0395 query.filter<Mail::Important>(true); 0396 query.filter<Mail::Folder>(Sink::Query{}.filter<Folder::Name>("test")); 0397 query.request<Mail::Subject>().request<Mail::Important>(); 0398 0399 auto messageIdentifier = createMessage(QStringList() << "test", newMessage("Foobar")); 0400 0401 VERIFYEXEC(Store::synchronize(syncScope)); 0402 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0403 0404 QCOMPARE(Store::read<Mail>(query).size(), 0); 0405 0406 markAsImportant(QStringList() << "test", messageIdentifier); 0407 0408 // Ensure all local data is processed 0409 VERIFYEXEC(Store::synchronize(syncScope)); 0410 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0411 0412 QCOMPARE(Store::read<Mail>(query).size(), 1); 0413 } 0414 0415 void MailSyncTest::testSyncSingleFolder() 0416 { 0417 VERIFYEXEC(Store::synchronize(Sink::SyncScope{ApplicationDomain::getTypeName<Folder>()}.resourceFilter(mResourceInstanceIdentifier))); 0418 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0419 0420 Folder::Ptr folder; 0421 { 0422 auto job = Store::fetchAll<Folder>(Sink::Query{}.resourceFilter(mResourceInstanceIdentifier).filter<Folder::Name>("test")).template then([&](const QList<Folder::Ptr> &folders) { 0423 ASYNCCOMPARE(folders.size(), 1); 0424 folder = folders.first(); 0425 return KAsync::null(); 0426 }); 0427 VERIFYEXEC(job); 0428 } 0429 0430 auto syncScope = Sink::SyncScope{ApplicationDomain::getTypeName<Mail>()}; 0431 syncScope.resourceFilter(mResourceInstanceIdentifier); 0432 syncScope.filter<Mail::Folder>(QVariant::fromValue(folder->identifier())); 0433 0434 // Ensure all local data is processed 0435 VERIFYEXEC(Store::synchronize(syncScope)); 0436 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0437 } 0438 0439 void MailSyncTest::testSyncSingleMail() 0440 { 0441 VERIFYEXEC(Store::synchronize(Sink::SyncScope{}.resourceFilter(mResourceInstanceIdentifier))); 0442 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0443 0444 Mail::Ptr mail; 0445 { 0446 auto job = Store::fetchAll<Mail>(Sink::Query{}.resourceFilter(mResourceInstanceIdentifier)).template then([&](const QList<Mail::Ptr> &mails) { 0447 ASYNCVERIFY(mails.size() >= 1); 0448 mail = mails.first(); 0449 return KAsync::null(); 0450 }); 0451 VERIFYEXEC(job); 0452 } 0453 QVERIFY(mail); 0454 0455 auto syncScope = Sink::SyncScope{ApplicationDomain::getTypeName<Mail>()}; 0456 syncScope.resourceFilter(mResourceInstanceIdentifier); 0457 syncScope.filter(mail->identifier()); 0458 0459 // Ensure all local data is processed 0460 VERIFYEXEC(Store::synchronize(syncScope)); 0461 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0462 } 0463 0464 void MailSyncTest::testSyncSingleMailWithBogusId() 0465 { 0466 VERIFYEXEC(Store::synchronize(Sink::SyncScope{}.resourceFilter(mResourceInstanceIdentifier))); 0467 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0468 0469 auto syncScope = Sink::SyncScope{ApplicationDomain::getTypeName<Mail>()}; 0470 syncScope.resourceFilter(mResourceInstanceIdentifier); 0471 syncScope.filter("WTFisThisEven?"); 0472 0473 // Ensure all local data is processed 0474 VERIFYEXEC(Store::synchronize(syncScope)); 0475 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0476 } 0477 0478 void MailSyncTest::testFailingSync() 0479 { 0480 auto resource = createFaultyResource(); 0481 QVERIFY(!resource.identifier().isEmpty()); 0482 VERIFYEXEC(Store::create(resource)); 0483 0484 Sink::Query query; 0485 query.resourceFilter(resource.identifier()); 0486 0487 bool errorReceived = false; 0488 0489 //Wait for the error notifiction 0490 auto notifier = QSharedPointer<Sink::Notifier>::create(resource.identifier()); 0491 notifier->registerHandler([&](const Notification ¬ification) { 0492 SinkTrace() << "Received notification " << notification; 0493 //Maildir detects misconfiguration, imap fails to connect 0494 if (notification.type == Sink::Notification::Error && 0495 (notification.code == ApplicationDomain::ConnectionError || 0496 notification.code == ApplicationDomain::ConfigurationError)) { 0497 errorReceived = true; 0498 } 0499 }); 0500 0501 VERIFYEXEC(Store::synchronize(query)); 0502 // Ensure sync fails if resource is misconfigured. We have to wait longer than the timeout in imapserverproxy 0503 QTRY_VERIFY_WITH_TIMEOUT(errorReceived, 10000); 0504 } 0505 0506 void MailSyncTest::testSyncUidvalidity() 0507 { 0508 createFolder({"uidvalidity"}); 0509 createMessage({"uidvalidity"}, newMessage("old")); 0510 0511 VERIFYEXEC(Store::synchronize(SyncScope{ApplicationDomain::getTypeName<Folder>()}.resourceFilter(mResourceInstanceIdentifier))); 0512 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0513 0514 auto folder = Store::readOne<Folder>(Query{}.resourceFilter(mResourceInstanceIdentifier).filter<Folder::Name>("uidvalidity")); 0515 0516 auto folderSyncScope = SyncScope{ApplicationDomain::getTypeName<Mail>()}; 0517 folderSyncScope.resourceFilter(mResourceInstanceIdentifier); 0518 folderSyncScope.filter<Mail::Folder>(QVariant::fromValue(folder.identifier())); 0519 VERIFYEXEC(Store::synchronize(folderSyncScope)); 0520 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0521 0522 0523 { 0524 Sink::Query query; 0525 query.resourceFilter(mResourceInstanceIdentifier); 0526 query.request<Mail::Subject>().request<Mail::MimeMessage>().request<Mail::Folder>().request<Mail::Date>(); 0527 query.filter<Mail::Folder>(folder); 0528 auto mails = Store::read<Mail>(query); 0529 QCOMPARE(mails.size(), 1); 0530 } 0531 0532 resetTestEnvironment(); 0533 0534 createFolder({"uidvalidity"}); 0535 createMessage({"uidvalidity"}, newMessage("new")); 0536 0537 // Ensure all local data is processed 0538 VERIFYEXEC(Store::synchronize(folderSyncScope)); 0539 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 0540 0541 //Now we should have one message 0542 auto folder2 = Store::readOne<Folder>(Query{}.resourceFilter(mResourceInstanceIdentifier).filter<Folder::Name>("uidvalidity")); 0543 Sink::Query query; 0544 query.resourceFilter(mResourceInstanceIdentifier); 0545 query.request<Mail::Subject>().request<Mail::MimeMessage>().request<Mail::Folder>().request<Mail::Date>(); 0546 query.filter<Mail::Folder>(folder2); 0547 auto mails = Store::read<Mail>(query); 0548 QCOMPARE(mails.size(), 1); 0549 QCOMPARE(mails.first().getSubject(), QLatin1String{"new"}); 0550 } 0551