File indexing completed on 2024-04-28 03:51:41
0001 /* 0002 This file is part of the KDE Baloo project. 0003 SPDX-FileCopyrightText: 2011 Sebastian Trueg <trueg@kde.org> 0004 SPDX-FileCopyrightText: 2013-2014 Vishesh Handa <vhanda@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "pendingfilequeue.h" 0010 0011 #include <QTest> 0012 #include <QSignalSpy> 0013 #include <qtimer.h> 0014 0015 namespace Baloo { 0016 0017 class PendingFileQueueTest : public QObject 0018 { 0019 Q_OBJECT 0020 0021 public: 0022 PendingFileQueueTest(); 0023 0024 private Q_SLOTS: 0025 void testTimers(); 0026 void testTimeout(); 0027 void testRequeue(); 0028 void testDeleteCreate(); 0029 void testCreateDelete(); 0030 void testCreateDelete2(); 0031 }; 0032 0033 PendingFileQueueTest::PendingFileQueueTest() 0034 { 0035 } 0036 0037 class TimerEventEater : public QObject 0038 { 0039 Q_OBJECT 0040 0041 public: 0042 TimerEventEater(QObject* parent = nullptr) : QObject(parent) {} 0043 0044 protected: 0045 bool eventFilter(QObject *object, QEvent *event) override { 0046 Q_UNUSED(object); 0047 Q_UNUSED(event); 0048 return true; 0049 } 0050 }; 0051 0052 void PendingFileQueueTest::testTimers() 0053 { 0054 QString myUrl(QStringLiteral("/tmp")); 0055 0056 PendingFileQueue queue; 0057 queue.setMinimumTimeout(1); 0058 queue.setTrackingTime(1); 0059 0060 QSignalSpy spy(&queue, SIGNAL(indexModifiedFile(QString))); 0061 QVERIFY(spy.isValid()); 0062 0063 PendingFile file(myUrl); 0064 file.setModified(); 0065 queue.enqueue(file); 0066 0067 // The signal should be emitted immediately 0068 QVERIFY(spy.wait(50)); 0069 QCOMPARE(spy.count(), 1); 0070 QCOMPARE(spy.takeFirst().constFirst().toString(), myUrl); 0071 QCOMPARE(queue.m_recentlyEmitted.count(), 1); 0072 0073 // Enqueue the url again. This time it should wait for should wait for the 0074 // minimumTimeout 0075 queue.enqueue(file); 0076 0077 QTest::qWait(100); 0078 QCOMPARE(queue.m_pendingFiles.count(), 1); 0079 QCOMPARE(queue.m_recentlyEmitted.count(), 1); 0080 QVERIFY(spy.isEmpty()); 0081 0082 QVERIFY(spy.wait(1500)); 0083 QCOMPARE(spy.count(), 1); 0084 QCOMPARE(spy.takeFirst().constFirst().toString(), myUrl); 0085 QCOMPARE(queue.m_pendingFiles.count(), 0); 0086 QCOMPARE(queue.m_recentlyEmitted.count(), 1); 0087 0088 // Wait for Tracking Time 0089 QTest::qWait(1500); 0090 QCOMPARE(queue.m_recentlyEmitted.count(), 0); 0091 } 0092 0093 void PendingFileQueueTest::testTimeout() 0094 { 0095 QString file1Url(QStringLiteral("file1_url")); 0096 QString file2Url(QStringLiteral("file2_url")); 0097 0098 QTime currentTime = QTime::currentTime(); 0099 0100 PendingFileQueue queue; 0101 queue.setMinimumTimeout(2); 0102 0103 auto eventEater = new TimerEventEater(this); 0104 queue.m_cacheTimer.installEventFilter(eventEater); 0105 queue.m_clearRecentlyEmittedTimer.installEventFilter(eventEater); 0106 queue.m_pendingFilesTimer.installEventFilter(eventEater); 0107 0108 QSignalSpy spy(&queue, SIGNAL(indexModifiedFile(QString))); 0109 QVERIFY(spy.isValid()); 0110 0111 PendingFile file1(file1Url); 0112 PendingFile file2(file2Url); 0113 file1.setModified(); 0114 file2.setModified(); 0115 0116 // Enqueue, and process the event queue 0117 queue.enqueue(file1); 0118 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0119 0120 // The signal should be emitted immediately 0121 QVERIFY(spy.wait()); 0122 QCOMPARE(spy.count(), 1); 0123 QCOMPARE(spy.takeFirst().constFirst().toString(), file1Url); 0124 0125 // Enqueue file1 again, and also file2. This time, only file2 0126 // should be signaled immediately 0127 queue.enqueue(file1); 0128 queue.enqueue(file2); 0129 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0130 0131 QVERIFY(spy.wait(50)); 0132 QCOMPARE(spy.count(), 1); 0133 QCOMPARE(spy.takeFirst().constFirst().toString(), file2Url); 0134 0135 // Advance time 1.5 seconds, and let the pending queue be processed. 0136 // Nothing should be signaled, as the timeout is 2 seconds 0137 currentTime = currentTime.addMSecs(1500); 0138 QTimer::singleShot(0, [&queue, currentTime] { queue.processPendingFiles(currentTime); }); 0139 QVERIFY(!spy.wait(50)); 0140 0141 currentTime = currentTime.addMSecs(1000); 0142 QTimer::singleShot(0, [&queue, currentTime] { queue.processPendingFiles(currentTime); }); 0143 QVERIFY(spy.wait(0)); 0144 QCOMPARE(spy.count(), 1); 0145 QCOMPARE(spy.takeFirst().constFirst().toString(), file1Url); 0146 } 0147 0148 void PendingFileQueueTest::testRequeue() 0149 { 0150 QString myUrl(QStringLiteral("/tmp")); 0151 0152 QTime currentTime = QTime::currentTime(); 0153 0154 PendingFileQueue queue; 0155 queue.setMinimumTimeout(2); 0156 queue.setMaximumTimeout(5); 0157 0158 auto eventEater = new TimerEventEater(this); 0159 queue.m_cacheTimer.installEventFilter(eventEater); 0160 queue.m_clearRecentlyEmittedTimer.installEventFilter(eventEater); 0161 queue.m_pendingFilesTimer.installEventFilter(eventEater); 0162 0163 QSignalSpy spy(&queue, SIGNAL(indexModifiedFile(QString))); 0164 QVERIFY(spy.isValid()); 0165 0166 PendingFile file(myUrl); 0167 file.setModified(); 0168 queue.enqueue(file); 0169 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0170 0171 // The signal should be emitted immediately 0172 QVERIFY(spy.wait()); 0173 QCOMPARE(spy.count(), 1); 0174 QCOMPARE(spy.takeFirst().constFirst().toString(), myUrl); 0175 0176 // Send many events. The first one should enqueue it with the minimumTimeout, and each 0177 // successive one should double the timeout up to maxTimeout 0178 for (int i = 0; i < 3; i++) { 0179 queue.enqueue(file); 0180 currentTime = currentTime.addMSecs(20); 0181 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0182 spy.wait(0); 0183 } 0184 0185 // Signal should be emitted after 5 seconds (min(2 * 2 * 2, maxTimeout)) 0186 int elapsed10thSeconds = 0; 0187 while (true) { 0188 currentTime = currentTime.addMSecs(100); 0189 QTimer::singleShot(0, [&queue, currentTime] { queue.processPendingFiles(currentTime); }); 0190 if (spy.wait(0)) { 0191 break; 0192 } 0193 QVERIFY2(elapsed10thSeconds <= 50, "Signal emitted late"); 0194 elapsed10thSeconds++; 0195 } 0196 QVERIFY2(elapsed10thSeconds > 40, "Signal emitted early"); 0197 0198 QCOMPARE(spy.count(), 1); 0199 QCOMPARE(spy.takeFirst().constFirst().toString(), myUrl); 0200 } 0201 0202 void PendingFileQueueTest::testDeleteCreate() 0203 { 0204 QString myUrl(QStringLiteral("/dir/testfile")); 0205 0206 QTime currentTime = QTime::currentTime(); 0207 0208 PendingFileQueue queue; 0209 0210 auto eventEater = new TimerEventEater(this); 0211 queue.m_cacheTimer.installEventFilter(eventEater); 0212 queue.m_clearRecentlyEmittedTimer.installEventFilter(eventEater); 0213 queue.m_pendingFilesTimer.installEventFilter(eventEater); 0214 0215 QSignalSpy spyModified(&queue, SIGNAL(indexModifiedFile(QString))); 0216 QSignalSpy spyRemoved(&queue, SIGNAL(removeFileIndex(QString))); 0217 QVERIFY(spyModified.isValid()); 0218 QVERIFY(spyRemoved.isValid()); 0219 0220 PendingFile file1(myUrl); 0221 PendingFile file2(myUrl); 0222 file1.setDeleted(); 0223 file2.setModified(); 0224 0225 queue.enqueue(file1); 0226 queue.enqueue(file2); 0227 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0228 0229 // The signals should be emitted immediately 0230 QVERIFY(spyModified.wait()); 0231 0232 QCOMPARE(spyRemoved.count(), 1); 0233 QCOMPARE(spyRemoved.takeFirst().constFirst().toString(), myUrl); 0234 0235 QCOMPARE(spyModified.count(), 1); 0236 QCOMPARE(spyModified.takeFirst().constFirst().toString(), myUrl); 0237 } 0238 0239 void PendingFileQueueTest::testCreateDelete() 0240 { 0241 QString myUrl(QStringLiteral("/dir/testfile")); 0242 0243 QTime currentTime = QTime::currentTime(); 0244 0245 PendingFileQueue queue; 0246 0247 auto eventEater = new TimerEventEater(this); 0248 queue.m_cacheTimer.installEventFilter(eventEater); 0249 queue.m_clearRecentlyEmittedTimer.installEventFilter(eventEater); 0250 queue.m_pendingFilesTimer.installEventFilter(eventEater); 0251 0252 QSignalSpy spyModified(&queue, SIGNAL(indexModifiedFile(QString))); 0253 QSignalSpy spyRemoved(&queue, SIGNAL(removeFileIndex(QString))); 0254 QVERIFY(spyModified.isValid()); 0255 QVERIFY(spyRemoved.isValid()); 0256 0257 // Actually same file, just different events 0258 PendingFile file_modified(myUrl); 0259 PendingFile file_delete(myUrl); 0260 file_modified.setModified(); 0261 file_delete.setDeleted(); 0262 0263 QTimer::singleShot(0, [&] { 0264 queue.enqueue(file_modified); 0265 queue.enqueue(file_delete); 0266 }); 0267 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0268 0269 // The Removed signal should be emitted immediately 0270 QVERIFY(spyRemoved.wait()); 0271 0272 // The Modified signal should be suppressed 0273 QCOMPARE(spyModified.count(), 0); 0274 0275 QCOMPARE(spyRemoved.count(), 1); 0276 QCOMPARE(spyRemoved.takeFirst().constFirst().toString(), myUrl); 0277 } 0278 0279 void PendingFileQueueTest::testCreateDelete2() 0280 { 0281 QString myUrl(QStringLiteral("/dir/testfile")); 0282 0283 QTime currentTime = QTime::currentTime(); 0284 0285 PendingFileQueue queue; 0286 0287 auto eventEater = new TimerEventEater(this); 0288 queue.m_cacheTimer.installEventFilter(eventEater); 0289 queue.m_clearRecentlyEmittedTimer.installEventFilter(eventEater); 0290 queue.m_pendingFilesTimer.installEventFilter(eventEater); 0291 0292 QSignalSpy spyModified(&queue, SIGNAL(indexModifiedFile(QString))); 0293 QSignalSpy spyRemoved(&queue, SIGNAL(removeFileIndex(QString))); 0294 QVERIFY(spyModified.isValid()); 0295 QVERIFY(spyRemoved.isValid()); 0296 0297 PendingFile file_modified(myUrl); 0298 PendingFile file_delete(myUrl); 0299 file_modified.setModified(); 0300 file_delete.setDeleted(); 0301 0302 // Prime the recent files list 0303 queue.enqueue(file_modified); 0304 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0305 QVERIFY(spyModified.wait()); 0306 QCOMPARE(spyModified.count(), 1); 0307 QCOMPARE(spyModified.takeFirst().constFirst().toString(), myUrl); 0308 QCOMPARE(queue.m_recentlyEmitted.count(), 1); 0309 0310 // Modify the file again 0311 QTimer::singleShot(0, [&] { queue.enqueue(file_modified); }); 0312 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0313 // Process the timer, the file should be pending now 0314 QTest::qWait(10); 0315 QCOMPARE(queue.m_pendingFiles.count(), 1); 0316 0317 // Let 5 seconds pass (minimum pending timeout) 0318 currentTime = currentTime.addMSecs(5000); 0319 QTimer::singleShot(0, [&] { queue.enqueue(file_delete); }); 0320 // The "process" timer fires 10ms after the enqueue, plenty of time for the pending timer to fire 0321 QTimer::singleShot(0, [&queue, currentTime] { queue.processPendingFiles(currentTime); }); 0322 currentTime = currentTime.addMSecs(10); 0323 QTimer::singleShot(0, [&queue, currentTime] { queue.processCache(currentTime); }); 0324 0325 // The Removed signal should be emitted immediately 0326 QVERIFY(spyRemoved.wait()); 0327 QCOMPARE(spyRemoved.count(), 1); 0328 QCOMPARE(spyRemoved.takeFirst().constFirst().toString(), myUrl); 0329 0330 // The Modified signal should be suppressed, the file no longer be pending 0331 QCOMPARE(spyModified.count(), 0); 0332 QCOMPARE(queue.m_pendingFiles.count(), 0); 0333 } 0334 0335 } // namespace 0336 0337 QTEST_GUILESS_MAIN(Baloo::PendingFileQueueTest) 0338 0339 #include "pendingfilequeuetest.moc"