1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2025-05-09 23:34:09 +02:00

Pin state updates

- unspecified and inherited are different
- move enum to header in common/
- access through Vfs instead of directly in Journal
This commit is contained in:
Christian Kamm 2019-01-23 15:12:02 +01:00 committed by Kevin Ottens
parent 2722c61515
commit 7f400e3226
No known key found for this signature in database
GPG Key ID: 074BBBCB8DECC9E2
15 changed files with 255 additions and 98 deletions

76
src/common/pinstate.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (C) by Christian Kamm <mail@ckamm.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef PINSTATE_H
#define PINSTATE_H
#include "ocsynclib.h"
namespace OCC {
/** Determines whether items should be available locally permanently or not
*
* The idea is that files and folders can be marked with the user intent
* on availability.
*
* The Inherited state is used for resetting a pin state to what its
* parent path would do.
*
* The pin state of a directory usually only matters for the initial pin and
* hydration state of new remote files. It's perfectly possible for a
* AlwaysLocal directory to have only OnlineOnly items. (though setting pin
* states is usually done recursively, so one'd need to set the folder to
* pinned and then each contained item to unpinned)
*
* Note: This enum intentionally mimics CF_PIN_STATE of Windows cfapi.
*/
enum class PinState {
/** The pin state is derived from the state of the parent folder.
*
* For example new remote files start out in this state, following
* the state of their parent folder.
*
* This state is used purely for resetting pin states to their derived
* value. The effective state for an item will never be "Inherited".
*/
Inherited = 0,
/** The file shall be available and up to date locally.
*
* Also known as "pinned". Pinned dehydrated files shall be hydrated
* as soon as possible.
*/
AlwaysLocal = 1,
/** File shall be a dehydrated placeholder, filled on demand.
*
* Also known as "unpinned". Unpinned hydrated files shall be dehydrated
* as soon as possible.
*
* If a unpinned file becomes hydrated its pin state changes to unspecified.
*/
OnlineOnly = 2,
/** The user hasn't made a decision. The client or platform may hydrate or
* dehydrate as they see fit.
*
* New remote files in unspecified directories start unspecified, and
* dehydrated (which is an arbitrary decision).
*/
Unspecified = 3,
};
}
#endif

View File

