Test: Add test for locked file tracking and propagation

This commit is contained in:
Christian Kamm 2018-11-05 12:12:49 +01:00 committed by Kevin Ottens
parent da178c1352
commit 9d55590d10
No known key found for this signature in database
GPG key ID: 074BBBCB8DECC9E2
4 changed files with 180 additions and 0 deletions

View file

@ -38,6 +38,16 @@ void LockWatcher::addFile(const QString &path)
_watchedPaths.insert(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() void LockWatcher::checkFiles()
{ {
QSet<QString> unlocked; QSet<QString> unlocked;

View file

@ -51,6 +51,12 @@ public:
*/ */
void addFile(const QString &path); 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: signals:
/** Emitted when one of the watched files is no longer /** Emitted when one of the watched files is no longer
* being locked. */ * being locked. */

View file

@ -58,6 +58,7 @@ nextcloud_add_test(LocalDiscovery "syncenginetestutils.h")
nextcloud_add_test(RemoteDiscovery "syncenginetestutils.h") nextcloud_add_test(RemoteDiscovery "syncenginetestutils.h")
nextcloud_add_test(Permissions "syncenginetestutils.h") nextcloud_add_test(Permissions "syncenginetestutils.h")
nextcloud_add_test(SelectiveSync "syncenginetestutils.h") nextcloud_add_test(SelectiveSync "syncenginetestutils.h")
nextcloud_add_test(LockedFiles "syncenginetestutils.h;../src/gui/lockwatcher.cpp")
nextcloud_add_test(FolderWatcher "${FolderWatcher_SRC}") nextcloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
if( UNIX AND NOT APPLE ) if( UNIX AND NOT APPLE )

163
test/testlockedfiles.cpp Normal file
View 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"