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