@ -29,28 +29,11 @@
#include "common/ownsql.h"
#include "common/syncjournalfilerecord.h"
#include "common/result.h"
#include "common/pinstate.h"
namespace OCC {
class SyncJournalFileRecord;
/** Determines whether files should be available locally or not
*
* For new remote files the file's PinState is calculated by looking for
* the closest parent folder that isn't Inherited.
*
* TODO: It seems to make sense to also store per-file PinStates.
* Maybe these could communicate intent, similar to ItemTypeVirtualFileDownload
* and ...FileDehydrate?
*/
enum class PinState {
/// Inherit the PinState of the parent directory (default)
Inherited = 0,
/// Download file and keep it updated.
AlwaysLocal = 1,
/// File shall be virtual locally.
OnlineOnly = 2,
};
/**
* @brief Class that handles the sync database
*

View File

@ -19,6 +19,7 @@
#include "vfs.h"
#include "plugin.h"
#include "version.h"
#include "syncjournaldb.h"
#include <QPluginLoader>
#include <QLoggingCategory>
@ -59,11 +60,34 @@ Optional<Vfs::Mode> Vfs::modeFromString(const QString &str)
return {};
}
VfsOff::VfsOff(QObject *parent)
VfsDefaults::VfsDefaults(QObject *parent)
: Vfs(parent)
{
}
void VfsDefaults::start(const VfsSetupParams &params)
{
_setupParams = params;
}
bool VfsDefaults::setPinState(const QString &folderPath, PinState state)
{
auto path = folderPath.toUtf8();
_setupParams.journal->wipePinStateForPathAndBelow(path);
_setupParams.journal->setPinStateForPath(path, state);
return true;
}
Optional<PinState> VfsDefaults::getPinState(const QString &folderPath)
{
return _setupParams.journal->effectivePinStateForPath(folderPath.toUtf8());
}
VfsOff::VfsOff(QObject *parent)
: VfsDefaults(parent)
{
}
VfsOff::~VfsOff() = default;
static QString modeToPluginName(Vfs::Mode mode)

View File

@ -22,6 +22,7 @@
#include "ocsynclib.h"
#include "result.h"
#include "syncfilestatus.h"
#include "pinstate.h"
typedef struct csync_file_stat_s csync_file_stat_t;
@ -48,7 +49,7 @@ struct OCSYNC_EXPORT VfsSetupParams
*
* Note: The journal must live at least until the Vfs::stop() call.
*/
SyncJournalDb *journal;
SyncJournalDb *journal = nullptr;
/// Strings potentially passed on to the platform
QString providerName;
@ -101,14 +102,14 @@ public:
virtual QString fileSuffix() const = 0;
/// Must be called at least once before start(). May make sense to merge with start().
virtual void registerFolder(const VfsSetupParams &params) = 0;
/** Initializes interaction with the VFS provider.
*
* For example, the VFS provider might monitor files to be able to start a file
* hydration (download of a file's remote contents) when the user wants to open
* it.
*
* Usually some registration needs to be done with the backend. This function
* should take care of it if necessary.
*/
virtual void start(const VfsSetupParams &params) = 0;
@ -160,6 +161,24 @@ public:
*/
virtual bool statTypeVirtualFile(csync_file_stat_t *stat, void *stat_data) = 0;
/** Sets the pin state for the item at a path.
*
* Usually this would forward to setting the pin state flag in the db table,
* but some vfs plugins will store the pin state in file attributes instead.
*
* folderPath is relative to the sync folder.
*/
virtual bool setPinState(const QString &folderPath, PinState state) = 0;
/** Returns the pin state of an item at a path.
*
* Usually backed by the db's effectivePinState() function but some vfs
* plugins will override it to retrieve the state from elsewhere.
*
* folderPath is relative to the sync folder.
*/
virtual Optional<PinState> getPinState(const QString &folderPath) = 0;
public slots:
/** Update in-sync state based on SyncFileStatusTracker signal.
*
@ -176,8 +195,27 @@ signals:
void doneHydrating();
};
class OCSYNC_EXPORT VfsDefaults : public Vfs
{
public:
explicit VfsDefaults(QObject* parent = nullptr);
// stores the params
void start(const VfsSetupParams &params) override;
// use the journal to back the pinstates
bool setPinState(const QString &folderPath, PinState state) override;
Optional<PinState> getPinState(const QString &folderPath) override;
// access initial setup data
const VfsSetupParams &params() const { return _setupParams; }
protected:
VfsSetupParams _setupParams;
};
/// Implementation of Vfs for Vfs::Off mode - does nothing
class OCSYNC_EXPORT VfsOff : public Vfs
class OCSYNC_EXPORT VfsOff : public VfsDefaults
{
Q_OBJECT
@ -189,12 +227,9 @@ public:
QString fileSuffix() const override { return QString(); }
void registerFolder(const VfsSetupParams &) override {}
void start(const VfsSetupParams &) override {}
void stop() override {}
void unregisterFolder() override {}
bool isHydrating() const override { return false; }
bool updateMetadata(const QString &, time_t, quint64, const QByteArray &, QString *) override { return true; }

View File

@ -487,7 +487,6 @@ void Folder::startVfs()
connect(&_engine->syncFileStatusTracker(), &SyncFileStatusTracker::fileStatusChanged,
_vfs.data(), &Vfs::fileStatusChanged);
_vfs->registerFolder(vfsParams); // Do this always?
_vfs->start(vfsParams);
}

View File

@ -205,6 +205,7 @@ public:
// Used by the Socket API
SyncJournalDb *journalDb() { return &_journal; }
SyncEngine &syncEngine() { return *_engine; }
Vfs &vfs() { return *_vfs; }
RequestEtagJob *etagJob() { return _requestEtagJob; }
std::chrono::milliseconds msecSinceLastSync() const { return std::chrono::milliseconds(_timeSinceLastSyncDone.elapsed()); }

View File

@ -69,7 +69,10 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
OCC::Utility::convertSizeToDWORD(fileNotifyBufferSize), true,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_NOTIFY_CHANGE_FILE_NAME
| FILE_NOTIFY_CHANGE_DIR_NAME
| FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_ATTRIBUTES, // attributes are for vfs pin state changes
&dwBytesReturned,
&overlapped,
nullptr)) {

View File

@ -700,9 +700,8 @@ void SocketApi::command_MAKE_AVAILABLE_LOCALLY(const QString &filesArg, SocketLi
continue;
// Update the pin state on all items
auto pinPath = data.folderRelativePathNoVfsSuffix().toUtf8();
data.folder->journalDb()->wipePinStateForPathAndBelow(pinPath);
data.folder->journalDb()->setPinStateForPath(pinPath, PinState::AlwaysLocal);
auto pinPath = data.folderRelativePathNoVfsSuffix();
data.folder->vfs().setPinState(pinPath, PinState::AlwaysLocal);
// Trigger the recursive download
data.folder->downloadVirtualFile(data.folderRelativePath);
@ -720,9 +719,8 @@ void SocketApi::command_MAKE_ONLINE_ONLY(const QString &filesArg, SocketListener
continue;
// Update the pin state on all items
auto pinPath = data.folderRelativePathNoVfsSuffix().toUtf8();
data.folder->journalDb()->wipePinStateForPathAndBelow(pinPath);
data.folder->journalDb()->setPinStateForPath(pinPath, PinState::OnlineOnly);
auto pinPath = data.folderRelativePathNoVfsSuffix();
data.folder->vfs().setPinState(pinPath, PinState::OnlineOnly);
// Trigger recursive dehydration
data.folder->dehydrateFile(data.folderRelativePath);
@ -1021,7 +1019,7 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe
for (const auto &file : files) {
auto fileData = FileData::get(file);
auto path = fileData.folderRelativePathNoVfsSuffix();
auto pinState = syncFolder->journalDb()->effectivePinStateForPath(path.toUtf8());
auto pinState = syncFolder->vfs().getPinState(path);
if (!pinState) {
// db error
hasAlwaysLocal = true;

View File

@ -426,14 +426,10 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(
}
// Turn new remote files into virtual files if the option is enabled.
auto &opts = _discoveryData->_syncOptions;
if (!directoryPinState()) {
dbError();
return;
}
if (!localEntry.isValid()
&& item->_type == ItemTypeFile
&& opts._vfs->mode() != Vfs::Off
&& *directoryPinState() == PinState::OnlineOnly) {
&& _pinState != PinState::AlwaysLocal) {
item->_type = ItemTypeVirtualFile;
if (isVfsWithSuffix())
addVirtualFileSuffix(path._original);
@ -989,8 +985,7 @@ void ProcessDirectoryJob::processFileFinalize(
if (!checkPermissions(item))
recurse = false;
if (recurse) {
auto job = new ProcessDirectoryJob(item, recurseQueryLocal, recurseQueryServer, _discoveryData, this);
job->_currentFolder = path;
auto job = new ProcessDirectoryJob(path, item, recurseQueryLocal, recurseQueryServer, this);
if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
job->setParent(_discoveryData);
_discoveryData->_queuedDeletedDirectories[path._original] = job;
@ -1031,8 +1026,7 @@ void ProcessDirectoryJob::processBlacklisted(const PathTuple &path, const OCC::L
qCInfo(lcDisco) << "Discovered (blacklisted) " << item->_file << item->_instruction << item->_direction << item->isDirectory();
if (item->isDirectory() && item->_instruction != CSYNC_INSTRUCTION_IGNORE) {
auto job = new ProcessDirectoryJob(item, NormalQuery, InBlackList, _discoveryData, this);
job->_currentFolder = path;
auto job = new ProcessDirectoryJob(path, item, NormalQuery, InBlackList, this);
connect(job, &ProcessDirectoryJob::finished, this, &ProcessDirectoryJob::subJobFinished);
_queuedJobs.push_back(job);
} else {
@ -1357,19 +1351,18 @@ bool ProcessDirectoryJob::runLocalQuery()
return true;
}
Optional<PinState> ProcessDirectoryJob::directoryPinState()
{
if (!_pinStateCache) {
_pinStateCache = _discoveryData->_statedb->effectivePinStateForPath(
_currentFolder._original.toUtf8());
// don't cache db errors, just retry next time
}
return _pinStateCache;
}
bool ProcessDirectoryJob::isVfsWithSuffix() const
{
return _discoveryData->_syncOptions._vfs->mode() == Vfs::WithSuffix;
}
void ProcessDirectoryJob::computePinState(PinState parentState)
{
_pinState = parentState;
if (_queryLocal != ParentDontExist) {
if (auto state = _discoveryData->_syncOptions._vfs->getPinState(_currentFolder._local)) // ouch! pin local or original?
_pinState = *state;
}
}
}

View File

@ -48,6 +48,8 @@ class SyncJournalDb;
class ProcessDirectoryJob : public QObject
{
Q_OBJECT
struct PathTuple;
public:
enum QueryMode {
NormalQuery,
@ -56,14 +58,30 @@ public:
InBlackList // Do not query this folder because it is in the blacklist (remote entries only)
};
Q_ENUM(QueryMode)
explicit ProcessDirectoryJob(const SyncFileItemPtr &dirItem, QueryMode queryLocal, QueryMode queryServer,
DiscoveryPhase *data, QObject *parent)
/** For creating the root job
*
* The base pin state is used if the root dir's pin state can't be retrieved.
*/
explicit ProcessDirectoryJob(DiscoveryPhase *data, PinState basePinState, QObject *parent)
: QObject(parent)
, _discoveryData(data)
{
computePinState(basePinState);
}
/// For creating subjobs
explicit ProcessDirectoryJob(const PathTuple &path, const SyncFileItemPtr &dirItem,
QueryMode queryLocal, QueryMode queryServer,
ProcessDirectoryJob *parent)
: QObject(parent)
, _dirItem(dirItem)
, _queryServer(queryServer)
, _queryLocal(queryLocal)
, _discoveryData(data)
, _discoveryData(parent->_discoveryData)
, _currentFolder(path)
{
computePinState(parent->_pinState);
}
void start();
@ -180,11 +198,15 @@ private:
*/
bool runLocalQuery();
/** Retrieve and cache directory pin state */
Optional<PinState> directoryPinState();
/** Sets _pinState
*
* If the folder exists locally its state is retrieved, otherwise the
* parent's pin state is inherited.
*/
void computePinState(PinState parentState);
QueryMode _queryServer;
QueryMode _queryLocal;
QueryMode _queryServer = QueryMode::NormalQuery;
QueryMode _queryLocal = QueryMode::NormalQuery;
// Holds entries that resulted from a NormalQuery
QVector<RemoteInfo> _serverNormalQueryEntries;
@ -222,7 +244,7 @@ private:
PathTuple _currentFolder;
bool _childModified = false; // the directory contains modified item what would prevent deletion
bool _childIgnored = false; // The directory contains ignored item that would prevent deletion
Optional<PinState> _pinStateCache; // The directories pin-state, once retrieved, see directoryPinState()
PinState _pinState = PinState::Unspecified; // The directory's pin-state, see setParentPinState()
signals:
void finished();

View File

@ -637,8 +637,8 @@ void SyncEngine::slotStartDiscovery()
connect(_discoveryPhase.data(), &DiscoveryPhase::silentlyExcluded,
_syncFileStatusTracker.data(), &SyncFileStatusTracker::slotAddSilentlyExcluded);
auto discoveryJob = new ProcessDirectoryJob(SyncFileItemPtr(), ProcessDirectoryJob::NormalQuery, ProcessDirectoryJob::NormalQuery,
_discoveryPhase.data(), _discoveryPhase.data());
auto discoveryJob = new ProcessDirectoryJob(
_discoveryPhase.data(), PinState::AlwaysLocal, _discoveryPhase.data());
_discoveryPhase->startJob(discoveryJob);
connect(discoveryJob, &ProcessDirectoryJob::etag, this, &SyncEngine::slotRootEtagReceived);
}

