File indexing completed on 2023-10-03 03:15:39
0001 /* 0002 This file is part of the KDE libraries 0003 0004 SPDX-FileCopyrightText: 2009 David Faure <faure@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include <kdirwatch.h> 0010 0011 #include <QDebug> 0012 #include <QDir> 0013 #include <QFileInfo> 0014 #include <QTest> 0015 #include <QThread> 0016 0017 #include "kcoreaddons_debug.h" 0018 0019 class StaticObject 0020 { 0021 public: 0022 KDirWatch m_dirWatch; 0023 }; 0024 Q_GLOBAL_STATIC(StaticObject, s_staticObject) 0025 0026 class StaticObjectUsingSelf // like KSambaShare does, bug 353080 0027 { 0028 public: 0029 StaticObjectUsingSelf() 0030 { 0031 KDirWatch::self(); 0032 } 0033 ~StaticObjectUsingSelf() 0034 { 0035 if (KDirWatch::exists() && KDirWatch::self()->contains(QDir::homePath())) { 0036 KDirWatch::self()->removeDir(QDir::homePath()); 0037 } 0038 } 0039 }; 0040 Q_GLOBAL_STATIC(StaticObjectUsingSelf, s_staticObjectUsingSelf) 0041 0042 namespace KDirWatchTestUtils 0043 { 0044 // Just to make the inotify packets bigger 0045 static const char s_filePrefix[] = "This_is_a_test_file_"; 0046 0047 static const char *methodToString(KDirWatch::Method method) 0048 { 0049 switch (method) { 0050 case KDirWatch::FAM: 0051 return "Fam"; 0052 case KDirWatch::INotify: 0053 return "INotify"; 0054 case KDirWatch::Stat: 0055 return "Stat"; 0056 case KDirWatch::QFSWatch: 0057 return "QFSWatch"; 0058 } 0059 return "ERROR!"; 0060 } 0061 0062 // helper method: create a file 0063 inline void createFile(const QString &path, bool slow = false) 0064 { 0065 QFile file(path); 0066 QVERIFY(file.open(QIODevice::WriteOnly)); 0067 #ifdef Q_OS_FREEBSD 0068 // FreeBSD has inotify implemented as user-space library over native kevent API. 0069 // When using it, one has to open() a file to start watching it, so workaround 0070 // test breakage by giving inotify time to react to file creation. 0071 // Full context: https://github.com/libinotify-kqueue/libinotify-kqueue/issues/10 0072 if (!slow) { 0073 QThread::msleep(1); 0074 } 0075 #else 0076 Q_UNUSED(slow) 0077 #endif 0078 file.write(QByteArray("foo")); 0079 file.close(); 0080 } 0081 0082 inline int createDirectoryTree(const QString &basePath, int depth = 4) 0083 { 0084 int filesCreated = 0; 0085 0086 const int numFiles = 10; 0087 for (int i = 0; i < numFiles; ++i) { 0088 createFile(basePath + QLatin1Char('/') + QLatin1String(s_filePrefix) + QString::number(i)); 0089 ++filesCreated; 0090 } 0091 0092 if (depth <= 0) { 0093 return filesCreated; 0094 } 0095 0096 const int numFolders = 5; 0097 for (int i = 0; i < numFolders; ++i) { 0098 const QString childPath = basePath + QLatin1String("/subdir") + QString::number(i); 0099 QDir().mkdir(childPath); 0100 filesCreated += createDirectoryTree(childPath, depth - 1); 0101 } 0102 0103 return filesCreated; 0104 } 0105 0106 inline void waitUntilAfter(const QDateTime &ctime) 0107 { 0108 int totalWait = 0; 0109 QDateTime now; 0110 Q_FOREVER { 0111 now = QDateTime::currentDateTime(); 0112 if (now.toMSecsSinceEpoch() / 1000 == ctime.toMSecsSinceEpoch() / 1000) // truncate milliseconds 0113 { 0114 totalWait += 50; 0115 QTest::qWait(50); 0116 } else { 0117 QVERIFY(now > ctime); // can't go back in time ;) 0118 QTest::qWait(50); // be safe 0119 break; 0120 } 0121 } 0122 // if (totalWait > 0) 0123 qCDebug(KCOREADDONS_DEBUG) << "Waited" << totalWait << "ms so that now" << now.toString(Qt::ISODate) << "is >" << ctime.toString(Qt::ISODate); 0124 } 0125 inline void waitUntilMTimeChange(const QString &path) 0126 { 0127 // Wait until the current second is more than the file's mtime 0128 // otherwise this change will go unnoticed 0129 0130 QFileInfo fi(path); 0131 QVERIFY(fi.exists()); 0132 const QDateTime ctime = fi.lastModified(); 0133 waitUntilAfter(ctime); 0134 } 0135 0136 inline void waitUntilNewSecond() 0137 { 0138 QDateTime now = QDateTime::currentDateTime(); 0139 waitUntilAfter(now); 0140 } 0141 0142 }