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 &notification) {
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