From: Christian Kamm Date: Wed, 23 Jan 2019 14:12:02 +0000 (+0100) Subject: Pin state updates X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~308 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=7f400e3226cf6590dcd2e71a851a74f5d7af16a3;p=nextcloud-desktop.git Pin state updates - unspecified and inherited are different - move enum to header in common/ - access through Vfs instead of directly in Journal --- diff --git a/src/common/pinstate.h b/src/common/pinstate.h new file mode 100644 index 000000000..5fb267168 --- /dev/null +++ b/src/common/pinstate.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) by Christian Kamm + * + * 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 diff --git a/src/common/syncjournaldb.h b/src/common/syncjournaldb.h index 0e280f8cb..2062581c1 100644 --- a/src/common/syncjournaldb.h +++ b/src/common/syncjournaldb.h @@ -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 * diff --git a/src/common/vfs.cpp b/src/common/vfs.cpp index 4f3b6fadc..7e712a654 100644 --- a/src/common/vfs.cpp +++ b/src/common/vfs.cpp @@ -19,6 +19,7 @@ #include "vfs.h" #include "plugin.h" #include "version.h" +#include "syncjournaldb.h" #include #include @@ -59,11 +60,34 @@ Optional Vfs::modeFromString(const QString &str) return {}; } -VfsOff::VfsOff(QObject *parent) +VfsDefaults::VfsDefaults(QObject *parent) : Vfs(parent) { } +void VfsDefaults::start(const VfsSetupParams ¶ms) +{ + _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 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) diff --git a/src/common/vfs.h b/src/common/vfs.h index 9db7edc9c..35e7b86ac 100644 --- a/src/common/vfs.h +++ b/src/common/vfs.h @@ -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 ¶ms) = 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 ¶ms) = 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 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 ¶ms) override; + + // use the journal to back the pinstates + bool setPinState(const QString &folderPath, PinState state) override; + Optional getPinState(const QString &folderPath) override; + + // access initial setup data + const VfsSetupParams ¶ms() 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; } diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index f4a8107a1..0fb13ec13 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -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); } diff --git a/src/gui/folder.h b/src/gui/folder.h index 0eb45286a..ab395b049 100644 --- a/src/gui/folder.h +++ b/src/gui/folder.h @@ -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()); } diff --git a/src/gui/folderwatcher_win.cpp b/src/gui/folderwatcher_win.cpp index 23175f73e..9e184c32c 100644 --- a/src/gui/folderwatcher_win.cpp +++ b/src/gui/folderwatcher_win.cpp @@ -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)) { diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index a42033211..e4f44f639 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -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; diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index 04e50292c..286c72fc5 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -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 ProcessDirectoryJob::directoryPinState() +bool ProcessDirectoryJob::isVfsWithSuffix() const { - if (!_pinStateCache) { - _pinStateCache = _discoveryData->_statedb->effectivePinStateForPath( - _currentFolder._original.toUtf8()); - // don't cache db errors, just retry next time - } - return _pinStateCache; + return _discoveryData->_syncOptions._vfs->mode() == Vfs::WithSuffix; } -bool ProcessDirectoryJob::isVfsWithSuffix() const +void ProcessDirectoryJob::computePinState(PinState parentState) { - return _discoveryData->_syncOptions._vfs->mode() == Vfs::WithSuffix; + _pinState = parentState; + if (_queryLocal != ParentDontExist) { + if (auto state = _discoveryData->_syncOptions._vfs->getPinState(_currentFolder._local)) // ouch! pin local or original? + _pinState = *state; + } } } diff --git a/src/libsync/discovery.h b/src/libsync/discovery.h index bfb6856a3..6cc059bbd 100644 --- a/src/libsync/discovery.h +++ b/src/libsync/discovery.h @@ -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 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 _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 _pinStateCache; // The directories pin-state, once retrieved, see directoryPinState() + PinState _pinState = PinState::Unspecified; // The directory's pin-state, see setParentPinState() signals: void finished(); diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index c48b75a56..1cc29d8a6 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -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); } diff --git a/src/libsync/vfs/suffix/vfs_suffix.cpp b/src/libsync/vfs/suffix/vfs_suffix.cpp index 60d753a1b..518decf70 100644 --- a/src/libsync/vfs/suffix/vfs_suffix.cpp +++ b/src/libsync/vfs/suffix/vfs_suffix.cpp @@ -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() { } diff --git a/src/libsync/vfs/suffix/vfs_suffix.h b/src/libsync/vfs/suffix/vfs_suffix.h index 2949533aa..9c2a2cc08 100644 --- a/src/libsync/vfs/suffix/vfs_suffix.h +++ b/src/libsync/vfs/suffix/vfs_suffix.h @@ -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 ¶ms) override; - void start(const VfsSetupParams ¶ms) override; void stop() override; void unregisterFolder() override; diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index d60d6dc3a..f3663f8ba 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -12,6 +12,7 @@ #include "filesystem.h" #include "syncengine.h" #include "common/syncjournaldb.h" +#include "common/vfs.h" #include "csync_exclude.h" #include @@ -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 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; } diff --git a/test/testsyncvirtualfiles.cpp b/test/testsyncvirtualfiles.cpp index f07c4e59a..c8e8c2d6a 100644 --- a/test/testsyncvirtualfiles.cpp +++ b/test/testsyncvirtualfiles.cpp @@ -59,12 +59,15 @@ void markForDehydration(FakeFolder &folder, const QByteArray &path) journal.avoidReadFromDbOnNextSync(record._path); } -SyncOptions vfsSyncOptions(FakeFolder &fakeFolder) +QSharedPointer setupVfs(FakeFolder &folder) { - SyncOptions options; - options._vfs.reset(createVfsFromPlugin(Vfs::WithSuffix).release()); - fakeFolder.syncJournal().setPinStateForPath("", PinState::OnlineOnly); - return options; + auto suffixVfs = QSharedPointer(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(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");