File indexing completed on 2024-04-21 03:53:38

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 }