mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2025-05-11 02:34:10 +02:00
Test: Add test for locked file tracking and propagation
This commit is contained in:
parent
da178c1352
commit
9d55590d10
@ -38,6 +38,16 @@ void LockWatcher::addFile(const QString &path)
|
||||
_watchedPaths.insert(path);
|
||||
}
|
||||
|
||||
void LockWatcher::setCheckInterval(std::chrono::milliseconds interval)
|
||||
{
|
||||
_timer.start(interval.count());
|
||||
}
|
||||
|
||||
bool LockWatcher::contains(const QString &path)
|
||||
{
|
||||
return _watchedPaths.contains(path);
|
||||
}
|
||||
|
||||
void LockWatcher::checkFiles()
|
||||
{
|
||||
QSet<QString> unlocked;
|
||||
|
@ -51,6 +51,12 @@ public:
|
||||
*/
|
||||
void addFile(const QString &path);
|
||||
|
||||
/** Adjusts the default interval for checking whether the lock is still present */
|
||||
void setCheckInterval(std::chrono::milliseconds interval);
|
||||
|
||||
/** Whether the path is being watched for lock-changes */
|
||||
bool contains(const QString &path);
|
||||
|
||||
signals:
|
||||
/** Emitted when one of the watched files is no longer
|
||||
* being locked. */
|
||||
|
@ -58,6 +58,7 @@ nextcloud_add_test(LocalDiscovery "syncenginetestutils.h")
|
||||
nextcloud_add_test(RemoteDiscovery "syncenginetestutils.h")
|
||||
nextcloud_add_test(Permissions "syncenginetestutils.h")
|
||||
nextcloud_add_test(SelectiveSync "syncenginetestutils.h")
|
||||
nextcloud_add_test(LockedFiles "syncenginetestutils.h;../src/gui/lockwatcher.cpp")
|
||||
nextcloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
|
||||
|
||||
if( UNIX AND NOT APPLE )
|
||||
|
163
test/testlockedfiles.cpp
Normal file
163
test/testlockedfiles.cpp
Normal file
@ -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"
|
Loading…
Reference in New Issue
Block a user