diff options
author | Christian Kamm <mail@ckamm.de> | 2019-01-23 17:12:02 +0300 |
---|---|---|
committer | ckamm <mail@ckamm.de> | 2019-02-11 15:35:14 +0300 |
commit | 010abe4c823af3dae7078854d1096f25b8b7225c (patch) | |
tree | 48852485d65dd29243f6e2a5fec69706b4294b76 | |
parent | 8ea639e58f2d2599f3f966f9f65a4f29c025ca43 (diff) |
Pin state updates
- unspecified and inherited are different
- move enum to header in common/
- access through Vfs instead of directly in Journal
-rw-r--r-- | src/common/pinstate.h | 76 | ||||
-rw-r--r-- | src/common/syncjournaldb.h | 19 | ||||
-rw-r--r-- | src/common/vfs.cpp | 26 | ||||
-rw-r--r-- | src/common/vfs.h | 51 | ||||
-rw-r--r-- | src/gui/folder.cpp | 1 | ||||
-rw-r--r-- | src/gui/folder.h | 1 | ||||
-rw-r--r-- | src/gui/folderwatcher_win.cpp | 5 | ||||
-rw-r--r-- | src/gui/socketapi.cpp | 12 | ||||
-rw-r--r-- | src/libsync/discovery.cpp | 29 | ||||
-rw-r--r-- | src/libsync/discovery.h | 38 | ||||
-rw-r--r-- | src/libsync/syncengine.cpp | 4 | ||||
-rw-r--r-- | src/libsync/vfs/suffix/vfs_suffix.cpp | 10 | ||||
-rw-r--r-- | src/libsync/vfs/suffix/vfs_suffix.h | 4 | ||||
-rw-r--r-- | test/syncenginetestutils.h | 30 | ||||
-rw-r--r-- | test/testsyncvirtualfiles.cpp | 45 |
15 files changed, 254 insertions, 97 deletions
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 <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 diff --git a/src/common/syncjournaldb.h b/src/common/syncjournaldb.h index 5dd4aab5c..b69a6e1e4 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 <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 ¶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<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) 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<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 ¶ms) 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 ¶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 7aef748dd..eb4672ca3 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -474,7 +474,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 286b4ccbd..4cbfedfa9 100644 --- a/src/gui/folder.h +++ b/src/gui/folder.h @@ -211,6 +211,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 4f963fbe2..5ecfe0e2c 100644 --- a/src/gui/folderwatcher_win.cpp +++ b/src/gui/folderwatcher_win.cpp @@ -67,7 +67,10 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize, SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize); if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer, 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, NULL)) { diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index 6d879bb0f..16fa5859a 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -619,9 +619,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); @@ -639,9 +638,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); @@ -917,7 +915,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 = folder->journalDb()->effectivePinStateForPath(path.toUtf8()); + auto pinState = folder->vfs().getPinState(path); if (!pinState) { // db error hasAlwaysLocal = true; diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index 5cd33463d..b00e7451e 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -427,14 +427,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); @@ -981,8 +977,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; @@ -1023,8 +1018,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 { @@ -1349,19 +1343,18 @@ bool ProcessDirectoryJob::runLocalQuery() return true; } -Optional<PinState> 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<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(); diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index d7f81f16b..313010d7f 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -568,8 +568,8 @@ void SyncEngine::startSync() 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 b4f9e89d5..549d0092f 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 <cstring> @@ -1139,12 +1140,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; } diff --git a/test/testsyncvirtualfiles.cpp b/test/testsyncvirtualfiles.cpp index 7a3b154cf..bb17f3e5b 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<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.owncloud")); QVERIFY(!fakeFolder.currentLocalState().find("A/B/b1.owncloud")); - fakeFolder.syncEngine().setSyncOptions(SyncOptions{}); + fakeFolder.switchToVfs(QSharedPointer<Vfs>(new VfsOff)); QVERIFY(fakeFolder.syncOnce()); QVERIFY(fakeFolder.currentRemoteState().find("A/a3.owncloud")); // 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.owncloud")); QVERIFY(fakeFolder.currentLocalState().find("local/file2")); - QVERIFY(fakeFolder.currentLocalState().find("unspec/file2")); + QVERIFY(fakeFolder.currentLocalState().find("unspec/file2.owncloud")); // file1 is unchanged QVERIFY(fakeFolder.currentLocalState().find("file1.owncloud")); @@ -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.owncloud"); |