File indexing completed on 2024-04-28 03:51:41
0001 /* 0002 SPDX-FileCopyrightText: 2010 Sebastian Trueg <trueg at kde.org> 0003 SPDX-FileCopyrightText: 2014 Vishesh Handa <vhanda@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "kinotify.h" 0009 0010 #include <QTemporaryDir> 0011 #include <KRandom> 0012 0013 #include <QTextStream> 0014 #include <QFile> 0015 #include <QSignalSpy> 0016 #include <QDir> 0017 #include <QTest> 0018 0019 #include <stdio.h> 0020 0021 class KInotifyTest : public QObject 0022 { 0023 Q_OBJECT 0024 0025 private Q_SLOTS: 0026 void testDeleteFile(); 0027 void testDeleteFolder(); 0028 void testCreateFolder(); 0029 void testRenameFile(); 0030 void testRenameDeleteFile(); 0031 void testMoveFile(); 0032 void testRenameFolder(); 0033 void testMoveFolder(); 0034 void testMoveFromUnwatchedFolder(); 0035 void testMoveToUnwatchedFolder(); 0036 void testMoveRootFolder(); 0037 void testFileClosedAfterWrite(); 0038 0039 void init(); 0040 0041 private: 0042 std::unique_ptr<QTemporaryDir> m_tmpDir; 0043 QDir m_dir; 0044 std::unique_ptr<KInotify> m_kn; 0045 }; 0046 0047 namespace 0048 { 0049 void touchFile(const QString& path) 0050 { 0051 QFile file(path); 0052 file.open(QIODevice::WriteOnly); 0053 QTextStream s(&file); 0054 s << KRandom::randomString(10); 0055 } 0056 0057 void mkdir(const QString& path) 0058 { 0059 QDir().mkpath(path); 0060 QVERIFY(QDir(path).exists()); 0061 } 0062 } 0063 0064 void KInotifyTest::init() 0065 { 0066 m_tmpDir = std::make_unique<QTemporaryDir>(); 0067 0068 const QString subDir(QStringLiteral("%1/subdir/").arg(m_tmpDir->path())); 0069 mkdir(subDir); 0070 m_dir = QDir(subDir); 0071 0072 m_kn = std::make_unique<KInotify>(nullptr); 0073 QVERIFY(m_kn->addWatch(m_dir.path(), KInotify::EventAll)); 0074 0075 QSignalSpy kiSpy(m_kn.get(), &KInotify::installedWatches); 0076 QVERIFY(kiSpy.count() || kiSpy.wait()); 0077 } 0078 0079 void KInotifyTest::testDeleteFile() 0080 { 0081 // create some test files 0082 const QString f1(QStringLiteral("%1/randomJunk1").arg(m_dir.path())); 0083 touchFile(f1); 0084 0085 // listen to the desired signal 0086 QSignalSpy spy(m_kn.get(), &KInotify::deleted); 0087 0088 // test removing a file 0089 QFile::remove(f1); 0090 QVERIFY(spy.wait()); 0091 QCOMPARE(spy.count(), 1); 0092 QCOMPARE(spy.takeFirst().at(0).toString(), f1); 0093 } 0094 0095 void KInotifyTest::testDeleteFolder() 0096 { 0097 const QString d1(QStringLiteral("%1/").arg(m_dir.path())); 0098 0099 // listen to the desired signal 0100 QSignalSpy spy(m_kn.get(), &KInotify::deleted); 0101 0102 // test removing a folder 0103 QVERIFY(QDir().rmdir(d1)); 0104 QVERIFY(spy.wait()); 0105 QCOMPARE(spy.count(), 1); 0106 QCOMPARE(spy.first().at(0).toString(), d1); 0107 QCOMPARE(spy.first().at(1).toBool(), true); 0108 // make sure we do not watch the removed folder anymore 0109 QVERIFY(!m_kn->watchingPath(d1)); 0110 } 0111 0112 void KInotifyTest::testCreateFolder() 0113 { 0114 // listen to the desired signal 0115 QSignalSpy createdSpy(m_kn.get(), &KInotify::created); 0116 0117 // create the subdir 0118 const QString d1(QStringLiteral("%1/randomJunk1/").arg(m_dir.path())); 0119 mkdir(d1); 0120 QVERIFY(createdSpy.wait()); 0121 QCOMPARE(createdSpy.count(), 1); 0122 QCOMPARE(createdSpy.takeFirst().at(0).toString(), d1); 0123 QVERIFY(m_kn->watchingPath(d1)); 0124 0125 // lets go one level deeper 0126 const QString d2 = QStringLiteral("%1subdir1/").arg(d1); 0127 mkdir(d2); 0128 QVERIFY(createdSpy.wait()); 0129 QCOMPARE(createdSpy.count(), 1); 0130 QCOMPARE(createdSpy.takeFirst().at(0).toString(), d2); 0131 QVERIFY(m_kn->watchingPath(d2)); 0132 0133 // although we are in the folder test lets try creating a file 0134 const QString f1 = QStringLiteral("%1somefile1").arg(d2); 0135 touchFile(f1); 0136 QVERIFY(createdSpy.wait()); 0137 QCOMPARE(createdSpy.count(), 1); 0138 QCOMPARE(createdSpy.takeFirst().at(0).toString(), f1); 0139 } 0140 0141 void KInotifyTest::testRenameFile() 0142 { 0143 // create some test files 0144 const QString f1(QStringLiteral("%1/randomJunk1").arg(m_dir.path())); 0145 touchFile(f1); 0146 0147 // listen to the desired signal 0148 QSignalSpy spy(m_kn.get(), &KInotify::moved); 0149 0150 // actually move the file 0151 const QString f2(QStringLiteral("%1/randomJunk2").arg(m_dir.path())); 0152 rename(f1.toLocal8Bit().constData(), f2.toLocal8Bit().constData()); 0153 0154 // check the desired signal 0155 QVERIFY(spy.wait()); 0156 QCOMPARE(spy.count(), 1); 0157 QList<QVariant> args = spy.takeFirst(); 0158 QCOMPARE(args.at(0).toString(), f1); 0159 QCOMPARE(args.at(1).toString(), f2); 0160 0161 // test a subsequent rename 0162 const QString f3(QStringLiteral("%1/randomJunk3").arg(m_dir.path())); 0163 rename(f2.toLocal8Bit().constData(), f3.toLocal8Bit().constData()); 0164 0165 // check the desired signal 0166 QVERIFY(spy.wait()); 0167 QCOMPARE(spy.count(), 1); 0168 args = spy.takeFirst(); 0169 QCOMPARE(args.at(0).toString(), f2); 0170 QCOMPARE(args.at(1).toString(), f3); 0171 } 0172 0173 void KInotifyTest::testRenameDeleteFile() 0174 { 0175 // create some test files 0176 const QString f1(QStringLiteral("%1/randomJunk1").arg(m_dir.path())); 0177 touchFile(f1); 0178 0179 // listen to the desired signal 0180 QSignalSpy spy(m_kn.get(), &KInotify::moved); 0181 0182 // actually move the file 0183 const QString f2(QStringLiteral("%1/randomJunk2").arg(m_dir.path())); 0184 rename(f1.toLocal8Bit().constData(), f2.toLocal8Bit().constData()); 0185 0186 // check the desired signal 0187 QVERIFY(spy.wait()); 0188 QCOMPARE(spy.count(), 1); 0189 QList<QVariant> args = spy.takeFirst(); 0190 QCOMPARE(args.at(0).toString(), f1); 0191 QCOMPARE(args.at(1).toString(), f2); 0192 0193 // test a subsequent delete 0194 QSignalSpy spy1(m_kn.get(), &KInotify::deleted); 0195 QFile::remove(f2); 0196 0197 // check the desired signal 0198 QVERIFY(spy1.wait()); 0199 QCOMPARE(spy1.count(), 1); 0200 QCOMPARE(spy1.takeFirst().at(0).toString(), f2); 0201 0202 QVERIFY(spy.isEmpty()); 0203 } 0204 0205 void KInotifyTest::testMoveFile() 0206 { 0207 // create some test files 0208 QTemporaryDir destDir; 0209 const QString src(QStringLiteral("%1/randomJunk1").arg(m_dir.path())); 0210 const QString dest(QStringLiteral("%1/randomJunk2").arg(destDir.path())); 0211 touchFile(src); 0212 0213 // Add another path without common parent to the watcher 0214 QSignalSpy knSpy(m_kn.get(), &KInotify::installedWatches); 0215 m_kn->addWatch(destDir.path(), KInotify::EventAll); 0216 QVERIFY(knSpy.count() || knSpy.wait()); 0217 0218 // listen to the desired signal 0219 QSignalSpy spy(m_kn.get(), &KInotify::moved); 0220 0221 // actually move the file 0222 rename(src.toLocal8Bit().constData(), dest.toLocal8Bit().constData()); 0223 0224 // check the desired signal 0225 QVERIFY(spy.wait()); 0226 QCOMPARE(spy.count(), 1); 0227 QList<QVariant> args = spy.takeFirst(); 0228 QCOMPARE(args.at(0).toString(), src); 0229 QCOMPARE(args.at(1).toString(), dest); 0230 0231 // test a subsequent move (back to the original folder) 0232 const QString dest2(QStringLiteral("%1/randomJunk3").arg(m_dir.path())); 0233 rename(dest.toLocal8Bit().constData(), dest2.toLocal8Bit().constData()); 0234 0235 // check the desired signal 0236 QVERIFY(spy.wait()); 0237 QCOMPARE(spy.count(), 1); 0238 args = spy.takeFirst(); 0239 QCOMPARE(args.at(0).toString(), dest); 0240 QCOMPARE(args.at(1).toString(), dest2); 0241 } 0242 0243 void KInotifyTest::testRenameFolder() 0244 { 0245 // create some test files 0246 const QString d1(QStringLiteral("%1/randomJunk1/").arg(m_dir.path())); 0247 mkdir(d1); 0248 0249 { 0250 QSignalSpy spy(m_kn.get(), &KInotify::created); 0251 QVERIFY(spy.wait()); 0252 } 0253 0254 // listen to the desired signal 0255 QSignalSpy spy(m_kn.get(), &KInotify::moved); 0256 0257 // actually rename the folder 0258 const QString d2(QStringLiteral("%1/randomJunk2/").arg(m_dir.path())); 0259 rename(d1.toLocal8Bit().constData(), d2.toLocal8Bit().constData()); 0260 0261 // check the desired signal 0262 QVERIFY(spy.wait()); 0263 QCOMPARE(spy.count(), 1); 0264 QList<QVariant> args = spy.takeFirst(); 0265 QCOMPARE(args.at(0).toString(), d1); 0266 QCOMPARE(args.at(1).toString(), d2); 0267 0268 // check the path cache 0269 QVERIFY(!m_kn->watchingPath(d1)); 0270 QVERIFY(m_kn->watchingPath(d2)); 0271 0272 // test a subsequent rename 0273 const QString d3(QStringLiteral("%1/randomJunk3/").arg(m_dir.path())); 0274 rename(d2.toLocal8Bit().constData(), d3.toLocal8Bit().constData()); 0275 0276 // check the desired signal 0277 QVERIFY(spy.wait()); 0278 QCOMPARE(spy.count(), 1); 0279 args = spy.takeFirst(); 0280 QCOMPARE(args.at(0).toString(), d2); 0281 QCOMPARE(args.at(1).toString(), d3); 0282 0283 // check the path cache 0284 QVERIFY(!m_kn->watchingPath(d1)); 0285 QVERIFY(!m_kn->watchingPath(d2)); 0286 QVERIFY(m_kn->watchingPath(d3)); 0287 0288 // KInotify claims it has updated its data structures, lets see if that is true 0289 // by creating a file in the new folder 0290 // listen to the desired signal 0291 const QString f4(QStringLiteral("%1somefile").arg(d3)); 0292 0293 QSignalSpy createdSpy(m_kn.get(), &KInotify::created); 0294 0295 // test creating a file 0296 touchFile(f4); 0297 0298 QVERIFY(createdSpy.wait()); 0299 QCOMPARE(createdSpy.count(), 1); 0300 QCOMPARE(createdSpy.takeFirst().at(0).toString(), f4); 0301 } 0302 0303 void KInotifyTest::testMoveFolder() 0304 { 0305 // create some test files 0306 QTemporaryDir destDir; 0307 const QString src(QStringLiteral("%1/randomJunk1/").arg(m_dir.path())); 0308 const QString dest(QStringLiteral("%1/randomJunk2/").arg(destDir.path())); 0309 mkdir(src); 0310 0311 // Add another path without common parent to the watcher 0312 QSignalSpy knSpy(m_kn.get(), &KInotify::installedWatches); 0313 m_kn->addWatch(destDir.path(), KInotify::EventAll); 0314 QVERIFY(knSpy.count() || knSpy.wait()); 0315 0316 // listen to the desired signal 0317 QSignalSpy spy(m_kn.get(), &KInotify::moved); 0318 0319 // actually move the file 0320 rename(src.toLocal8Bit().constData(), dest.toLocal8Bit().constData()); 0321 0322 // check the desired signal 0323 QVERIFY(spy.wait()); 0324 QCOMPARE(spy.count(), 1); 0325 QList<QVariant> args = spy.takeFirst(); 0326 QCOMPARE(args.at(0).toString(), src); 0327 QCOMPARE(args.at(1).toString(), dest); 0328 0329 // check the path cache 0330 QVERIFY(!m_kn->watchingPath(src)); 0331 QVERIFY(m_kn->watchingPath(dest)); 0332 0333 // test a subsequent move 0334 const QString dest2(QStringLiteral("%1/randomJunk3/").arg(m_dir.path())); 0335 rename(dest.toLocal8Bit().constData(), dest2.toLocal8Bit().constData()); 0336 0337 // check the desired signal 0338 QVERIFY(spy.wait()); 0339 QCOMPARE(spy.count(), 1); 0340 args = spy.takeFirst(); 0341 QCOMPARE(args.at(0).toString(), dest); 0342 QCOMPARE(args.at(1).toString(), dest2); 0343 0344 // check the path cache 0345 QVERIFY(!m_kn->watchingPath(src)); 0346 QVERIFY(!m_kn->watchingPath(dest)); 0347 QVERIFY(m_kn->watchingPath(dest2)); 0348 0349 // KInotify claims it has updated its data structures, lets see if that is true 0350 // by creating a file in the new folder 0351 // listen to the desired signal 0352 const QString f4(QStringLiteral("%1somefile").arg(dest2)); 0353 0354 QSignalSpy createdSpy(m_kn.get(), &KInotify::created); 0355 0356 // test creating a file 0357 touchFile(f4); 0358 0359 QVERIFY(createdSpy.wait()); 0360 QCOMPARE(createdSpy.count(), 1); 0361 QCOMPARE(createdSpy.takeFirst().at(0).toString(), f4); 0362 } 0363 0364 void KInotifyTest::testMoveFromUnwatchedFolder() 0365 { 0366 // create unwatched source folder 0367 QTemporaryDir srcDir; 0368 const QString src{srcDir.path()}; 0369 const QString dest{m_dir.path()}; 0370 0371 QSignalSpy spy(m_kn.get(), &KInotify::created); 0372 0373 // Create stuff inside src 0374 mkdir(QStringLiteral("%1/sub").arg(src)); 0375 touchFile(QStringLiteral("%1/sub/file1").arg(src)); 0376 mkdir(QStringLiteral("%1/sub/sub1").arg(src)); 0377 touchFile(QStringLiteral("%1/sub/sub1/file2").arg(src)); 0378 0379 // Now move 0380 QFile::rename(QStringLiteral("%1/sub").arg(src), 0381 QStringLiteral("%1/sub").arg(dest)); 0382 0383 QVERIFY(spy.wait()); 0384 QCOMPARE(spy.count(), 4); 0385 0386 // Checking if watches are installed 0387 QSignalSpy spy1(m_kn.get(), &KInotify::deleted); 0388 QDir dstdir(QStringLiteral("%1/sub").arg(dest)); 0389 dstdir.removeRecursively(); 0390 0391 QVERIFY(spy1.wait()); 0392 QCOMPARE(spy1.count(), 4); 0393 } 0394 0395 void KInotifyTest::testMoveToUnwatchedFolder() 0396 { 0397 // create unwatched destination folder 0398 QTemporaryDir destDir; 0399 const QString src{m_dir.path()}; 0400 const QString dest{destDir.path()}; 0401 0402 QSignalSpy spy(m_kn.get(), &KInotify::created); 0403 0404 // Create stuff inside src 0405 mkdir(QStringLiteral("%1/sub").arg(src)); 0406 touchFile(QStringLiteral("%1/sub/file1").arg(src)); 0407 touchFile(QStringLiteral("%1/file2").arg(src)); 0408 0409 QVERIFY(spy.wait()); 0410 QCOMPARE(spy.count(), 3); 0411 0412 // Move file 0413 QFile::rename(QStringLiteral("%1/file2").arg(src), 0414 QStringLiteral("%1/file2").arg(dest)); 0415 0416 QSignalSpy spy1(m_kn.get(), &KInotify::deleted); 0417 QVERIFY(spy1.wait()); 0418 QCOMPARE(spy1.count(), 1); 0419 0420 // Move dir 0421 QFile::rename(QStringLiteral("%1/sub").arg(src), 0422 QStringLiteral("%1/sub").arg(dest)); 0423 0424 QVERIFY(spy1.wait()); 0425 QCOMPARE(spy1.count(), 2); 0426 } 0427 0428 void KInotifyTest::testMoveRootFolder() 0429 { 0430 // listen for the moved signal 0431 QSignalSpy spy(m_kn.get(), &KInotify::moved); 0432 0433 // Rename the watched root directory 0434 const QString src(QStringLiteral("%1/").arg(m_dir.path())); 0435 const QString dest(QStringLiteral("%1/newname/").arg(m_tmpDir->path())); 0436 QFile::rename(src, dest); 0437 0438 // check the desired signal 0439 QEXPECT_FAIL("", "KInotify cannot handle moving of top-level folders.", Abort); 0440 QVERIFY(spy.wait(500)); 0441 QCOMPARE(spy.count(), 1); 0442 QList<QVariant> args = spy.takeFirst(); 0443 QCOMPARE(args.at(0).toString(), src); 0444 QCOMPARE(args.at(1).toString(), dest); 0445 0446 // check the path cache 0447 QVERIFY(!m_kn->watchingPath(src)); 0448 QVERIFY(m_kn->watchingPath(dest)); 0449 } 0450 0451 void KInotifyTest::testFileClosedAfterWrite() 0452 { 0453 QSignalSpy spy(m_kn.get(), &KInotify::closedWrite); 0454 touchFile(m_dir.path() + QLatin1String("/file")); 0455 0456 QVERIFY(spy.wait()); 0457 QCOMPARE(spy.count(), 1); 0458 QCOMPARE(spy.at(0).first().toString(), QString(m_dir.path() + QLatin1String("/file"))); 0459 } 0460 0461 QTEST_GUILESS_MAIN(KInotifyTest) 0462 0463 #include "kinotifytest.moc"