From 0f0d8a5a8fecf545cdf58ab50d05253ffd20e90b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 14 Feb 2012 15:52:49 +0100 Subject: Stabilize QFileSystemWatcher test. - Run each test in a temporary directory, avoid writing test files in source/build tree and prevents tests being influenced by left-overs from previous runs and locks of the application on the current directory. - Modify test to be able to use absolute paths to the temporary directory. - Skip parts of test removeFileAndUnWatch if a race condition occurs. Task-number: QTBUG-24029 Change-Id: I215cc2e0fe6f92d2ffe597b01cdc9c9a39e3c5b4 Reviewed-by: Robin Burchell --- .../io/qfilesystemwatcher/qfilesystemwatcher.pro | 1 - .../qfilesystemwatcher/tst_qfilesystemwatcher.cpp | 103 ++++++++++++++------- 2 files changed, 69 insertions(+), 35 deletions(-) (limited to 'tests/auto/corelib/io') diff --git a/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro b/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro index 043b2b5d1d..e712a6ad5f 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro +++ b/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro @@ -4,4 +4,3 @@ QT = core testlib SOURCES = tst_qfilesystemwatcher.cpp mac: CONFIG += insignificant_test # QTBUG-22744 -win32:CONFIG += insignificant_test # QTBUG-24029 diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp index 5e5a99f937..2635565c2b 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp +++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -42,6 +42,7 @@ #include +#include #include #ifdef Q_OS_LINUX @@ -52,9 +53,15 @@ # endif #endif +/* All tests need to run in temporary directories not used + * by the application to avoid non-deterministic failures on Windows + * due to locked directories and left-overs from previous tests. */ + class tst_QFileSystemWatcher : public QObject { Q_OBJECT +public: + tst_QFileSystemWatcher(); private slots: void basicTest_data(); @@ -75,11 +82,20 @@ private slots: void removeFileAndUnWatch(); - void cleanup(); - void destroyAfterQCoreApplication(); + +private: + QString m_tempDirPattern; }; +tst_QFileSystemWatcher::tst_QFileSystemWatcher() +{ + m_tempDirPattern = QDir::tempPath(); + if (!m_tempDirPattern.endsWith(QLatin1Char('/'))) + m_tempDirPattern += QLatin1Char('/'); + m_tempDirPattern += QStringLiteral("tst_qfilesystemwatcherXXXXXX"); +} + void tst_QFileSystemWatcher::basicTest_data() { QTest::addColumn("backend"); @@ -92,7 +108,9 @@ void tst_QFileSystemWatcher::basicTest() QFETCH(QString, backend); // create test file - QFile testFile("testfile.txt"); + QTemporaryDir temporaryDirectory(m_tempDirPattern); + QVERIFY(temporaryDirectory.isValid()); + QFile testFile(temporaryDirectory.path() + QStringLiteral("/testfile.txt")); testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner); testFile.remove(); QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); @@ -151,14 +169,16 @@ void tst_QFileSystemWatcher::basicTest() QCOMPARE(changedSpy.count(), 0); // readd the file watch with a relative path - QVERIFY(watcher.addPath(testFile.fileName().prepend("./"))); + const QString relativeTestFileName = QDir::current().relativeFilePath(testFile.fileName()); + QVERIFY(!relativeTestFileName.isEmpty()); + QVERIFY(watcher.addPath(relativeTestFileName)); testFile.open(QIODevice::WriteOnly | QIODevice::Truncate); testFile.write(QByteArray("hello multiverse!")); testFile.close(); QTRY_VERIFY(changedSpy.count() > 0); - QVERIFY(watcher.removePath(testFile.fileName().prepend("./"))); + QVERIFY(watcher.removePath(relativeTestFileName)); changedSpy.clear(); @@ -222,15 +242,21 @@ void tst_QFileSystemWatcher::watchDirectory() { QFETCH(QString, backend); - QDir().mkdir("testDir"); - QDir testDir("testDir"); + QTemporaryDir temporaryDirectory(m_tempDirPattern); + QVERIFY(temporaryDirectory.isValid()); + + QDir temporaryDir(temporaryDirectory.path()); + const QString testDirName = QStringLiteral("testDir"); + QVERIFY(temporaryDir.mkdir(testDirName)); + QDir testDir = temporaryDir; + QVERIFY(testDir.cd(testDirName)); QString testFileName = testDir.filePath("testFile.txt"); QFile::remove(testFileName); QFileSystemWatcher watcher; watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); - QVERIFY(watcher.addPath(testDir.dirName())); + QVERIFY(watcher.addPath(testDir.absolutePath())); QSignalSpy changedSpy(&watcher, SIGNAL(directoryChanged(const QString &))); QVERIFY(changedSpy.isValid()); @@ -246,7 +272,7 @@ void tst_QFileSystemWatcher::watchDirectory() QString fileName; // remove the watch, should not get notification of a new file - QVERIFY(watcher.removePath(testDir.dirName())); + QVERIFY(watcher.removePath(testDir.absolutePath())); QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); testFile.close(); @@ -256,7 +282,7 @@ void tst_QFileSystemWatcher::watchDirectory() QCOMPARE(changedSpy.count(), 0); - QVERIFY(watcher.addPath(testDir.dirName())); + QVERIFY(watcher.addPath(testDir.absolutePath())); // remove the file again, should get a signal from the watcher QVERIFY(testFile.remove()); @@ -265,7 +291,7 @@ void tst_QFileSystemWatcher::watchDirectory() eventLoop.exec(); // remove the directory, should get a signal from the watcher - QVERIFY(QDir().rmdir("testDir")); + QVERIFY(temporaryDir.rmdir(testDirName)); // waiting max 5 seconds for notification for directory removal to trigger #ifdef Q_OS_WINCE @@ -276,15 +302,16 @@ void tst_QFileSystemWatcher::watchDirectory() QCOMPARE(changedSpy.at(1).count(), 1); fileName = changedSpy.at(0).at(0).toString(); - QCOMPARE(fileName, testDir.dirName()); + QCOMPARE(fileName, testDir.absolutePath()); fileName = changedSpy.at(1).at(0).toString(); - QCOMPARE(fileName, testDir.dirName()); + QCOMPARE(fileName, testDir.absolutePath()); changedSpy.clear(); // recreate the file, we should not get any notification - if (!QDir().mkdir("testDir")) - QSKIP("Failed to recreate directory, skipping final test."); + if (!temporaryDir.mkdir(testDirName)) + QSKIP(qPrintable(QString::fromLatin1("Failed to recreate directory '%1' under '%2', skipping final test."). + arg(testDirName, temporaryDir.absolutePath()))); // waiting max 5 seconds for notification for dir recreation to trigger timer.start(5000); @@ -292,7 +319,7 @@ void tst_QFileSystemWatcher::watchDirectory() QCOMPARE(changedSpy.count(), 0); - QVERIFY(QDir().rmdir("testDir")); + QVERIFY(temporaryDir.rmdir(testDirName)); } void tst_QFileSystemWatcher::addPath() @@ -360,8 +387,15 @@ void tst_QFileSystemWatcher::removePaths() void tst_QFileSystemWatcher::watchFileAndItsDirectory() { QFETCH(QString, backend); - QDir().mkdir("testDir"); - QDir testDir("testDir"); + + QTemporaryDir temporaryDirectory(m_tempDirPattern); + QVERIFY(temporaryDirectory.isValid()); + + QDir temporaryDir(temporaryDirectory.path()); + const QString testDirName = QStringLiteral("testDir"); + QVERIFY(temporaryDir.mkdir(testDirName)); + QDir testDir = temporaryDir; + QVERIFY(testDir.cd(testDirName)); QString testFileName = testDir.filePath("testFile.txt"); QString secondFileName = testDir.filePath("testFile2.txt"); @@ -378,7 +412,7 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QFileSystemWatcher watcher; watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); - QVERIFY(watcher.addPath(testDir.dirName())); + QVERIFY(watcher.addPath(testDir.absolutePath())); QVERIFY(watcher.addPath(testFileName)); QSignalSpy fileChangedSpy(&watcher, SIGNAL(fileChanged(const QString &))); @@ -443,17 +477,7 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QCOMPARE(fileChangedSpy.count(), 0); QCOMPARE(dirChangedSpy.count(), 1); - QVERIFY(QDir().rmdir("testDir")); -} - -void tst_QFileSystemWatcher::cleanup() -{ - QDir testDir("testDir"); - QString testFileName = testDir.filePath("testFile.txt"); - QString secondFileName = testDir.filePath("testFile2.txt"); - QFile::remove(testFileName); - QFile::remove(secondFileName); - QDir().rmdir("testDir"); + QVERIFY(temporaryDir.rmdir(testDirName)); } void tst_QFileSystemWatcher::nonExistingFile() @@ -475,22 +499,33 @@ void tst_QFileSystemWatcher::nonExistingFile() void tst_QFileSystemWatcher::removeFileAndUnWatch() { - static const char * const filename = "foo.txt"; + QTemporaryDir temporaryDirectory(m_tempDirPattern); + QVERIFY(temporaryDirectory.isValid()); + + const QString filename = temporaryDirectory.path() + QStringLiteral("/foo.txt"); + QFileSystemWatcher watcher; { QFile testFile(filename); - testFile.open(QIODevice::WriteOnly); + QVERIFY2(testFile.open(QIODevice::WriteOnly), + qPrintable(QString::fromLatin1("Cannot open %1 for writing: %2").arg(filename, testFile.errorString()))); testFile.close(); } QVERIFY(watcher.addPath(filename)); QFile::remove(filename); - QVERIFY(watcher.removePath(filename)); + /* There are potential race conditions here; the watcher thread might remove the file from its list + * before the call to watcher.removePath(), which then fails. When that happens, the auto-signal + * notification to remove the file from the watcher's main list will not be delivered before the next + * event loop such that the call to watcher.addPath() fails since the file is still in the main list. */ + if (!watcher.removePath(filename)) + QSKIP("Skipping remaining test due to race condition."); { QFile testFile(filename); - testFile.open(QIODevice::WriteOnly); + QVERIFY2(testFile.open(QIODevice::WriteOnly), + qPrintable(QString::fromLatin1("Cannot open %1 for writing: %2").arg(filename, testFile.errorString()))); testFile.close(); } QVERIFY(watcher.addPath(filename)); -- cgit v1.2.3