File indexing completed on 2024-05-12 05:17:12
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2008 Kevin Ottens <ervin@kde.org> 0004 0005 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com> 0006 SPDX-FileContributor: Kevin Ottens <kevin@kdab.com> 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #include <QEventLoop> 0012 #include <QObject> 0013 #include <QSignalSpy> 0014 #include <QTest> 0015 0016 #include "job.h" 0017 #include "kimaptest/fakeserver.h" 0018 #include "kimaptest/mockjob.h" 0019 #include "session.h" 0020 0021 Q_DECLARE_METATYPE(KIMAP::Session::State) 0022 Q_DECLARE_METATYPE(KJob *) 0023 0024 class SessionTest : public QObject 0025 { 0026 Q_OBJECT 0027 0028 private Q_SLOTS: 0029 0030 void initTestCase() 0031 { 0032 qRegisterMetaType<KIMAP::Session::State>(); 0033 } 0034 0035 void shouldStartDisconnected() 0036 { 0037 FakeServer fakeServer; 0038 fakeServer.setScenario(QList<QByteArray>() << FakeServer::greeting()); 0039 fakeServer.startAndWait(); 0040 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0041 QSignalSpy spy(&s, &KIMAP::Session::stateChanged); 0042 QCOMPARE((int)s.state(), (int)KIMAP::Session::Disconnected); 0043 QTest::qWait(600); 0044 QCOMPARE((int)s.state(), (int)KIMAP::Session::NotAuthenticated); 0045 QCOMPARE(spy.count(), 1); // NotAuthenticated 0046 QList<QVariant> arguments = spy.takeFirst(); 0047 QCOMPARE((int)qvariant_cast<KIMAP::Session::State>(arguments.at(0)), (int)KIMAP::Session::NotAuthenticated); 0048 QCOMPARE((int)qvariant_cast<KIMAP::Session::State>(arguments.at(1)), (int)KIMAP::Session::Disconnected); 0049 } 0050 0051 void shouldFailForInvalidHosts() 0052 { 0053 KIMAP::Session s(QStringLiteral("0.0.0.0"), 1234); 0054 s.setTimeout(1); // 1 second timeout 0055 0056 QSignalSpy spyFail(&s, &KIMAP::Session::connectionFailed); 0057 QSignalSpy spyLost(&s, &KIMAP::Session::connectionLost); 0058 QSignalSpy spyState(&s, &KIMAP::Session::stateChanged); 0059 0060 QCOMPARE((int)s.state(), (int)KIMAP::Session::Disconnected); 0061 0062 QTest::qWait(500); 0063 QCOMPARE((int)s.state(), (int)KIMAP::Session::Disconnected); 0064 QCOMPARE(spyFail.count(), 1); 0065 QCOMPARE(spyLost.count(), 0); 0066 QCOMPARE(spyState.count(), 0); 0067 0068 // Wait 800ms more. So now it's 1.3 seconds, check that the socket timeout has correctly been 0069 // disabled, and that it hadn't fired unexpectedly. 0070 QTest::qWait(800); 0071 QCOMPARE(spyFail.count(), 1); 0072 } 0073 0074 /** 0075 Checks that the timeout works when the connection succeeds, but the server doesn't sends anything 0076 back to the client. This could happen for example if we connected to a non-IMAP server. 0077 */ 0078 void shouldTimeoutOnNoGreeting() 0079 { 0080 FakeServer fakeServer; 0081 fakeServer.setScenario(QList<QByteArray>()); 0082 fakeServer.startAndWait(); 0083 0084 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0085 s.setTimeout(2); 0086 QSignalSpy spyFail(&s, &KIMAP::Session::connectionFailed); 0087 QSignalSpy spyLost(&s, &KIMAP::Session::connectionLost); 0088 QSignalSpy spyState(&s, &KIMAP::Session::stateChanged); 0089 QCOMPARE((int)s.state(), (int)KIMAP::Session::Disconnected); 0090 0091 // Wait 1.8 second. Since the timeout is set to 2 seconds, the socket should be still 0092 // disconnected at this point, yet the connectionFailed() signal shouldn't have been emitted. 0093 QTest::qWait(1800); 0094 QCOMPARE((int)s.state(), (int)KIMAP::Session::Disconnected); 0095 QCOMPARE(spyFail.count(), 0); 0096 QCOMPARE(spyLost.count(), 0); 0097 QCOMPARE(spyState.count(), 0); 0098 0099 // Wait 0.5 second more. Now we are at 2.3 seconds, the socket should have timed out, and the 0100 // connectionFailed() signal should have been emitted. 0101 QTest::qWait(500); 0102 QCOMPARE((int)s.state(), (int)KIMAP::Session::Disconnected); 0103 QCOMPARE(spyFail.count(), 0); 0104 QCOMPARE(spyLost.count(), 1); 0105 QCOMPARE(spyState.count(), 0); 0106 } 0107 0108 void shouldSupportPreauth() 0109 { 0110 FakeServer fakeServer; 0111 fakeServer.setScenario(QList<QByteArray>() << FakeServer::preauth()); 0112 fakeServer.startAndWait(); 0113 0114 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0115 QSignalSpy spy(&s, &KIMAP::Session::stateChanged); 0116 QCOMPARE((int)s.state(), (int)KIMAP::Session::Disconnected); 0117 QTest::qWait(500); 0118 QCOMPARE((int)s.state(), (int)KIMAP::Session::Authenticated); 0119 QCOMPARE(spy.count(), 1); // Authenticated 0120 QList<QVariant> arguments = spy.takeFirst(); 0121 QCOMPARE((int)qvariant_cast<KIMAP::Session::State>(arguments.at(0)), (int)KIMAP::Session::Authenticated); 0122 QCOMPARE((int)qvariant_cast<KIMAP::Session::State>(arguments.at(1)), (int)KIMAP::Session::Disconnected); 0123 } 0124 0125 void shouldRespectStartOrder() 0126 { 0127 FakeServer fakeServer; 0128 fakeServer.setScenario(QList<QByteArray>() << FakeServer::greeting()); 0129 fakeServer.startAndWait(); 0130 0131 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0132 auto j1 = new MockJob(&s); 0133 connect(j1, &KJob::result, this, &SessionTest::jobDone); 0134 auto j2 = new MockJob(&s); 0135 connect(j2, &KJob::result, this, &SessionTest::jobDone); 0136 auto j3 = new MockJob(&s); 0137 connect(j3, &KJob::result, this, &SessionTest::jobDone); 0138 auto j4 = new MockJob(&s); 0139 connect(j4, &KJob::result, this, &SessionTest::jobDone); 0140 0141 j4->start(); 0142 j2->start(); 0143 j3->start(); 0144 j1->start(); 0145 0146 m_expectedCalls = 4; 0147 m_eventLoop.exec(); 0148 0149 QCOMPARE(m_jobs.size(), 4); 0150 QCOMPARE(m_jobs[0], j4); 0151 QCOMPARE(m_jobs[1], j2); 0152 QCOMPARE(m_jobs[2], j3); 0153 QCOMPARE(m_jobs[3], j1); 0154 } 0155 0156 void shouldManageQueueSize() 0157 { 0158 FakeServer fakeServer; 0159 fakeServer.setScenario(QList<QByteArray>() << FakeServer::greeting()); 0160 fakeServer.startAndWait(); 0161 0162 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0163 0164 QSignalSpy queueSpy(&s, &KIMAP::Session::jobQueueSizeChanged); 0165 0166 QCOMPARE(s.jobQueueSize(), 0); 0167 0168 auto j1 = new MockJob(&s); 0169 auto j2 = new MockJob(&s); 0170 auto j3 = new MockJob(&s); 0171 auto j4 = new MockJob(&s); 0172 connect(j4, &KJob::result, &m_eventLoop, &QEventLoop::quit); 0173 0174 QCOMPARE(s.jobQueueSize(), 0); 0175 0176 j1->start(); 0177 QCOMPARE(s.jobQueueSize(), 1); 0178 QCOMPARE(queueSpy.size(), 1); 0179 QCOMPARE(queueSpy.at(0).at(0).toInt(), 1); 0180 0181 j2->start(); 0182 QCOMPARE(s.jobQueueSize(), 2); 0183 QCOMPARE(queueSpy.size(), 2); 0184 QCOMPARE(queueSpy.at(1).at(0).toInt(), 2); 0185 0186 j3->start(); 0187 QCOMPARE(s.jobQueueSize(), 3); 0188 QCOMPARE(queueSpy.size(), 3); 0189 QCOMPARE(queueSpy.at(2).at(0).toInt(), 3); 0190 0191 j4->start(); 0192 QCOMPARE(s.jobQueueSize(), 4); 0193 QCOMPARE(queueSpy.size(), 4); 0194 QCOMPARE(queueSpy.at(3).at(0).toInt(), 4); 0195 0196 queueSpy.clear(); 0197 m_eventLoop.exec(); 0198 0199 QCOMPARE(s.jobQueueSize(), 0); 0200 0201 QCOMPARE(queueSpy.at(0).at(0).toInt(), 3); 0202 QCOMPARE(queueSpy.at(1).at(0).toInt(), 2); 0203 QCOMPARE(queueSpy.at(2).at(0).toInt(), 1); 0204 QCOMPARE(queueSpy.at(3).at(0).toInt(), 0); 0205 } 0206 0207 void shouldTimeoutOnNoReply() 0208 { 0209 FakeServer fakeServer; 0210 fakeServer.setScenario(QList<QByteArray>() << FakeServer::preauth() << "C: A000001 DUMMY" 0211 << "S: * DUMMY" 0212 << "S: * DUMMY" 0213 << "S: * DUMMY" 0214 << "S: * DUMMY" 0215 << "S: * DUMMY" 0216 << "S: * DUMMY" 0217 << "S: * DUMMY" 0218 << "S: * DUMMY" 0219 << "S: * DUMMY" 0220 << "S: * DUMMY" 0221 << "S: * DUMMY" 0222 << "S: * DUMMY" 0223 << "S: * DUMMY" 0224 // We never get a OK or anything, so the job can't normally complete 0225 ); 0226 fakeServer.startAndWait(); 0227 0228 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0229 0230 QSignalSpy spyFail(&s, &KIMAP::Session::connectionFailed); 0231 QSignalSpy spyLost(&s, &KIMAP::Session::connectionLost); 0232 QSignalSpy spyState(&s, &KIMAP::Session::stateChanged); 0233 0234 auto mock = new MockJob(&s); 0235 mock->setCommand("DUMMY"); 0236 0237 mock->exec(); 0238 // We expect to get an error here due to some timeout 0239 QVERIFY(mock->error() != 0); 0240 QCOMPARE(spyFail.count(), 0); 0241 QCOMPARE(spyLost.count(), 1); 0242 QCOMPARE(spyState.count(), 2); // Authenticated, Disconnected 0243 } 0244 0245 void shouldFailFirstJobOnConnectionFailed() 0246 { 0247 qRegisterMetaType<KJob *>(); 0248 0249 FakeServer fakeServer; 0250 fakeServer.setScenario(QList<QByteArray>()); 0251 fakeServer.startAndWait(); 0252 0253 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0254 s.setTimeout(1); 0255 0256 auto j1 = new MockJob(&s); 0257 QSignalSpy spyResult1(j1, &KJob::result); 0258 QSignalSpy spyDestroyed1(j1, &QObject::destroyed); 0259 0260 auto j2 = new MockJob(&s); 0261 QSignalSpy spyResult2(j2, &KJob::result); 0262 QSignalSpy spyDestroyed2(j2, &QObject::destroyed); 0263 0264 auto j3 = new MockJob(&s); 0265 QSignalSpy spyResult3(j3, &KJob::result); 0266 QSignalSpy spyDestroyed3(j3, &QObject::destroyed); 0267 0268 j1->start(); 0269 j2->start(); 0270 j3->start(); 0271 0272 QCOMPARE(s.jobQueueSize(), 3); 0273 0274 QTest::qWait(1100); 0275 0276 // Check that only the first job has emitted it's result 0277 QCOMPARE(spyResult1.count(), 1); 0278 QCOMPARE(spyResult2.count(), 0); 0279 QCOMPARE(spyResult3.count(), 0); 0280 0281 // Check that all jobs have been deleted 0282 QCOMPARE(spyDestroyed1.count(), 1); 0283 QCOMPARE(spyDestroyed2.count(), 1); 0284 QCOMPARE(spyDestroyed3.count(), 1); 0285 0286 QCOMPARE(s.jobQueueSize(), 0); 0287 } 0288 0289 void shouldCloseOnInconsistency() 0290 { 0291 for (int count = 0; count < 10; count++) { 0292 FakeServer fakeServer; 0293 fakeServer.setScenario(QList<QByteArray>() << FakeServer::preauth() << "C: A000001 DUMMY" 0294 << "S: * DUMMY %" 0295 << "S: DUMMY)"); 0296 fakeServer.startAndWait(); 0297 0298 KIMAP::Session s(QStringLiteral("127.0.0.1"), 5989); 0299 0300 QSignalSpy spyFail(&s, &KIMAP::Session::connectionFailed); 0301 QSignalSpy spyLost(&s, &KIMAP::Session::connectionLost); 0302 QSignalSpy spyState(&s, &KIMAP::Session::stateChanged); 0303 0304 auto mock = new MockJob(&s); 0305 mock->setTimeout(5000); 0306 mock->setCommand("DUMMY"); 0307 0308 mock->setAutoDelete(false); 0309 mock->start(); 0310 QTest::qWait(250); // Should be plenty 0311 0312 // We expect to get an error here due to the inconsistency 0313 QVERIFY(mock->error() != 0); 0314 QCOMPARE(spyFail.count(), 0); 0315 QCOMPARE(spyLost.count(), 1); 0316 QCOMPARE(spyState.count(), 2); // Authenticated, Disconnected 0317 0318 delete mock; 0319 } 0320 } 0321 0322 public Q_SLOTS: 0323 void jobDone(KJob *job) 0324 { 0325 m_jobs << job; 0326 0327 if (m_expectedCalls == m_jobs.size()) { 0328 m_eventLoop.quit(); 0329 } 0330 } 0331 0332 private: 0333 QEventLoop m_eventLoop; 0334 int m_expectedCalls; 0335 QList<KJob *> m_jobs; 0336 }; 0337 0338 QTEST_GUILESS_MAIN(SessionTest) 0339 0340 #include "testsession.moc"