View File

@ -22,7 +22,7 @@
namespace OCC {
VfsSuffix::VfsSuffix(QObject *parent)
: Vfs(parent)
: VfsDefaults(parent)
{
}
@ -40,14 +40,6 @@ QString VfsSuffix::fileSuffix() const
return QStringLiteral(APPLICATION_DOTVIRTUALFILE_SUFFIX);
}
void VfsSuffix::registerFolder(const VfsSetupParams &)
{
}
void VfsSuffix::start(const VfsSetupParams &)
{
}
void VfsSuffix::stop()
{
}

View File

@ -21,7 +21,7 @@
namespace OCC {
class VfsSuffix : public Vfs
class VfsSuffix : public VfsDefaults
{
Q_OBJECT
@ -32,8 +32,6 @@ public:
Mode mode() const override;
QString fileSuffix() const override;
void registerFolder(const VfsSetupParams &params) override;
void start(const VfsSetupParams &params) override;
void stop() override;
void unregisterFolder() override;

View File

@ -12,6 +12,7 @@
#include "filesystem.h"
#include "syncengine.h"
#include "common/syncjournaldb.h"
#include "common/vfs.h"
#include "csync_exclude.h"
#include <QDir>
@ -925,12 +926,41 @@ public:
// Ignore temporary files from the download. (This is in the default exclude list, but we don't load it)
_syncEngine->excludedFiles().addManualExclude("]*.~*");
// Ensure we have a valid VfsOff instance "running"
switchToVfs(_syncEngine->syncOptions()._vfs);
// A new folder will update the local file state database on first sync.
// To have a state matching what users will encounter, we have to a sync
// using an identical local/remote file tree first.
syncOnce();
}
void switchToVfs(QSharedPointer<OCC::Vfs> vfs)
{
auto opts = _syncEngine->syncOptions();
opts._vfs->stop();
QObject::disconnect(_syncEngine.get(), 0, opts._vfs.data(), 0);
opts._vfs = vfs;
_syncEngine->setSyncOptions(opts);
OCC::VfsSetupParams vfsParams;
vfsParams.filesystemPath = localPath();
vfsParams.remotePath = "";
vfsParams.account = _account;
vfsParams.journal = _journalDb.get();
vfsParams.providerName = "OC-TEST";
vfsParams.providerVersion = "0.1";
vfsParams.enableShellIntegration = false;
QObject::connect(_syncEngine.get(), &QObject::destroyed, vfs.data(), [vfs]() {
vfs->stop();
vfs->unregisterFolder();
});
vfs->start(vfsParams);
}
OCC::AccountPtr account() const { return _account; }
OCC::SyncEngine &syncEngine() const { return *_syncEngine; }
OCC::SyncJournalDb &syncJournal() const { return *_journalDb; }

View File

@ -59,12 +59,15 @@ void markForDehydration(FakeFolder &folder, const QByteArray &path)
journal.avoidReadFromDbOnNextSync(record._path);
}
SyncOptions vfsSyncOptions(FakeFolder &fakeFolder)
QSharedPointer<Vfs> setupVfs(FakeFolder &folder)
{
SyncOptions options;
options._vfs.reset(createVfsFromPlugin(Vfs::WithSuffix).release());
fakeFolder.syncJournal().setPinStateForPath("", PinState::OnlineOnly);
return options;
auto suffixVfs = QSharedPointer<Vfs>(createVfsFromPlugin(Vfs::WithSuffix).release());
folder.switchToVfs(suffixVfs);
// Using this directly doesn't recursively unpin everything
folder.syncJournal().setPinStateForPath("", PinState::OnlineOnly);
return suffixVfs;
}
class TestSyncVirtualFiles : public QObject
@ -85,7 +88,7 @@ private slots:
QFETCH(bool, doLocalDiscovery);
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
@ -206,7 +209,7 @@ private slots:
void testVirtualFileConflict()
{
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
@ -277,7 +280,7 @@ private slots:
void testWithNormalSync()
{
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
@ -313,7 +316,7 @@ private slots:
void testVirtualFileDownload()
{
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
@ -381,7 +384,7 @@ private slots:
void testVirtualFileDownloadResume()
{
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
@ -422,8 +425,7 @@ private slots:
void testNewFilesNotVirtual()
{
FakeFolder fakeFolder{ FileInfo() };
SyncOptions syncOptions = vfsSyncOptions(fakeFolder);
fakeFolder.syncEngine().setSyncOptions(syncOptions);
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
fakeFolder.remoteModifier().mkdir("A");
@ -443,7 +445,7 @@ private slots:
void testDownloadRecursive()
{
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
// Create a virtual file for remote files
@ -540,7 +542,7 @@ private slots:
void testRenameToVirtual()
{
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
@ -578,7 +580,7 @@ private slots:
void testRenameVirtual()
{
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
@ -620,7 +622,7 @@ private slots:
void testSyncDehydration()
{
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@ -697,7 +699,7 @@ private slots:
void testWipeVirtualSuffixFiles()
{
FakeFolder fakeFolder{ FileInfo{} };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
// Create a suffix-vfs baseline
@ -733,7 +735,7 @@ private slots:
QVERIFY(fakeFolder.currentLocalState().find("A/a3.nextcloud"));
QVERIFY(!fakeFolder.currentLocalState().find("A/B/b1.nextcloud"));
fakeFolder.syncEngine().setSyncOptions(SyncOptions{});
fakeFolder.switchToVfs(QSharedPointer<Vfs>(new VfsOff));
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find("A/a3.nextcloud")); // regular upload
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@ -742,7 +744,7 @@ private slots:
void testNewVirtuals()
{
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
auto setPin = [&] (const QByteArray &path, PinState state) {
@ -757,6 +759,7 @@ private slots:
setPin("local", PinState::AlwaysLocal);
setPin("online", PinState::OnlineOnly);
setPin("unspec", PinState::Unspecified);
// Test 1: root is OnlineOnly
fakeFolder.remoteModifier().insert("file1");
@ -782,7 +785,7 @@ private slots:
QVERIFY(fakeFolder.currentLocalState().find("file2"));
QVERIFY(fakeFolder.currentLocalState().find("online/file2.nextcloud"));
QVERIFY(fakeFolder.currentLocalState().find("local/file2"));
QVERIFY(fakeFolder.currentLocalState().find("unspec/file2"));
QVERIFY(fakeFolder.currentLocalState().find("unspec/file2.nextcloud"));
// file1 is unchanged
QVERIFY(fakeFolder.currentLocalState().find("file1.nextcloud"));
@ -810,7 +813,7 @@ private slots:
cleanup();
// Enable suffix vfs
fakeFolder.syncEngine().setSyncOptions(vfsSyncOptions(fakeFolder));
setupVfs(fakeFolder);
// Local changes of suffixed file do nothing
fakeFolder.localModifier().appendByte("A/file1.nextcloud");