File indexing completed on 2024-05-12 05:17:10

0001 /*
0002    SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0003    SPDX-FileContributor: Kevin Ottens <kevin@kdab.com>
0004 
0005    SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include <QTest>
0009 
0010 #include "kimap/idlejob.h"
0011 #include "kimap/selectjob.h"
0012 #include "kimap/session.h"
0013 #include "kimaptest/fakeserver.h"
0014 
0015 #include <QSignalSpy>
0016 #include <QTest>
0017 
0018 Q_DECLARE_METATYPE(QList<int>)
0019 Q_DECLARE_METATYPE(QList<qint64>)
0020 Q_DECLARE_METATYPE(KIMAP::IdleJob *)
0021 
0022 class IdleJobTest : public QObject
0023 {
0024     Q_OBJECT
0025 
0026 public:
0027     explicit IdleJobTest(QObject *parent = nullptr)
0028         : QObject(parent)
0029     {
0030         qRegisterMetaType<KIMAP::IdleJob *>();
0031     }
0032 
0033 private Q_SLOTS:
0034     void shouldReactToIdle_data()
0035     {
0036         QTest::addColumn<QList<QByteArray>>("scenario");
0037         QTest::addColumn<QString>("expectedMailBox");
0038         QTest::addColumn<QList<int>>("expectedMessageCounts");
0039         QTest::addColumn<QList<int>>("expectedRecentCounts");
0040         QTest::addColumn<QList<qint64>>("expectedFlagsNotifications");
0041 
0042         QList<QByteArray> scenario;
0043         QString expectedMailBox;
0044         QList<int> expectedMessageCounts;
0045         QList<int> expectedRecentCounts;
0046         QList<qint64> expectedFlagsNotifications;
0047 
0048         scenario.clear();
0049         scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX/Foo\""
0050                  << "S: A000001 OK SELECT done"
0051                  << "C: A000002 IDLE"
0052                  << "S: + OK"
0053                  << "S: * 0 RECENT"
0054                  << "S: * 1 EXISTS"
0055                  << "S: * 1 RECENT"
0056                  << "S: * 2 EXISTS"
0057                  << "S: A000002 OK done idling";
0058 
0059         expectedMailBox = QStringLiteral("INBOX/Foo");
0060 
0061         expectedMessageCounts.clear();
0062         expectedRecentCounts.clear();
0063 
0064         expectedMessageCounts << 1 << 2;
0065         expectedRecentCounts << 0 << 1;
0066 
0067         QTest::newRow("normal") << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts << expectedFlagsNotifications;
0068 
0069         scenario.clear();
0070         scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX/Foo\""
0071                  << "S: A000001 OK SELECT done"
0072                  << "C: A000002 IDLE"
0073                  << "S: + OK"
0074                  << "S: * 0 RECENT"
0075                  << "S: * 1 RECENT"
0076                  << "S: A000002 OK done idling";
0077 
0078         expectedMailBox = QStringLiteral("INBOX/Foo");
0079 
0080         expectedMessageCounts.clear();
0081         expectedRecentCounts.clear();
0082 
0083         expectedMessageCounts << -1 << -1;
0084         expectedRecentCounts << 0 << 1;
0085 
0086         QTest::newRow("only RECENT") << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts << expectedFlagsNotifications;
0087 
0088         scenario.clear();
0089         scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX/Foo\""
0090                  << "S: A000001 OK SELECT done"
0091                  << "C: A000002 IDLE"
0092                  << "S: + OK"
0093                  << "S: * 1 EXISTS"
0094                  << "S: * 2 EXISTS"
0095                  << "S: A000002 OK done idling";
0096 
0097         expectedMailBox = QStringLiteral("INBOX/Foo");
0098 
0099         expectedMessageCounts.clear();
0100         expectedRecentCounts.clear();
0101 
0102         expectedMessageCounts << 1 << 2;
0103         expectedRecentCounts << -1 << -1;
0104 
0105         QTest::newRow("only EXISTS") << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts << expectedFlagsNotifications;
0106 
0107         scenario.clear();
0108         scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX/Foo\""
0109                  << "S: A000001 OK SELECT done"
0110                  << "C: A000002 IDLE"
0111                  << "S: + OK"
0112                  << "S: * 2 EXISTS"
0113                  << "W: 150"
0114                  << "S: * 1 RECENT"
0115                  << "S: A000002 OK done idling";
0116 
0117         expectedMailBox = QStringLiteral("INBOX/Foo");
0118 
0119         expectedMessageCounts.clear();
0120         expectedRecentCounts.clear();
0121 
0122         expectedMessageCounts << 2;
0123         expectedRecentCounts << 1;
0124 
0125         QTest::newRow("under 200ms, same notification")
0126             << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts << expectedFlagsNotifications;
0127 
0128         scenario.clear();
0129         scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX/Foo\""
0130                  << "S: A000001 OK SELECT done"
0131                  << "C: A000002 IDLE"
0132                  << "S: + OK"
0133                  << "S: * 2 EXISTS"
0134                  << "W: 250"
0135                  << "S: * 1 RECENT"
0136                  << "S: A000002 OK done idling";
0137 
0138         expectedMailBox = QStringLiteral("INBOX/Foo");
0139 
0140         expectedMessageCounts.clear();
0141         expectedRecentCounts.clear();
0142 
0143         expectedMessageCounts << 2 << -1;
0144         expectedRecentCounts << -1 << 1;
0145 
0146         QTest::newRow("above 200ms, two notifications")
0147             << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts << expectedFlagsNotifications;
0148 
0149         scenario.clear();
0150         scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX/Foo\""
0151                  << "S: A000001 OK SELECT done"
0152                  << "C: A000002 IDLE"
0153                  << "S: + OK"
0154                  << "S: * 1 FETCH (FLAGS ())"
0155                  << "W: 200"
0156                  << "S: * 2 FETCH (FLAGS (\\Seen))"
0157                  << "S: A000002 OK done idling";
0158 
0159         expectedMailBox = QStringLiteral("INBOX/Foo");
0160 
0161         expectedMessageCounts.clear();
0162         expectedRecentCounts.clear();
0163         expectedFlagsNotifications << 1 << 2;
0164 
0165         QTest::newRow("2 flags change notifications") << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts
0166                                                       << expectedFlagsNotifications;
0167     }
0168 
0169     void shouldReactToIdle()
0170     {
0171         QFETCH(QList<QByteArray>, scenario);
0172         QFETCH(QString, expectedMailBox);
0173         QFETCH(QList<int>, expectedMessageCounts);
0174         QFETCH(QList<int>, expectedRecentCounts);
0175         QFETCH(QList<qint64>, expectedFlagsNotifications);
0176 
0177         QVERIFY(expectedMessageCounts.size() == expectedRecentCounts.size());
0178 
0179         FakeServer fakeServer;
0180         fakeServer.setScenario(scenario);
0181         fakeServer.startAndWait();
0182 
0183         KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989);
0184 
0185         auto select = new KIMAP::SelectJob(&session);
0186         select->setMailBox(expectedMailBox);
0187         QVERIFY(select->exec());
0188 
0189         auto idle = new KIMAP::IdleJob(&session);
0190 
0191         QSignalSpy statsSpy(idle, &KIMAP::IdleJob::mailBoxStats);
0192         QSignalSpy flagsSpy(idle, &KIMAP::IdleJob::mailBoxMessageFlagsChanged);
0193 
0194         bool result = idle->exec();
0195 
0196         if (result) {
0197             QCOMPARE(statsSpy.count(), expectedMessageCounts.size());
0198             QCOMPARE(flagsSpy.count(), expectedFlagsNotifications.size());
0199 
0200             for (int i = 0; i < statsSpy.count(); i++) {
0201                 const KIMAP::IdleJob *job = statsSpy.at(i).at(0).value<KIMAP::IdleJob *>();
0202                 const QString mailBox = statsSpy.at(i).at(1).toString();
0203                 const int messageCount = statsSpy.at(i).at(2).toInt();
0204                 const int recentCount = statsSpy.at(i).at(3).toInt();
0205 
0206                 QCOMPARE(job, idle);
0207                 QCOMPARE(mailBox, expectedMailBox);
0208                 QCOMPARE(messageCount, expectedMessageCounts.at(i));
0209                 QCOMPARE(recentCount, expectedRecentCounts.at(i));
0210             }
0211 
0212             for (int i = 0; i < flagsSpy.count(); i++) {
0213                 const KIMAP::IdleJob *job = flagsSpy.at(i).at(0).value<KIMAP::IdleJob *>();
0214                 const qint64 uid = flagsSpy.at(i).at(1).toLongLong();
0215 
0216                 QCOMPARE(job, idle);
0217                 QCOMPARE(uid, expectedFlagsNotifications.at(i));
0218             }
0219         }
0220 
0221         fakeServer.quit();
0222     }
0223 
0224     void shouldResetTimeout_data()
0225     {
0226         QTest::addColumn<QList<QByteArray>>("scenario");
0227         {
0228             QList<QByteArray> scenario;
0229             scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\""
0230                      << "S: A000001 OK SELECT done"
0231                      << "C: A000002 IDLE"
0232                      << "S: + OK"
0233                      << "S: A000002 OK done idling";
0234 
0235             QTest::newRow("good") << scenario;
0236         }
0237 
0238         {
0239             QList<QByteArray> scenario;
0240             scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\""
0241                      << "S: A000001 OK SELECT done"
0242                      << "C: A000002 IDLE"
0243                      << "S: + OK"
0244                      << "X";
0245 
0246             QTest::newRow("bad") << scenario;
0247         }
0248     }
0249 
0250     void shouldResetTimeout()
0251     {
0252         QFETCH(QList<QByteArray>, scenario);
0253 
0254         FakeServer fakeServer;
0255         fakeServer.setScenario(scenario);
0256         fakeServer.startAndWait();
0257 
0258         KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989);
0259         const int originalTimeout = session.timeout();
0260 
0261         auto select = new KIMAP::SelectJob(&session);
0262         select->setMailBox(QStringLiteral("INBOX"));
0263         QVERIFY(select->exec());
0264 
0265         auto idle = new KIMAP::IdleJob(&session);
0266         idle->exec();
0267 
0268         QCOMPARE(session.timeout(), originalTimeout);
0269 
0270         fakeServer.quit();
0271     }
0272 };
0273 
0274 QTEST_GUILESS_MAIN(IdleJobTest)
0275 
0276 #include "idlejobtest.moc"