From d371855e56ce4bed449f4f998567a15d069a56a7 Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Fri, 7 Oct 2022 18:15:13 +0200 Subject: [PATCH] test that files soon to be expired will be synced automatically try to ensure that we properly sync again files for which lock has expired Signed-off-by: Matthieu Gallien --- test/syncenginetestutils.cpp | 24 ++++++++++ test/syncenginetestutils.h | 16 +++++++ test/testlocaldiscovery.cpp | 13 +----- test/testlockfile.cpp | 88 ++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 11 deletions(-) diff --git a/test/syncenginetestutils.cpp b/test/syncenginetestutils.cpp index 70b87bb5a..f7e1faf5a 100644 --- a/test/syncenginetestutils.cpp +++ b/test/syncenginetestutils.cpp @@ -103,6 +103,10 @@ void DiskFileModifier::setModTime(const QString &relativePath, const QDateTime & OCC::FileSystem::setModTime(_rootDir.filePath(relativePath), OCC::Utility::qDateTimeToTime_t(modTime)); } +void DiskFileModifier::modifyLockState([[maybe_unused]] const QString &relativePath, [[maybe_unused]] LockState lockState, [[maybe_unused]] int lockType, [[maybe_unused]] const QString &lockOwner, [[maybe_unused]] const QString &lockOwnerId, [[maybe_unused]] const QString &lockEditorId, [[maybe_unused]] quint64 lockTime, [[maybe_unused]] quint64 lockTimeout) +{ +} + FileInfo FileInfo::A12_B12_C12_S12() { FileInfo fi { QString {}, { @@ -195,6 +199,19 @@ void FileInfo::setModTimeKeepEtag(const QString &relativePath, const QDateTime & file->lastModified = modTime; } +void FileInfo::modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) +{ + FileInfo *file = findInvalidatingEtags(relativePath); + Q_ASSERT(file); + file->lockState = lockState; + file->lockType = lockType; + file->lockOwner = lockOwner; + file->lockOwnerId = lockOwnerId; + file->lockEditorId = lockEditorId; + file->lockTime = lockTime; + file->lockTimeout = lockTimeout; +} + FileInfo *FileInfo::find(PathComponents pathComponents, const bool invalidateEtags) { if (pathComponents.isEmpty()) { @@ -334,6 +351,13 @@ FakePropfindReply::FakePropfindReply(FileInfo &remoteRootFileInfo, QNetworkAcces xml.writeTextElement(ocUri, QStringLiteral("permissions"), !fileInfo.permissions.isNull() ? QString(fileInfo.permissions.toString()) : fileInfo.isShared ? QStringLiteral("SRDNVCKW") : QStringLiteral("RDNVCKW")); xml.writeTextElement(ocUri, QStringLiteral("id"), QString::fromUtf8(fileInfo.fileId)); xml.writeTextElement(ocUri, QStringLiteral("checksums"), QString::fromUtf8(fileInfo.checksums)); + xml.writeTextElement(ncUri, QStringLiteral("lock-owner"), fileInfo.lockOwnerId); + xml.writeTextElement(ncUri, QStringLiteral("lock"), fileInfo.lockState == FileInfo::LockState::FileLocked ? QStringLiteral("1") : QStringLiteral("0")); + xml.writeTextElement(ncUri, QStringLiteral("lock-owner-type"), fileInfo.lockOwnerId); + xml.writeTextElement(ncUri, QStringLiteral("lock-owner-displayname"), fileInfo.lockOwnerId); + xml.writeTextElement(ncUri, QStringLiteral("lock-owner-editor"), fileInfo.lockOwnerId); + xml.writeTextElement(ncUri, QStringLiteral("lock-time"), QString::number(fileInfo.lockTime)); + xml.writeTextElement(ncUri, QStringLiteral("lock-timeout"), QString::number(fileInfo.lockTimeout)); buffer.write(fileInfo.extraDavProperties); xml.writeEndElement(); // prop xml.writeTextElement(davUri, QStringLiteral("status"), QStringLiteral("HTTP/1.1 200 OK")); diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index ddd50273b..ab4074df6 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -76,6 +76,11 @@ public: class FileModifier { public: + enum class LockState { + FileLocked, + FileUnlocked, + }; + virtual ~FileModifier() = default; virtual void remove(const QString &relativePath) = 0; virtual void insert(const QString &relativePath, qint64 size = 64, char contentChar = 'W') = 0; @@ -84,6 +89,7 @@ public: virtual void mkdir(const QString &relativePath) = 0; virtual void rename(const QString &relativePath, const QString &relativeDestinationDirectory) = 0; virtual void setModTime(const QString &relativePath, const QDateTime &modTime) = 0; + virtual void modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) = 0; }; class DiskFileModifier : public FileModifier @@ -99,6 +105,7 @@ public: void mkdir(const QString &relativePath) override; void rename(const QString &from, const QString &to) override; void setModTime(const QString &relativePath, const QDateTime &modTime) override; + void modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) override; }; class FileInfo : public FileModifier @@ -130,6 +137,8 @@ public: void setModTimeKeepEtag(const QString &relativePath, const QDateTime &modTime); + void modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) override; + FileInfo *find(PathComponents pathComponents, const bool invalidateEtags = false); FileInfo *createDir(const QString &relativePath); @@ -163,6 +172,13 @@ public: QByteArray extraDavProperties; qint64 size = 0; char contentChar = 'W'; + LockState lockState = LockState::FileUnlocked; + int lockType = 0; + QString lockOwner; + QString lockOwnerId; + QString lockEditorId; + quint64 lockTime = 0; + quint64 lockTimeout = 0; // Sorted by name to be able to compare trees QMap children; diff --git a/test/testlocaldiscovery.cpp b/test/testlocaldiscovery.cpp index 80350bf90..9ed191c8e 100644 --- a/test/testlocaldiscovery.cpp +++ b/test/testlocaldiscovery.cpp @@ -621,15 +621,7 @@ private slots: fakeFolder.remoteModifier().insert(fooFileRootFolder); fakeFolder.remoteModifier().insert(barFileRootFolder); - - const auto lockedFileDavProps = QByteArray("1" - "0" - "user1" - "user1" - "user1" - "1648046707"); - - fakeFolder.remoteModifier().find("bar")->extraDavProperties = lockedFileDavProps; + fakeFolder.remoteModifier().modifyLockState(QStringLiteral("bar"), FileInfo::LockState::FileLocked, 0, QStringLiteral("user1"), {}, QStringLiteral("user1"), 1648046707, 0); fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder")); fakeFolder.remoteModifier().insert(fooFileSubFolder); @@ -648,8 +640,7 @@ private slots: QVERIFY(fakeFolder.syncJournal().getFileRecord(QStringLiteral("bar"), &fileRecordBefore)); QVERIFY(fileRecordBefore._lockstate._locked); - const auto unlockedFileDavProps = QByteArray("0"); - fakeFolder.remoteModifier().find("bar")->extraDavProperties = unlockedFileDavProps; + fakeFolder.remoteModifier().modifyLockState(QStringLiteral("bar"), FileInfo::LockState::FileUnlocked, {}, {}, {}, {}, {}, {}); fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem); diff --git a/test/testlockfile.cpp b/test/testlockfile.cpp index 97538295e..16f246fcf 100644 --- a/test/testlockfile.cpp +++ b/test/testlockfile.cpp @@ -5,6 +5,7 @@ #include "common/syncjournaldb.h" #include "common/syncjournalfilerecord.h" #include "syncenginetestutils.h" +#include "localdiscoverytracker.h" #include #include @@ -482,6 +483,93 @@ private slots: QVERIFY(jobFailure.wait()); QCOMPARE(jobSuccess.count(), 0); } + + void testSyncLockedFilesAlmostExpired() + { + FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() }; + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + QSignalSpy spySyncCompleted(&fakeFolder.syncEngine(), &OCC::SyncEngine::finished); + + ItemCompletedSpy completeSpy(fakeFolder); + + completeSpy.clear(); + QVERIFY(fakeFolder.syncOnce()); + + QCOMPARE(completeSpy.findItem(QStringLiteral("A/a1"))->_locked, OCC::SyncFileItem::LockStatus::UnlockedItem); + OCC::SyncJournalFileRecord fileRecordBefore; + QVERIFY(fakeFolder.syncJournal().getFileRecord(QStringLiteral("A/a1"), &fileRecordBefore)); + QVERIFY(!fileRecordBefore._lockstate._locked); + + fakeFolder.remoteModifier().modifyLockState(QStringLiteral("A/a1"), FileModifier::LockState::FileLocked, 1, QStringLiteral("Nextcloud Office"), {}, QStringLiteral("richdocuments"), QDateTime::currentDateTime().toSecsSinceEpoch() - 1220, 1226); + + completeSpy.clear(); + QVERIFY(fakeFolder.syncOnce()); + + QCOMPARE(completeSpy.findItem(QStringLiteral("A/a1"))->_locked, OCC::SyncFileItem::LockStatus::LockedItem); + OCC::SyncJournalFileRecord fileRecordLocked; + QVERIFY(fakeFolder.syncJournal().getFileRecord(QStringLiteral("A/a1"), &fileRecordLocked)); + QVERIFY(fileRecordLocked._lockstate._locked); + + spySyncCompleted.clear(); + + QTest::qWait(5000); + + fakeFolder.remoteModifier().modifyLockState(QStringLiteral("A/a1"), FileModifier::LockState::FileUnlocked, {}, {}, {}, {}, {}, {}); + + QCOMPARE(spySyncCompleted.count(), 0); + QVERIFY(spySyncCompleted.wait(3000)); + QCOMPARE(spySyncCompleted.count(), 1); + + OCC::SyncJournalFileRecord fileRecordUnlocked; + QVERIFY(fakeFolder.syncJournal().getFileRecord(QStringLiteral("A/a1"), &fileRecordUnlocked)); + QVERIFY(!fileRecordUnlocked._lockstate._locked); + } + + void testSyncLockedFilesNoExpiredLockedFiles() + { + FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() }; + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + QSignalSpy spySyncCompleted(&fakeFolder.syncEngine(), &OCC::SyncEngine::finished); + + ItemCompletedSpy completeSpy(fakeFolder); + + completeSpy.clear(); + QVERIFY(fakeFolder.syncOnce()); + + QCOMPARE(completeSpy.findItem(QStringLiteral("A/a1"))->_locked, OCC::SyncFileItem::LockStatus::UnlockedItem); + OCC::SyncJournalFileRecord fileRecordBefore; + QVERIFY(fakeFolder.syncJournal().getFileRecord(QStringLiteral("A/a1"), &fileRecordBefore)); + QVERIFY(!fileRecordBefore._lockstate._locked); + + fakeFolder.remoteModifier().modifyLockState(QStringLiteral("A/a1"), FileModifier::LockState::FileLocked, 1, QStringLiteral("Nextcloud Office"), {}, QStringLiteral("richdocuments"), QDateTime::currentDateTime().toSecsSinceEpoch() - 1220, 1226); + + completeSpy.clear(); + QVERIFY(fakeFolder.syncOnce()); + + QCOMPARE(completeSpy.findItem(QStringLiteral("A/a1"))->_locked, OCC::SyncFileItem::LockStatus::LockedItem); + OCC::SyncJournalFileRecord fileRecordLocked; + QVERIFY(fakeFolder.syncJournal().getFileRecord(QStringLiteral("A/a1"), &fileRecordLocked)); + QVERIFY(fileRecordLocked._lockstate._locked); + + completeSpy.clear(); + QVERIFY(fakeFolder.syncOnce()); + + spySyncCompleted.clear(); + + QTest::qWait(1000); + + fakeFolder.remoteModifier().modifyLockState(QStringLiteral("A/a1"), FileModifier::LockState::FileUnlocked, {}, {}, {}, {}, {}, {}); + + QCOMPARE(spySyncCompleted.count(), 0); + QVERIFY(!spySyncCompleted.wait(3000)); + QCOMPARE(spySyncCompleted.count(), 0); + + OCC::SyncJournalFileRecord fileRecordUnlocked; + QVERIFY(fakeFolder.syncJournal().getFileRecord(QStringLiteral("A/a1"), &fileRecordUnlocked)); + QVERIFY(fileRecordUnlocked._lockstate._locked); + } }; QTEST_GUILESS_MAIN(TestLockFile)