diff options
author | Christian Kamm <mail@ckamm.de> | 2018-11-05 14:12:49 +0300 |
---|---|---|
committer | ckamm <mail@ckamm.de> | 2018-11-06 12:03:25 +0300 |
commit | 2bc1baa5e24ba30e1fea8647214749856d1342e4 (patch) | |
tree | 2cc21acec56d6e4539be0fb66b73f77c6f6a9992 /test | |
parent | a9599b4ccc7a20f761e0282560a4fcc1d36bedbf (diff) |
Test: Add test for locked file tracking and propagation
Diffstat (limited to 'test')
-rw-r--r-- | test/CMakeLists.txt | 3 | ||||
-rw-r--r-- | test/testlockedfiles.cpp | 163 |
2 files changed, 166 insertions, 0 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0b923b85c..c373ac050 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -54,6 +54,9 @@ owncloud_add_test(Blacklist "syncenginetestutils.h") owncloud_add_test(LocalDiscovery "syncenginetestutils.h") owncloud_add_test(RemoteDiscovery "syncenginetestutils.h") owncloud_add_test(Permissions "syncenginetestutils.h") + +owncloud_add_test(LockedFiles "syncenginetestutils.h;../src/gui/lockwatcher.cpp") + owncloud_add_test(FolderWatcher "${FolderWatcher_SRC}") if( UNIX AND NOT APPLE ) diff --git a/test/testlockedfiles.cpp b/test/testlockedfiles.cpp new file mode 100644 index 000000000..df1e8f8d0 --- /dev/null +++ b/test/testlockedfiles.cpp @@ -0,0 +1,163 @@ +/* + * This software is in the public domain, furnished "as is", without technical + * support, and with no warranty, express or implied, as to its usefulness for + * any purpose. + * + */ + +#include <QtTest> +#include "syncenginetestutils.h" +#include "lockwatcher.h" +#include <syncengine.h> +#include <localdiscoverytracker.h> + +using namespace OCC; + +#ifdef Q_OS_WIN +// pass combination of FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE +HANDLE makeHandle(const QString &file, int shareMode) +{ + const wchar_t *wuri = reinterpret_cast<const wchar_t *>(file.utf16()); + auto handle = CreateFileW( + wuri, + GENERIC_READ | GENERIC_WRITE, + shareMode, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + qWarning() << GetLastError(); + } + return handle; +} +#endif + +class TestLockedFiles : public QObject +{ + Q_OBJECT + +private slots: + void testBasicLockFileWatcher() + { + int count = 0; + QString file; + + LockWatcher watcher; + watcher.setCheckInterval(std::chrono::milliseconds(50)); + connect(&watcher, &LockWatcher::fileUnlocked, &watcher, [&](const QString &f) { ++count; file = f; }); + + QString tmpFile; + { + QTemporaryFile tmp; + tmp.setAutoRemove(false); + tmp.open(); + tmpFile = tmp.fileName(); + } + QVERIFY(QFile::exists(tmpFile)); + + QVERIFY(!FileSystem::isFileLocked(tmpFile)); + watcher.addFile(tmpFile); + QVERIFY(watcher.contains(tmpFile)); + + QEventLoop loop; + QTimer::singleShot(120, &loop, [&] { loop.exit(); }); + loop.exec(); + + QCOMPARE(count, 1); + QCOMPARE(file, tmpFile); + QVERIFY(!watcher.contains(tmpFile)); + +#ifdef Q_OS_WIN + auto h = makeHandle(tmpFile, 0); + QVERIFY(FileSystem::isFileLocked(tmpFile)); + watcher.addFile(tmpFile); + + count = 0; + file.clear(); + QThread::msleep(120); + qApp->processEvents(); + + QCOMPARE(count, 0); + QVERIFY(file.isEmpty()); + QVERIFY(watcher.contains(tmpFile)); + + CloseHandle(h); + QVERIFY(!FileSystem::isFileLocked(tmpFile)); + + QThread::msleep(120); + qApp->processEvents(); + + QCOMPARE(count, 1); + QCOMPARE(file, tmpFile); + QVERIFY(!watcher.contains(tmpFile)); +#endif + QFile::remove(tmpFile); + } + +#ifdef Q_OS_WIN + void testLockedFilePropagation() + { + FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() }; + + QStringList seenLockedFiles; + connect(&fakeFolder.syncEngine(), &SyncEngine::seenLockedFile, &fakeFolder.syncEngine(), + [&](const QString &file) { seenLockedFiles.append(file); }); + + LocalDiscoveryTracker tracker; + connect(&fakeFolder.syncEngine(), &SyncEngine::itemCompleted, &tracker, &LocalDiscoveryTracker::slotItemCompleted); + connect(&fakeFolder.syncEngine(), &SyncEngine::finished, &tracker, &LocalDiscoveryTracker::slotSyncFinished); + auto hasLocalDiscoveryPath = [&](const QString &path) { + auto &paths = tracker.localDiscoveryPaths(); + return paths.find(path.toUtf8()) != paths.end(); + }; + + // + // Local change, attempted upload, but file is locked! + // + fakeFolder.localModifier().appendByte("A/a1"); + tracker.addTouchedPath("A/a1"); + auto h1 = makeHandle(fakeFolder.localPath() + "A/a1", 0); + + fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths()); + tracker.startSyncPartialDiscovery(); + QVERIFY(!fakeFolder.syncOnce()); + + QVERIFY(seenLockedFiles.contains(fakeFolder.localPath() + "A/a1")); + QVERIFY(seenLockedFiles.size() == 1); + QVERIFY(hasLocalDiscoveryPath("A/a1")); + + CloseHandle(h1); + + fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths()); + tracker.startSyncPartialDiscovery(); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + seenLockedFiles.clear(); + QVERIFY(tracker.localDiscoveryPaths().empty()); + + // + // Remote change, attempted download, but file is locked! + // + fakeFolder.remoteModifier().appendByte("A/a1"); + auto h2 = makeHandle(fakeFolder.localPath() + "A/a1", 0); + + fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths()); + tracker.startSyncPartialDiscovery(); + QVERIFY(!fakeFolder.syncOnce()); + + QVERIFY(seenLockedFiles.contains(fakeFolder.localPath() + "A/a1")); + QVERIFY(seenLockedFiles.size() == 1); + + CloseHandle(h2); + + fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths()); + tracker.startSyncPartialDiscovery(); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + } +#endif +}; + +QTEST_GUILESS_MAIN(TestLockedFiles) +#include "testlockedfiles.moc" |