diff options
author | Matthieu Gallien <matthieu.gallien@nextcloud.com> | 2022-03-03 12:53:50 +0300 |
---|---|---|
committer | Matthieu Gallien (Rebase PR Action) <matthieu_gallien@yahoo.fr> | 2022-03-18 02:28:02 +0300 |
commit | d4081c99a7916ec0641789530f287137abebc140 (patch) | |
tree | 68c6c422540549e412dcde27e4fb7a7714e97dea | |
parent | b8ff1525f78e9c6ba065001cff9106a91db6936b (diff) |
prevent updating files when that would result in invalid mtime
ensure that we never try to sync a file with a sync that would result in
setting it up to an invalid mtime
test a recovery scenario with plain old sync folder and virtual files
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
-rw-r--r-- | src/libsync/discovery.cpp | 20 | ||||
-rw-r--r-- | test/syncenginetestutils.cpp | 7 | ||||
-rw-r--r-- | test/syncenginetestutils.h | 2 | ||||
-rw-r--r-- | test/testlocaldiscovery.cpp | 194 | ||||
-rw-r--r-- | test/testsyncengine.cpp | 28 | ||||
-rw-r--r-- | test/testsyncvirtualfiles.cpp | 65 |
6 files changed, 280 insertions, 36 deletions
diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index c9a3b1d53..cb6ce2755 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -848,6 +848,12 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo( if (_queryLocal != NormalQuery && _queryServer != NormalQuery) recurse = false; + if ((item->_direction == SyncFileItem::Down || item->_instruction == CSYNC_INSTRUCTION_CONFLICT) && (item->_modtime <= 0 || item->_modtime >= 0xFFFFFFFF)) { + item->_instruction = CSYNC_INSTRUCTION_ERROR; + item->_errorString = tr("Cannot sync due to invalid modification time"); + item->_status = SyncFileItem::Status::NormalError; + } + auto recurseQueryLocal = _queryLocal == ParentNotChanged ? ParentNotChanged : localEntry.isDirectory || item->_instruction == CSYNC_INSTRUCTION_RENAME ? NormalQuery : ParentDontExist; processFileFinalize(item, path, recurse, recurseQueryLocal, recurseQueryServer); }; @@ -875,14 +881,14 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo( } path._original = originalPath; item->_originalFile = path._original; - item->_modtime = base._modtime; - item->_inode = base._inode; + item->_modtime = base.isValid() ? base._modtime : localEntry.modtime; + item->_inode = base.isValid() ? base._inode : localEntry.inode; item->_instruction = CSYNC_INSTRUCTION_RENAME; item->_direction = direction; - item->_fileId = base._fileId; - item->_remotePerm = base._remotePerm; - item->_etag = base._etag; - item->_type = base._type; + item->_fileId = base.isValid() ? base._fileId : QByteArray{}; + item->_remotePerm = base.isValid() ? base._remotePerm : RemotePermissions{}; + item->_etag = base.isValid() ? base._etag : QByteArray{}; + item->_type = base.isValid() ? base._type : localEntry.type; }; if (!localEntry.isValid()) { @@ -1002,7 +1008,7 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo( item->_type = localEntry.isDirectory ? ItemTypeDirectory : ItemTypeFile; _childModified = true; } else if (dbEntry._modtime > 0 && localEntry.modtime <= 0) { - item->_instruction = CSYNC_INSTRUCTION_SYNC; + item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; item->_direction = SyncFileItem::Down; item->_size = localEntry.size > 0 ? localEntry.size : dbEntry._fileSize; item->_modtime = dbEntry._modtime; diff --git a/test/syncenginetestutils.cpp b/test/syncenginetestutils.cpp index a5eaaaaf7..1d813e3ff 100644 --- a/test/syncenginetestutils.cpp +++ b/test/syncenginetestutils.cpp @@ -188,6 +188,13 @@ void FileInfo::setModTime(const QString &relativePath, const QDateTime &modTime) file->lastModified = modTime; } +void FileInfo::setModTimeKeepEtag(const QString &relativePath, const QDateTime &modTime) +{ + FileInfo *file = find(relativePath); + Q_ASSERT(file); + file->lastModified = modTime; +} + FileInfo *FileInfo::find(PathComponents pathComponents, const bool invalidateEtags) { if (pathComponents.isEmpty()) { diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index c434925cc..8abe50848 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -128,6 +128,8 @@ public: void setModTime(const QString &relativePath, const QDateTime &modTime) override; + void setModTimeKeepEtag(const QString &relativePath, const QDateTime &modTime); + FileInfo *find(PathComponents pathComponents, const bool invalidateEtags = false); FileInfo *createDir(const QString &relativePath); diff --git a/test/testlocaldiscovery.cpp b/test/testlocaldiscovery.cpp index 448d2d2b6..fa714129d 100644 --- a/test/testlocaldiscovery.cpp +++ b/test/testlocaldiscovery.cpp @@ -387,8 +387,11 @@ private slots: QCOMPARE(fakeFolder.currentRemoteState(), expectedState); } - void testInvalidMtimeRecovery() + void testBlockInvalidMtimeSyncRemote() { + constexpr auto INVALID_MODTIME1 = 0; + constexpr auto INVALID_MODTIME2 = -3600; + FakeFolder fakeFolder{FileInfo{}}; QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); const QString fooFileRootFolder("foo"); @@ -408,44 +411,177 @@ private slots: QVERIFY(fakeFolder.syncOnce()); - fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.remoteModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.remoteModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.localModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(0)); - fakeFolder.localModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(0)); + fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.remoteModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.remoteModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + + QVERIFY(!fakeFolder.syncOnce()); + + QVERIFY(!fakeFolder.syncOnce()); + + fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.remoteModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.remoteModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + + QVERIFY(!fakeFolder.syncOnce()); + + QVERIFY(!fakeFolder.syncOnce()); + } + + void testBlockInvalidMtimeSyncLocal() + { + constexpr auto INVALID_MODTIME1 = 0; + constexpr auto INVALID_MODTIME2 = -3600; + + FakeFolder fakeFolder{FileInfo{}}; + + int nGET = 0; + fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &, QIODevice *) { + if (op == QNetworkAccessManager::GetOperation) + ++nGET; + return nullptr; + }); + + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + const QString fooFileRootFolder("foo"); + const QString barFileRootFolder("bar"); + const QString blaFileRootFolder("bla"); + const QString fooFileSubFolder("subfolder/foo"); + const QString barFileSubFolder("subfolder/bar"); + const QString blaFileSubFolder("subfolder/bla"); + + fakeFolder.remoteModifier().insert(fooFileRootFolder); + fakeFolder.remoteModifier().insert(barFileRootFolder); + fakeFolder.remoteModifier().insert(blaFileRootFolder); + fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder")); + fakeFolder.remoteModifier().insert(fooFileSubFolder); + fakeFolder.remoteModifier().insert(barFileSubFolder); + fakeFolder.remoteModifier().insert(blaFileSubFolder); QVERIFY(fakeFolder.syncOnce()); + nGET = 0; + + fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.localModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); + fakeFolder.localModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1)); QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 0); - auto expectedState = fakeFolder.currentLocalState(); - QCOMPARE(fakeFolder.currentRemoteState(), expectedState); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 0); - fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.remoteModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.remoteModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.localModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(-3600)); - fakeFolder.localModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(-3600)); + fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.localModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); + fakeFolder.localModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2)); - QVERIFY(!fakeFolder.syncOnce()); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 0); + + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(nGET, 0); + } + + void testDoNotSyncInvalidFutureMtime() + { + constexpr auto FUTURE_MTIME = 0xFFFFFFFF; + constexpr auto CURRENT_MTIME = 1646057277; + + FakeFolder fakeFolder{FileInfo{}}; + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + const QString fooFileRootFolder("foo"); + const QString barFileRootFolder("bar"); + const QString fooFileSubFolder("subfolder/foo"); + const QString barFileSubFolder("subfolder/bar"); + const QString fooFileAaaSubFolder("aaa/subfolder/foo"); + const QString barFileAaaSubFolder("aaa/subfolder/bar"); + + fakeFolder.remoteModifier().insert(fooFileRootFolder); + fakeFolder.remoteModifier().insert(barFileRootFolder); + fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder")); + fakeFolder.remoteModifier().insert(fooFileSubFolder); + fakeFolder.remoteModifier().insert(barFileSubFolder); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa")); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa/subfolder")); + fakeFolder.remoteModifier().insert(fooFileAaaSubFolder); + fakeFolder.remoteModifier().insert(barFileAaaSubFolder); + + QVERIFY(fakeFolder.syncOnce()); + + fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.remoteModifier().setModTime(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.remoteModifier().setModTime(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.localModifier().setModTime(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.localModifier().setModTime(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); QVERIFY(!fakeFolder.syncOnce()); + } + + void testInvalidFutureMtimeRecovery() + { + constexpr auto FUTURE_MTIME = 0xFFFFFFFF; + constexpr auto CURRENT_MTIME = 1646057277; + + FakeFolder fakeFolder{FileInfo{}}; + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - expectedState = fakeFolder.currentLocalState(); + const QString fooFileRootFolder("foo"); + const QString barFileRootFolder("bar"); + const QString fooFileSubFolder("subfolder/foo"); + const QString barFileSubFolder("subfolder/bar"); + const QString fooFileAaaSubFolder("aaa/subfolder/foo"); + const QString barFileAaaSubFolder("aaa/subfolder/bar"); + + fakeFolder.remoteModifier().insert(fooFileRootFolder); + fakeFolder.remoteModifier().insert(barFileRootFolder); + fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder")); + fakeFolder.remoteModifier().insert(fooFileSubFolder); + fakeFolder.remoteModifier().insert(barFileSubFolder); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa")); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa/subfolder")); + fakeFolder.remoteModifier().insert(fooFileAaaSubFolder); + fakeFolder.remoteModifier().insert(barFileAaaSubFolder); + + QVERIFY(fakeFolder.syncOnce()); + + fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(barFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(barFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(fakeFolder.syncOnce()); + + auto expectedState = fakeFolder.currentLocalState(); QCOMPARE(fakeFolder.currentRemoteState(), expectedState); } }; diff --git a/test/testsyncengine.cpp b/test/testsyncengine.cpp index 1ec461aa1..bc6125616 100644 --- a/test/testsyncengine.cpp +++ b/test/testsyncengine.cpp @@ -1129,6 +1129,34 @@ private slots: QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); } + + void testFolderWithFilesInError() + { + FakeFolder fakeFolder{FileInfo{}}; + + fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) -> QNetworkReply * { + Q_UNUSED(outgoingData) + + if (op == QNetworkAccessManager::GetOperation) { + const auto fileName = getFilePathFromUrl(request.url()); + if (fileName == QStringLiteral("aaa/subfolder/foo")) { + return new FakeErrorReply(op, request, &fakeFolder.syncEngine(), 403); + } + } + return nullptr; + }); + + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa")); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa/subfolder")); + fakeFolder.remoteModifier().insert(QStringLiteral("aaa/subfolder/bar")); + + QVERIFY(fakeFolder.syncOnce()); + + fakeFolder.remoteModifier().insert(QStringLiteral("aaa/subfolder/foo")); + QVERIFY(!fakeFolder.syncOnce()); + + QVERIFY(!fakeFolder.syncOnce()); + } }; QTEST_GUILESS_MAIN(TestSyncEngine) diff --git a/test/testsyncvirtualfiles.cpp b/test/testsyncvirtualfiles.cpp index 882879c7b..e45fc7d58 100644 --- a/test/testsyncvirtualfiles.cpp +++ b/test/testsyncvirtualfiles.cpp @@ -1517,6 +1517,71 @@ private slots: QCOMPARE(fakeFolder.currentLocalState().find("A/hello" DVSUFFIX)->size, 222); QCOMPARE(fakeFolder.currentLocalState().find("A/igno" DVSUFFIX)->size, 123); } + + void testUpdateMetadataErrorManagement() + { + FakeFolder fakeFolder{FileInfo{}}; + setupVfs(fakeFolder); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + // Existing files are propagated just fine in both directions + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa")); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa/subfolder")); + fakeFolder.remoteModifier().insert(QStringLiteral("aaa/subfolder/bar")); + QVERIFY(fakeFolder.syncOnce()); + + // New files on the remote create virtual files + fakeFolder.remoteModifier().setModTime(QStringLiteral("aaa/subfolder/bar"), QDateTime::fromSecsSinceEpoch(0)); + QVERIFY(!fakeFolder.syncOnce()); + + QVERIFY(!fakeFolder.syncOnce()); + } + + void testInvalidFutureMtimeRecovery() + { + constexpr auto FUTURE_MTIME = 0xFFFFFFFF; + constexpr auto CURRENT_MTIME = 1646057277; + + FakeFolder fakeFolder{FileInfo{}}; + setupVfs(fakeFolder); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + const QString fooFileRootFolder("foo"); + const QString barFileRootFolder("bar"); + const QString fooFileSubFolder("subfolder/foo"); + const QString barFileSubFolder("subfolder/bar"); + const QString fooFileAaaSubFolder("aaa/subfolder/foo"); + const QString barFileAaaSubFolder("aaa/subfolder/bar"); + + fakeFolder.remoteModifier().insert(fooFileRootFolder); + fakeFolder.remoteModifier().insert(barFileRootFolder); + fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder")); + fakeFolder.remoteModifier().insert(fooFileSubFolder); + fakeFolder.remoteModifier().insert(barFileSubFolder); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa")); + fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa/subfolder")); + fakeFolder.remoteModifier().insert(fooFileAaaSubFolder); + fakeFolder.remoteModifier().insert(barFileAaaSubFolder); + + QVERIFY(fakeFolder.syncOnce()); + + fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(barFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(barFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.remoteModifier().setModTimeKeepEtag(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME)); + fakeFolder.localModifier().setModTime(fooFileRootFolder + DVSUFFIX, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(barFileRootFolder + DVSUFFIX, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(fooFileSubFolder + DVSUFFIX, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(barFileSubFolder + DVSUFFIX, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(fooFileAaaSubFolder + DVSUFFIX, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + fakeFolder.localModifier().setModTime(barFileAaaSubFolder + DVSUFFIX, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME)); + + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(fakeFolder.syncOnce()); + } }; QTEST_GUILESS_MAIN(TestSyncVirtualFiles) |