File indexing completed on 2024-04-28 15:20:07

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 }