mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
ensure that normal sync engine will nto delete new file renamed due to trailing/leading spaces in name rename before upload in the same job to avoid having invalid state in local desktop client database to ensure any subsequent run of the sync engine will not make wrong decisions Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
601 lines
29 KiB
C++
601 lines
29 KiB
C++
/*
|
|
* 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 <syncengine.h>
|
|
#include <localdiscoverytracker.h>
|
|
|
|
using namespace OCC;
|
|
|
|
class TestLocalDiscovery : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
// Check correct behavior when local discovery is partially drawn from the db
|
|
void testLocalDiscoveryStyle()
|
|
{
|
|
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
|
|
|
|
LocalDiscoveryTracker tracker;
|
|
connect(&fakeFolder.syncEngine(), &SyncEngine::itemCompleted, &tracker, &LocalDiscoveryTracker::slotItemCompleted);
|
|
connect(&fakeFolder.syncEngine(), &SyncEngine::finished, &tracker, &LocalDiscoveryTracker::slotSyncFinished);
|
|
|
|
// More subdirectories are useful for testing
|
|
fakeFolder.localModifier().mkdir("A/X");
|
|
fakeFolder.localModifier().mkdir("A/Y");
|
|
fakeFolder.localModifier().insert("A/X/x1");
|
|
fakeFolder.localModifier().insert("A/Y/y1");
|
|
tracker.addTouchedPath("A/X");
|
|
|
|
tracker.startSyncFullDiscovery();
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
QVERIFY(tracker.localDiscoveryPaths().empty());
|
|
|
|
// Test begins
|
|
fakeFolder.localModifier().insert("A/a3");
|
|
fakeFolder.localModifier().insert("A/X/x2");
|
|
fakeFolder.localModifier().insert("A/Y/y2");
|
|
fakeFolder.localModifier().insert("B/b3");
|
|
fakeFolder.remoteModifier().insert("C/c3");
|
|
fakeFolder.remoteModifier().appendByte("C/c1");
|
|
tracker.addTouchedPath("A/X");
|
|
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths());
|
|
|
|
tracker.startSyncPartialDiscovery();
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/a3"));
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/X/x2"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find("A/Y/y2"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find("B/b3"));
|
|
QVERIFY(fakeFolder.currentLocalState().find("C/c3"));
|
|
QCOMPARE(fakeFolder.syncEngine().lastLocalDiscoveryStyle(), LocalDiscoveryStyle::DatabaseAndFilesystem);
|
|
QVERIFY(tracker.localDiscoveryPaths().empty());
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
QCOMPARE(fakeFolder.syncEngine().lastLocalDiscoveryStyle(), LocalDiscoveryStyle::FilesystemOnly);
|
|
QVERIFY(tracker.localDiscoveryPaths().empty());
|
|
}
|
|
|
|
void testLocalDiscoveryDecision()
|
|
{
|
|
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
|
|
auto &engine = fakeFolder.syncEngine();
|
|
|
|
QVERIFY(engine.shouldDiscoverLocally(""));
|
|
QVERIFY(engine.shouldDiscoverLocally("A"));
|
|
QVERIFY(engine.shouldDiscoverLocally("A/X"));
|
|
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(
|
|
LocalDiscoveryStyle::DatabaseAndFilesystem,
|
|
{ "A/X", "A/X space", "A/X/beta", "foo bar space/touch", "foo/", "zzz", "zzzz" });
|
|
|
|
QVERIFY(engine.shouldDiscoverLocally(""));
|
|
QVERIFY(engine.shouldDiscoverLocally("A"));
|
|
QVERIFY(engine.shouldDiscoverLocally("A/X"));
|
|
QVERIFY(!engine.shouldDiscoverLocally("B"));
|
|
QVERIFY(!engine.shouldDiscoverLocally("A B"));
|
|
QVERIFY(!engine.shouldDiscoverLocally("B/X"));
|
|
QVERIFY(engine.shouldDiscoverLocally("foo bar space"));
|
|
QVERIFY(engine.shouldDiscoverLocally("foo"));
|
|
QVERIFY(!engine.shouldDiscoverLocally("foo bar"));
|
|
QVERIFY(!engine.shouldDiscoverLocally("foo bar/touch"));
|
|
// These are within "A/X" so they should be discovered
|
|
QVERIFY(engine.shouldDiscoverLocally("A/X/alpha"));
|
|
QVERIFY(engine.shouldDiscoverLocally("A/X beta"));
|
|
QVERIFY(engine.shouldDiscoverLocally("A/X/Y"));
|
|
QVERIFY(engine.shouldDiscoverLocally("A/X space"));
|
|
QVERIFY(engine.shouldDiscoverLocally("A/X space/alpha"));
|
|
QVERIFY(!engine.shouldDiscoverLocally("A/Xylo/foo"));
|
|
QVERIFY(engine.shouldDiscoverLocally("zzzz/hello"));
|
|
QVERIFY(!engine.shouldDiscoverLocally("zzza/hello"));
|
|
|
|
QEXPECT_FAIL("", "There is a possibility of false positives if the set contains a path "
|
|
"which is a prefix, and that prefix is followed by a character less than '/'", Continue);
|
|
QVERIFY(!engine.shouldDiscoverLocally("A/X o"));
|
|
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(
|
|
LocalDiscoveryStyle::DatabaseAndFilesystem,
|
|
{});
|
|
|
|
QVERIFY(!engine.shouldDiscoverLocally(""));
|
|
}
|
|
|
|
// Check whether item success and item failure adjusts the
|
|
// tracker correctly.
|
|
void testTrackerItemCompletion()
|
|
{
|
|
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
|
|
|
|
LocalDiscoveryTracker tracker;
|
|
connect(&fakeFolder.syncEngine(), &SyncEngine::itemCompleted, &tracker, &LocalDiscoveryTracker::slotItemCompleted);
|
|
connect(&fakeFolder.syncEngine(), &SyncEngine::finished, &tracker, &LocalDiscoveryTracker::slotSyncFinished);
|
|
auto trackerContains = [&](const char *path) {
|
|
return tracker.localDiscoveryPaths().find(path) != tracker.localDiscoveryPaths().end();
|
|
};
|
|
|
|
tracker.addTouchedPath("A/spurious");
|
|
|
|
fakeFolder.localModifier().insert("A/a3");
|
|
tracker.addTouchedPath("A/a3");
|
|
|
|
fakeFolder.localModifier().insert("A/a4");
|
|
fakeFolder.serverErrorPaths().append("A/a4");
|
|
// We're not adding a4 as touched, it's in the same folder as a3 and will be seen.
|
|
// And due to the error it should be added to the explicit list while a3 gets removed.
|
|
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths());
|
|
tracker.startSyncPartialDiscovery();
|
|
QVERIFY(!fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/a3"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find("A/a4"));
|
|
QVERIFY(!trackerContains("A/a3"));
|
|
QVERIFY(trackerContains("A/a4"));
|
|
QVERIFY(trackerContains("A/spurious")); // not removed since overall sync not successful
|
|
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::FilesystemOnly);
|
|
tracker.startSyncFullDiscovery();
|
|
QVERIFY(!fakeFolder.syncOnce());
|
|
|
|
QVERIFY(!fakeFolder.currentRemoteState().find("A/a4"));
|
|
QVERIFY(trackerContains("A/a4")); // had an error, still here
|
|
QVERIFY(!trackerContains("A/spurious")); // removed due to full discovery
|
|
|
|
fakeFolder.serverErrorPaths().clear();
|
|
fakeFolder.syncJournal().wipeErrorBlacklist();
|
|
tracker.addTouchedPath("A/newspurious"); // will be removed due to successful sync
|
|
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths());
|
|
tracker.startSyncPartialDiscovery();
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/a4"));
|
|
QVERIFY(tracker.localDiscoveryPaths().empty());
|
|
}
|
|
|
|
void testDirectoryAndSubDirectory()
|
|
{
|
|
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
|
|
|
|
fakeFolder.localModifier().mkdir("A/newDir");
|
|
fakeFolder.localModifier().mkdir("A/newDir/subDir");
|
|
fakeFolder.localModifier().insert("A/newDir/subDir/file", 10);
|
|
|
|
auto expectedState = fakeFolder.currentLocalState();
|
|
|
|
// Only "A" was modified according to the file system tracker
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(
|
|
LocalDiscoveryStyle::DatabaseAndFilesystem,
|
|
{ "A" });
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QCOMPARE(fakeFolder.currentLocalState(), expectedState);
|
|
QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
|
|
}
|
|
|
|
// Tests the behavior of invalid filename detection
|
|
void testServerBlacklist()
|
|
{
|
|
FakeFolder fakeFolder { FileInfo::A12_B12_C12_S12() };
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
|
|
fakeFolder.syncEngine().account()->setCapabilities({ { "files",
|
|
QVariantMap { { "blacklisted_files", QVariantList { ".foo", "bar" } } } } });
|
|
fakeFolder.localModifier().insert("C/.foo");
|
|
fakeFolder.localModifier().insert("C/bar");
|
|
fakeFolder.localModifier().insert("C/moo");
|
|
fakeFolder.localModifier().insert("C/.moo");
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
QVERIFY(fakeFolder.currentRemoteState().find("C/moo"));
|
|
QVERIFY(fakeFolder.currentRemoteState().find("C/.moo"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find("C/.foo"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find("C/bar"));
|
|
}
|
|
|
|
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameAndUploadFile()
|
|
{
|
|
FakeFolder fakeFolder{FileInfo{}};
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
const QString fileWithSpaces1(" foo");
|
|
const QString fileWithSpaces2(" bar ");
|
|
const QString fileWithSpaces3("bla ");
|
|
const QString fileWithSpaces4("A/ foo");
|
|
const QString fileWithSpaces5("A/ bar ");
|
|
const QString fileWithSpaces6("A/bla ");
|
|
|
|
fakeFolder.localModifier().insert(fileWithSpaces1);
|
|
fakeFolder.localModifier().insert(fileWithSpaces2);
|
|
fakeFolder.localModifier().insert(fileWithSpaces3);
|
|
fakeFolder.localModifier().mkdir("A");
|
|
fakeFolder.localModifier().insert(fileWithSpaces4);
|
|
fakeFolder.localModifier().insert(fileWithSpaces5);
|
|
fakeFolder.localModifier().insert(fileWithSpaces6);
|
|
fakeFolder.localModifier().mkdir(QStringLiteral(" with spaces "));
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
|
|
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
|
|
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
|
|
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
|
|
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
|
|
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
|
|
|
|
QVERIFY(fakeFolder.currentLocalState().find(QStringLiteral("with spaces")));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(QStringLiteral(" with spaces ")));
|
|
|
|
fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, {QStringLiteral("foo"), QStringLiteral("bar"), QStringLiteral("bla"), QStringLiteral("A/foo"), QStringLiteral("A/bar"), QStringLiteral("A/bla")});
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces1.trimmed()));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces1));
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces2.trimmed()));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces2));
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces3.trimmed()));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces3));
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find(QStringLiteral("with spaces")));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(QStringLiteral(" with spaces ")));
|
|
QVERIFY(fakeFolder.currentLocalState().find(QStringLiteral("with spaces")));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(QStringLiteral(" with spaces ")));
|
|
}
|
|
|
|
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile()
|
|
{
|
|
FakeFolder fakeFolder{FileInfo{}};
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
const QString fileWithSpaces4("A/ foo");
|
|
const QString fileWithSpaces5("A/ bar ");
|
|
const QString fileWithSpaces6("A/bla ");
|
|
|
|
fakeFolder.remoteModifier().mkdir("A");
|
|
fakeFolder.remoteModifier().insert(fileWithSpaces4);
|
|
fakeFolder.remoteModifier().insert(fileWithSpaces5);
|
|
fakeFolder.remoteModifier().insert(fileWithSpaces6);
|
|
|
|
qDebug() << fakeFolder.currentRemoteState();
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
qDebug() << fakeFolder.currentRemoteState();
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
|
|
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
|
|
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
|
|
|
|
auto expectedState = fakeFolder.currentLocalState();
|
|
QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
|
|
}
|
|
|
|
void testCreateFileWithTrailingSpaces_localTrimmedDoesExist_dontRenameAndUploadFile()
|
|
{
|
|
FakeFolder fakeFolder{FileInfo{}};
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
const QString fileWithSpaces(" foo");
|
|
const QString fileTrimmed("foo");
|
|
|
|
fakeFolder.localModifier().insert(fileTrimmed);
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
fakeFolder.localModifier().insert(fileWithSpaces);
|
|
QVERIFY(!fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces));
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
|
|
}
|
|
|
|
void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAndUploadFile()
|
|
{
|
|
FakeFolder fakeFolder{FileInfo{}};
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
const QString fileWithSpaces(" foo");
|
|
const QString fileTrimmed("foo");
|
|
|
|
fakeFolder.localModifier().insert(fileTrimmed);
|
|
fakeFolder.localModifier().insert(fileWithSpaces);
|
|
QVERIFY(!fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
|
|
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces));
|
|
QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
|
|
}
|
|
|
|
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedExists_renameFile()
|
|
{
|
|
FakeFolder fakeFolder{FileInfo{}};
|
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
|
const QString fileWithSpaces1(" foo");
|
|
const QString fileWithSpaces2(" bar ");
|
|
const QString fileWithSpaces3("bla ");
|
|
|
|
fakeFolder.localModifier().insert(fileWithSpaces1);
|
|
fakeFolder.localModifier().insert(fileWithSpaces2);
|
|
fakeFolder.localModifier().insert(fileWithSpaces3);
|
|
fakeFolder.remoteModifier().insert(fileWithSpaces1);
|
|
fakeFolder.remoteModifier().insert(fileWithSpaces2);
|
|
fakeFolder.remoteModifier().insert(fileWithSpaces3);
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
|
|
auto expectedState = fakeFolder.currentLocalState();
|
|
qDebug() << expectedState;
|
|
QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
|
|
}
|
|
|
|
void testBlockInvalidMtimeSyncRemote()
|
|
{
|
|
constexpr auto INVALID_MODTIME1 = 0;
|
|
constexpr auto INVALID_MODTIME2 = -3600;
|
|
|
|
FakeFolder fakeFolder{FileInfo{}};
|
|
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());
|
|
|
|
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);
|
|
|
|
QVERIFY(fakeFolder.syncOnce());
|
|
QCOMPARE(nGET, 0);
|
|
|
|
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());
|
|
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());
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
QTEST_GUILESS_MAIN(TestLocalDiscovery)
|
|
#include "testlocaldiscovery.moc"
|