File indexing completed on 2024-09-15 03:37:20
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::INotify: 0051 return "INotify"; 0052 case KDirWatch::Stat: 0053 return "Stat"; 0054 case KDirWatch::QFSWatch: 0055 return "QFSWatch"; 0056 } 0057 return "ERROR!"; 0058 } 0059 0060 // helper method: create a file 0061 inline void createFile(const QString &path, bool slow = false) 0062 { 0063 QFile file(path); 0064 QVERIFY(file.open(QIODevice::WriteOnly)); 0065 #ifdef Q_OS_FREEBSD 0066 // FreeBSD has inotify implemented as user-space library over native kevent API. 0067 // When using it, one has to open() a file to start watching it, so workaround 0068 // test breakage by giving inotify time to react to file creation. 0069 // Full context: https://github.com/libinotify-kqueue/libinotify-kqueue/issues/10 0070 if (!slow) { 0071 QThread::msleep(1); 0072 } 0073 #else 0074 Q_UNUSED(slow) 0075 #endif 0076 file.write(QByteArray("foo")); 0077 file.close(); 0078 } 0079 0080 inline int createDirectoryTree(const QString &basePath, int depth = 4) 0081 { 0082 int filesCreated = 0; 0083 0084 const int numFiles = 10; 0085 for (int i = 0; i < numFiles; ++i) { 0086 createFile(basePath + QLatin1Char('/') + QLatin1String(s_filePrefix) + QString::number(i)); 0087 ++filesCreated; 0088 } 0089 0090 if (depth <= 0) { 0091 return filesCreated; 0092 } 0093 0094 const int numFolders = 5; 0095 for (int i = 0; i < numFolders; ++i) { 0096 const QString childPath = basePath + QLatin1String("/subdir") + QString::number(i); 0097 QDir().mkdir(childPath); 0098 filesCreated += createDirectoryTree(childPath, depth - 1); 0099 } 0100 0101 return filesCreated; 0102 } 0103 0104 inline void waitUntilAfter(const QDateTime &ctime) 0105 { 0106 int totalWait = 0; 0107 QDateTime now; 0108 Q_FOREVER { 0109 now = QDateTime::currentDateTime(); 0110 if (now.toMSecsSinceEpoch() / 1000 == ctime.toMSecsSinceEpoch() / 1000) // truncate milliseconds 0111 { 0112 totalWait += 50; 0113 QTest::qWait(50); 0114 } else { 0115 QVERIFY(now > ctime); // can't go back in time ;) 0116 QTest::qWait(50); // be safe 0117 break; 0118 } 0119 } 0120 // if (totalWait > 0) 0121 qCDebug(KCOREADDONS_DEBUG) << "Waited" << totalWait << "ms so that now" << now.toString(Qt::ISODate) << "is >" << ctime.toString(Qt::ISODate); 0122 } 0123 inline void waitUntilMTimeChange(const QString &path) 0124 { 0125 // Wait until the current second is more than the file's mtime 0126 // otherwise this change will go unnoticed 0127 0128 QFileInfo fi(path); 0129 QVERIFY(fi.exists()); 0130 const QDateTime ctime = fi.lastModified(); 0131 waitUntilAfter(ctime); 0132 } 0133 0134 inline void waitUntilNewSecond() 0135 { 0136 QDateTime now = QDateTime::currentDateTime(); 0137 waitUntilAfter(now); 0138 } 0139 0140 }