diff --git a/changelog/unreleased/12369.md b/changelog/unreleased/12369.md new file mode 100644 index 00000000000..cd1eb15785d --- /dev/null +++ b/changelog/unreleased/12369.md @@ -0,0 +1,7 @@ +Change: Remove capability to upload conflict files + +None of the supported servers implements (or plans on implementing) this +feature. This removal includes the `OWNCLOUD_UPLOAD_CONFLICT_FILES` +environment variable. + +https://github.com/owncloud/client/pull/12369 diff --git a/src/common/utility.cpp b/src/common/utility.cpp index 06cfda0a873..88b40438df6 100644 --- a/src/common/utility.cpp +++ b/src/common/utility.cpp @@ -380,8 +380,7 @@ bool Utility::urlEqual(QUrl url1, QUrl url2) return url1.matches(url2, QUrl::StripTrailingSlash | QUrl::NormalizePathSegments); } -QString Utility::makeConflictFileName( - const QString &fn, const QDateTime &dt, const QString &user) +QString Utility::makeConflictFileName(const QString &fn, const QDateTime &dt) { QString conflictFileName(fn); // Add conflict tag before the extension. @@ -392,12 +391,6 @@ QString Utility::makeConflictFileName( } QString conflictMarker = QStringLiteral(" (conflicted copy "); - if (!user.isEmpty()) { - // Don't allow parens in the user name, to ensure - // we can find the beginning and end of the conflict tag. - const auto userName = sanitizeForFileName(user).replace(QLatin1Char('('), QLatin1Char('_')).replace(QLatin1Char(')'), QLatin1Char('_'));; - conflictMarker += userName + QLatin1Char(' '); - } conflictMarker += dt.toString(QStringLiteral("yyyy-MM-dd hhmmss")) + QLatin1Char(')'); conflictFileName.insert(dotLocation, conflictMarker); diff --git a/src/common/utility.h b/src/common/utility.h index 7f2aa101649..8a9286e13a0 100644 --- a/src/common/utility.h +++ b/src/common/utility.h @@ -226,8 +226,7 @@ OCSYNC_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcUtility) /** Returns a file name based on \a fn that's suitable for a conflict. */ - OCSYNC_EXPORT QString makeConflictFileName( - const QString &fn, const QDateTime &dt, const QString &user); + OCSYNC_EXPORT QString makeConflictFileName(const QString &fn, const QDateTime &dt); /** Returns whether a file name indicates a conflict file */ diff --git a/src/csync/csync_exclude.cpp b/src/csync/csync_exclude.cpp index 812d40bd98c..d2d06a0da70 100644 --- a/src/csync/csync_exclude.cpp +++ b/src/csync/csync_exclude.cpp @@ -141,7 +141,7 @@ OCSYNC_EXPORT bool csync_is_windows_reserved_word(QStringView filename) return false; } -static CSYNC_EXCLUDE_TYPE _csync_excluded_common(QStringView path, bool excludeConflictFiles) +static CSYNC_EXCLUDE_TYPE _csync_excluded_common(QStringView path) { /* split up the path */ QStringView bname(path); @@ -211,7 +211,7 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(QStringView path, bool excludeC } - if (excludeConflictFiles && OCC::Utility::isConflictFile(path)) { + if (OCC::Utility::isConflictFile(path)) { return CSYNC_FILE_EXCLUDE_CONFLICT; } return CSYNC_NOT_EXCLUDED; @@ -236,11 +236,6 @@ void ExcludedFiles::addExcludeFilePath(const QString &path) _excludeFiles.insert(path); } -void ExcludedFiles::setExcludeConflictFiles(bool onoff) -{ - _excludeConflictFiles = onoff; -} - void ExcludedFiles::addManualExclude(const QString &expr) { _manualExcludes.append(expr); @@ -379,7 +374,7 @@ bool ExcludedFiles::isExcludedRemote(QStringView filePath, QStringView basePath, CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(QStringView path, ItemType filetype) const { - auto match = _csync_excluded_common(path, _excludeConflictFiles); + auto match = _csync_excluded_common(path); if (match != CSYNC_NOT_EXCLUDED) return match; if (_allExcludes.isEmpty()) @@ -428,7 +423,7 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(QStringView path, ItemTy CSYNC_EXCLUDE_TYPE ExcludedFiles::fullPatternMatch(QStringView p, ItemType filetype) const { - auto match = _csync_excluded_common(p, _excludeConflictFiles); + auto match = _csync_excluded_common(p); if (match != CSYNC_NOT_EXCLUDED) return match; if (_allExcludes.isEmpty()) diff --git a/src/csync/csync_exclude.h b/src/csync/csync_exclude.h index bc1bcef61f3..241763833c2 100644 --- a/src/csync/csync_exclude.h +++ b/src/csync/csync_exclude.h @@ -76,13 +76,6 @@ class OCSYNC_EXPORT ExcludedFiles : public QObject */ void addExcludeFilePath(const QString &path); - /** - * Whether conflict files shall be excluded. - * - * Defaults to true. - */ - void setExcludeConflictFiles(bool onoff); - /** * Checks whether a file or directory should be excluded. * @@ -226,8 +219,6 @@ public Q_SLOTS: QRegularExpression _fullRegexFile; QRegularExpression _fullRegexDir; - bool _excludeConflictFiles = true; - /** * Whether * and ? in patterns can match a / * diff --git a/src/libsync/capabilities.cpp b/src/libsync/capabilities.cpp index 25d04b82141..bdb02757cab 100644 --- a/src/libsync/capabilities.cpp +++ b/src/libsync/capabilities.cpp @@ -145,16 +145,6 @@ QString Capabilities::invalidFilenameRegex() const return _capabilities[QStringLiteral("dav")].toMap()[QStringLiteral("invalidFilenameRegex")].toString(); } -bool Capabilities::uploadConflictFiles() const -{ - static auto envIsSet = !qEnvironmentVariableIsEmpty("OWNCLOUD_UPLOAD_CONFLICT_FILES"); - static int envValue = qEnvironmentVariableIntValue("OWNCLOUD_UPLOAD_CONFLICT_FILES"); - if (envIsSet) - return envValue != 0; - - return _capabilities[QStringLiteral("uploadConflictFiles")].toBool(); -} - bool Capabilities::versioningEnabled() const { return _capabilities.value(QStringLiteral("files")).toMap().value(QStringLiteral("versioning")).toBool(); diff --git a/src/libsync/capabilities.h b/src/libsync/capabilities.h index 5b3fe81a990..70ec089cfec 100644 --- a/src/libsync/capabilities.h +++ b/src/libsync/capabilities.h @@ -239,11 +239,6 @@ class OWNCLOUDSYNC_EXPORT Capabilities */ QStringList blacklistedFiles() const; - /** - * Whether conflict files should remain local (default) or should be uploaded. - */ - bool uploadConflictFiles() const; - /** Is versioning available? */ bool versioningEnabled() const; diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp index aee498152fd..3022357f982 100644 --- a/src/libsync/owncloudpropagator.cpp +++ b/src/libsync/owncloudpropagator.cpp @@ -753,18 +753,13 @@ OwncloudPropagator::DiskSpaceResult OwncloudPropagator::diskSpaceCheck() const return DiskSpaceOk; } -bool OwncloudPropagator::createConflict(const SyncFileItemPtr &item, - PropagatorCompositeJob *composite, QString *error) +bool OwncloudPropagator::createConflict(const SyncFileItemPtr &item, QString *error) { QString fn = fullLocalPath(item->_file); QString renameError; auto conflictModTime = FileSystem::getModTime(fn); - QString conflictUserName; - if (account()->capabilities().uploadConflictFiles()) - conflictUserName = account()->davDisplayName(); - QString conflictFileName = Utility::makeConflictFileName( - item->_file, Utility::qDateTimeFromTime_t(conflictModTime), conflictUserName); + QString conflictFileName = Utility::makeConflictFileName(item->_file, Utility::qDateTimeFromTime_t(conflictModTime)); QString conflictFilePath = fullLocalPath(conflictFileName); // If the file is locked, we want to retry this sync when it @@ -800,25 +795,6 @@ bool OwncloudPropagator::createConflict(const SyncFileItemPtr &item, _journal->setConflictRecord(conflictRecord); - // Create a new upload job if the new conflict file should be uploaded - if (account()->capabilities().uploadConflictFiles()) { - if (composite && !QFileInfo(conflictFilePath).isDir()) { - SyncFileItemPtr conflictItem = SyncFileItemPtr(new SyncFileItem); - conflictItem->_file = conflictFileName; - conflictItem->_type = ItemTypeFile; - conflictItem->_direction = SyncFileItem::Up; - conflictItem->setInstruction(CSYNC_INSTRUCTION_NEW); - conflictItem->_modtime = conflictModTime; - conflictItem->_size = item->_previousSize; - Q_EMIT newItem(conflictItem); - composite->appendTask(conflictItem); - } else { - // Directories we can't process in one go. The next sync run - // will take care of uploading the conflict dir contents. - _anotherSyncNeeded = true; - } - } - return true; } @@ -907,7 +883,6 @@ void PropagatorCompositeJob::slotSubJobAbortFinished() void PropagatorCompositeJob::appendJob(PropagatorJob *job) { - job->setAssociatedComposite(this); _jobsToDo.append(job); } @@ -1037,7 +1012,6 @@ PropagateDirectory::PropagateDirectory(OwncloudPropagator *propagator, const Syn { if (_firstJob) { connect(_firstJob.get(), &PropagatorJob::finished, this, &PropagateDirectory::slotFirstJobFinished); - _firstJob->setAssociatedComposite(&_subJobs); } connect(&_subJobs, &PropagatorJob::finished, this, &PropagateDirectory::slotSubJobsFinished); } diff --git a/src/libsync/owncloudpropagator.h b/src/libsync/owncloudpropagator.h index 73c20ebd14d..827a1cd9e21 100644 --- a/src/libsync/owncloudpropagator.h +++ b/src/libsync/owncloudpropagator.h @@ -104,14 +104,6 @@ class PropagatorJob : public QObject */ virtual qint64 committedDiskSpace() const { return 0; } - /** Set the associated composite job - * - * Used only from PropagatorCompositeJob itself, when a job is added - * and from PropagateDirectory to associate the subJobs with the first - * job. - */ - void setAssociatedComposite(PropagatorCompositeJob *job) { _associatedComposite = job; } - const QString path() { return _path; } public Q_SLOTS: @@ -142,16 +134,6 @@ public Q_SLOTS: protected: OwncloudPropagator *propagator() const; - /** If this job gets added to a composite job, this will point to the parent. - * - * For the PropagateDirectory::_firstJob it will point to - * PropagateDirectory::_subJobs. - * - * That can be useful for jobs that want to spawn follow-up jobs without - * becoming composite jobs themselves. - */ - PropagatorCompositeJob *_associatedComposite = nullptr; - private: QString _path; JobState _jobState; @@ -496,13 +478,9 @@ class OWNCLOUDSYNC_EXPORT OwncloudPropagator : public QObject * * Sets up conflict records. * - * It also creates a new upload job in composite if the item that's - * moved away is a file and conflict uploads are requested. - * * Returns true on success, false and error on error. */ - bool createConflict(const SyncFileItemPtr &item, - PropagatorCompositeJob *composite, QString *error); + bool createConflict(const SyncFileItemPtr &item, QString *error); // Map original path (as in the DB) to target final path // TODO: no public members... diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index ca1a7684c3a..6fc6a68d922 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -404,7 +404,7 @@ void PropagateDownloadFile::start() const bool isConflict = _item->instruction() == CSYNC_INSTRUCTION_CONFLICT && QFileInfo(fsPath).isDir(); if (isConflict) { QString error; - if (!propagator()->createConflict(_item, _associatedComposite, &error)) { + if (!propagator()->createConflict(_item, &error)) { done(SyncFileItem::SoftError, error); return; } @@ -801,7 +801,7 @@ void PropagateDownloadFile::deleteExistingFolder() } QString error; - if (!propagator()->createConflict(_item, _associatedComposite, &error)) { + if (!propagator()->createConflict(_item, &error)) { done(SyncFileItem::NormalError, error); } } @@ -874,7 +874,7 @@ void PropagateDownloadFile::downloadFinished() bool isConflict = _item->instruction() == CSYNC_INSTRUCTION_CONFLICT && (QFileInfo(fn).isDir() || !FileSystem::fileEquals(fn, _tmpFile.fileName())); if (isConflict) { QString error; - if (!propagator()->createConflict(_item, _associatedComposite, &error)) { + if (!propagator()->createConflict(_item, &error)) { done(SyncFileItem::SoftError, error); return; } diff --git a/src/libsync/propagatorjobs.cpp b/src/libsync/propagatorjobs.cpp index ec383074b12..cbdbc9b3987 100644 --- a/src/libsync/propagatorjobs.cpp +++ b/src/libsync/propagatorjobs.cpp @@ -166,7 +166,7 @@ void PropagateLocalMkdir::start() } } else if (_item->instruction() == CSYNC_INSTRUCTION_CONFLICT) { QString error; - if (!propagator()->createConflict(_item, _associatedComposite, &error)) { + if (!propagator()->createConflict(_item, &error)) { done(SyncFileItem::SoftError, error); return; } diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index b3287223d83..320854c8f11 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -260,17 +260,8 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item) if (Utility::isConflictFile(item->_file)) _seenConflictFiles.insert(item->_file); - if (item->instruction() == CSYNC_INSTRUCTION_NONE) { - if (_account->capabilities().uploadConflictFiles() && Utility::isConflictFile(item->_file)) { - // For uploaded conflict files, files with no action performed on them should - // be displayed: but we mustn't overwrite the instruction if something happens - // to the file! - item->_errorString = tr("Unresolved conflict."); - item->setInstruction(CSYNC_INSTRUCTION_IGNORE); - item->_status = SyncFileItem::Conflict; - } + if (item->instruction() == CSYNC_INSTRUCTION_NONE) return; - } // check for blacklisting of this item. // if the item is on blacklist, the instruction was set to ERROR @@ -369,8 +360,6 @@ void SyncEngine::startSync() // undo the filter to allow this sync to retrieve and store the correct etags. _journal->clearEtagStorageFilter(); - _excludedFiles->setExcludeConflictFiles(!_account->capabilities().uploadConflictFiles()); - _lastLocalDiscoveryStyle = _localDiscoveryStyle; bool ok; diff --git a/test/testsyncconflict.cpp b/test/testsyncconflict.cpp index 0b49a5e7cd6..12b3e47db25 100644 --- a/test/testsyncconflict.cpp +++ b/test/testsyncconflict.cpp @@ -15,13 +15,6 @@ using namespace OCC; namespace { -auto uploadConflictFilesCapabilities(bool b) -{ - auto cap = TestUtils::testCapabilities(); - cap.insert({{QStringLiteral("uploadConflictFiles"), b}}); - return cap; -} - bool itemSuccessful(const ItemCompletedSpy &spy, const QString &path, const SyncInstructions instr) { auto item = spy.findItem(path); @@ -128,192 +121,6 @@ private Q_SLOTS: } } - void testUploadAfterDownload() - { - QFETCH_GLOBAL(Vfs::Mode, vfsMode); - QFETCH_GLOBAL(bool, filesAreDehydrated); - - FakeFolder fakeFolder(FileInfo::A12_B12_C12_S12(), vfsMode, filesAreDehydrated); - fakeFolder.account()->setCapabilities({fakeFolder.account()->url(), uploadConflictFilesCapabilities(true)}); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - - QMap conflictMap; - fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *) -> QNetworkReply * { - if (op == QNetworkAccessManager::PutOperation) { - if (request.rawHeader("OC-Conflict") == "1") { - auto baseFileId = request.rawHeader("OC-ConflictBaseFileId"); - auto components = request.url().toString().split(QLatin1Char('/')); - QString conflictFile = components.mid(components.size() - 2).join(QLatin1Char('/')); - conflictMap[baseFileId] = conflictFile; - [&] { - QVERIFY(!baseFileId.isEmpty()); - QCOMPARE(request.rawHeader("OC-ConflictInitialBasePath"), - Utility::conflictFileBaseNameFromPattern(conflictFile.toUtf8())); - }(); - } - } - return nullptr; - }); - - fakeFolder.localModifier().setContents(QStringLiteral("A/a1"), FileModifier::DefaultFileSize, 'L'); - fakeFolder.remoteModifier().setContents(QStringLiteral("A/a1"), FileModifier::DefaultFileSize, 'R'); - fakeFolder.localModifier().appendByte(QStringLiteral("A/a2")); - fakeFolder.remoteModifier().appendByte(QStringLiteral("A/a2")); - fakeFolder.remoteModifier().appendByte(QStringLiteral("A/a2")); - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - if (filesAreDehydrated) { - // There should be no conflicts: before a modification is done to a local file, - // it will be downloaded from the remote first. - QCOMPARE(conflictMap.size(), 0); - } else { - auto local = fakeFolder.currentLocalState(); - auto remote = fakeFolder.currentRemoteState(); - QCOMPARE(local, remote); - - auto a1FileId = fakeFolder.remoteModifier().find(QStringLiteral("A/a1"))->fileId; - auto a2FileId = fakeFolder.remoteModifier().find(QStringLiteral("A/a2"))->fileId; - QVERIFY(conflictMap.contains(a1FileId)); - QVERIFY(conflictMap.contains(a2FileId)); - QCOMPARE(conflictMap.size(), 2); - QCOMPARE(Utility::conflictFileBaseNameFromPattern(conflictMap[a1FileId].toUtf8()), QByteArray("A/a1")); - - // Check that the conflict file contains the username - QVERIFY(conflictMap[a1FileId].contains(QString::fromLatin1("(conflicted copy %1 ").arg(fakeFolder.account()->davDisplayName()))); - - QCOMPARE(remote.find(conflictMap[a1FileId])->contentChar, 'L'); - QCOMPARE(remote.find(QStringLiteral("A/a1"))->contentChar, 'R'); - - QCOMPARE(remote.find(conflictMap[a2FileId])->contentSize, 5); - QCOMPARE(remote.find(QStringLiteral("A/a2"))->contentSize, 6); - } - } - - void testSeparateUpload() - { - QFETCH_GLOBAL(Vfs::Mode, vfsMode); - QFETCH_GLOBAL(bool, filesAreDehydrated); - - FakeFolder fakeFolder(FileInfo::A12_B12_C12_S12(), vfsMode, filesAreDehydrated); - fakeFolder.account()->setCapabilities({fakeFolder.account()->url(), uploadConflictFilesCapabilities(true)}); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - - QMap conflictMap; - fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *) -> QNetworkReply * { - if (op == QNetworkAccessManager::PutOperation) { - if (request.rawHeader("OC-Conflict") == "1") { - auto baseFileId = request.rawHeader("OC-ConflictBaseFileId"); - auto components = request.url().toString().split(QLatin1Char('/')); - QString conflictFile = components.mid(components.size() - 2).join(QLatin1Char('/')); - conflictMap[baseFileId] = conflictFile; - [&] { - QVERIFY(!baseFileId.isEmpty()); - QCOMPARE(request.rawHeader("OC-ConflictInitialBasePath"), - Utility::conflictFileBaseNameFromPattern(conflictFile.toUtf8())); - }(); - } - } - return nullptr; - }); - - // Explicitly add a conflict file to simulate the case where the upload of the - // file didn't finish in the same sync run that the conflict was created. - // To do that we need to create a mock conflict record. - auto a1FileId = fakeFolder.remoteModifier().find(QStringLiteral("A/a1"))->fileId; - QString conflictName = QStringLiteral("A/a1 (conflicted copy me 1234)"); - fakeFolder.localModifier().insert(conflictName, FileModifier::DefaultFileSize, 'L'); - ConflictRecord conflictRecord; - conflictRecord.path = conflictName.toUtf8(); - conflictRecord.baseFileId = a1FileId; - conflictRecord.initialBasePath = "A/a1"; - fakeFolder.syncJournal().setConflictRecord(conflictRecord); - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - QCOMPARE(conflictMap.size(), 1); - QCOMPARE(conflictMap[a1FileId], conflictName); - QCOMPARE(fakeFolder.currentRemoteState().find(conflictMap[a1FileId])->contentChar, 'L'); - conflictMap.clear(); - - // Now the user can locally alter the conflict file and it will be uploaded - // as usual. - fakeFolder.localModifier().setContents(conflictName, FileModifier::DefaultFileSize + 1, 'P'); // make sure the file sizes are different - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - QCOMPARE(conflictMap.size(), 1); - QCOMPARE(conflictMap[a1FileId], conflictName); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - conflictMap.clear(); - - // Similarly, remote modifications of conflict files get propagated downwards - fakeFolder.remoteModifier().setContents(conflictName, FileModifier::DefaultFileSize + 1, 'Q'); // make sure the file sizes are different - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - QVERIFY(conflictMap.isEmpty()); - - // Conflict files for conflict files! - auto a1ConflictFileId = fakeFolder.remoteModifier().find(conflictName)->fileId; - fakeFolder.remoteModifier().appendByte(conflictName); - fakeFolder.remoteModifier().appendByte(conflictName); - fakeFolder.localModifier().appendByte(conflictName); - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - QCOMPARE(conflictMap.size(), 1); - QVERIFY(conflictMap.contains(a1ConflictFileId)); - QCOMPARE(fakeFolder.currentRemoteState().find(conflictName)->contentSize, FileModifier::DefaultFileSize + 3); - QCOMPARE(fakeFolder.currentRemoteState().find(conflictMap[a1ConflictFileId])->contentSize, FileModifier::DefaultFileSize + 2); - conflictMap.clear(); - } - - // What happens if we download a conflict file? Is the metadata set up correctly? - void testDownloadingConflictFile() - { - QFETCH_GLOBAL(Vfs::Mode, vfsMode); - QFETCH_GLOBAL(bool, filesAreDehydrated); - - FakeFolder fakeFolder(FileInfo::A12_B12_C12_S12(), vfsMode, filesAreDehydrated); - fakeFolder.account()->setCapabilities({fakeFolder.account()->url(), uploadConflictFilesCapabilities(true)}); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - - // With no headers from the server - fakeFolder.remoteModifier().insert(QStringLiteral("A/a1 (conflicted copy 1234)")); - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - auto conflictRecord = fakeFolder.syncJournal().conflictRecord("A/a1 (conflicted copy 1234)"); - QVERIFY(conflictRecord.isValid()); - QCOMPARE(conflictRecord.baseFileId, fakeFolder.remoteModifier().find(QStringLiteral("A/a1"))->fileId); - QCOMPARE(conflictRecord.initialBasePath, QByteArray("A/a1")); - - // Now with server headers - QObject parent; - auto a2FileId = fakeFolder.remoteModifier().find(QStringLiteral("A/a2"))->fileId; - fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *) -> QNetworkReply * { - if (op == QNetworkAccessManager::GetOperation) { - auto reply = new FakeGetReply(fakeFolder.remoteModifier(), op, request, &parent); - reply->setRawHeader("OC-Conflict", "1"); - reply->setRawHeader("OC-ConflictBaseFileId", a2FileId); - reply->setRawHeader("OC-ConflictBaseMtime", "1234"); - reply->setRawHeader("OC-ConflictBaseEtag", "etag"); - reply->setRawHeader("OC-ConflictInitialBasePath", "A/original"); - return reply; - } - return nullptr; - }); - fakeFolder.remoteModifier().insert(QStringLiteral("A/really-a-conflict")); // doesn't look like a conflict, but headers say it is - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); - - conflictRecord = fakeFolder.syncJournal().conflictRecord("A/really-a-conflict"); - - if (filesAreDehydrated) { - // A placeholder for the conflicting file is created, but no actual GET request is made, so there should be no conflict record - QVERIFY(!conflictRecord.isValid()); - } else { - QVERIFY(conflictRecord.isValid()); - QCOMPARE(conflictRecord.baseFileId, a2FileId); - QCOMPARE(conflictRecord.baseModtime, 1234); - QCOMPARE(conflictRecord.baseEtag, QByteArray("etag")); - QCOMPARE(conflictRecord.initialBasePath, QByteArray("A/original")); - } - } - // Check that conflict records are removed when the file is gone void testConflictRecordRemoval1() { @@ -321,7 +128,6 @@ private Q_SLOTS: QFETCH_GLOBAL(bool, filesAreDehydrated); FakeFolder fakeFolder(FileInfo::A12_B12_C12_S12(), vfsMode, filesAreDehydrated); - fakeFolder.account()->setCapabilities({fakeFolder.account()->url(), uploadConflictFilesCapabilities(true)}); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); // Make conflict records @@ -345,14 +151,12 @@ private Q_SLOTS: QVERIFY(!fakeFolder.syncJournal().conflictRecord("A/a2").isValid()); } - // Same test, but with uploadConflictFiles == false void testConflictRecordRemoval2() { QFETCH_GLOBAL(Vfs::Mode, vfsMode); QFETCH_GLOBAL(bool, filesAreDehydrated); FakeFolder fakeFolder(FileInfo::A12_B12_C12_S12(), vfsMode, filesAreDehydrated); - fakeFolder.account()->setCapabilities({fakeFolder.account()->url(), uploadConflictFilesCapabilities(false)}); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); // Create two conflicts @@ -478,7 +282,6 @@ private Q_SLOTS: QFETCH_GLOBAL(bool, filesAreDehydrated); FakeFolder fakeFolder(FileInfo::A12_B12_C12_S12(), vfsMode, filesAreDehydrated); - fakeFolder.account()->setCapabilities({fakeFolder.account()->url(), uploadConflictFilesCapabilities(true)}); ItemCompletedSpy completeSpy(fakeFolder); auto cleanup = [&]() { @@ -541,20 +344,6 @@ private Q_SLOTS: QCOMPARE(conflicts[1].toUtf8(), conflictRecords[1]); QVERIFY(QFileInfo(fakeFolder.localPath() + conflicts[1]).isDir()); QVERIFY(QFile::exists(fakeFolder.localPath() + conflicts[1] + QStringLiteral("/zzz"))); - - // The contents of the conflict directories will only be uploaded after - // another sync. - QCOMPARE(fakeFolder.syncEngine().isAnotherSyncNeeded(), true); - cleanup(); - QVERIFY(fakeFolder.applyLocalModificationsAndSync()); - - QVERIFY(itemSuccessful(completeSpy, conflicts[0], CSYNC_INSTRUCTION_NEW)); - QVERIFY(itemSuccessful(completeSpy, conflicts[0] + QStringLiteral("/bar"), CSYNC_INSTRUCTION_NEW)); - QVERIFY(itemSuccessful(completeSpy, conflicts[1], CSYNC_INSTRUCTION_NEW)); - QVERIFY(itemSuccessful(completeSpy, conflicts[1] + QStringLiteral("/zzz"), CSYNC_INSTRUCTION_NEW)); - QVERIFY(itemSuccessful(completeSpy, conflicts[2], CSYNC_INSTRUCTION_NEW)); - QVERIFY(itemSuccessful(completeSpy, conflicts[2] + QStringLiteral("/foo"), CSYNC_INSTRUCTION_NEW)); - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); } void testLocalFileRemoteDirConflict() @@ -563,7 +352,6 @@ private Q_SLOTS: QFETCH_GLOBAL(bool, filesAreDehydrated); FakeFolder fakeFolder(FileInfo::A12_B12_C12_S12(), vfsMode, filesAreDehydrated); - fakeFolder.account()->setCapabilities({fakeFolder.account()->url(), uploadConflictFilesCapabilities(true)}); ItemCompletedSpy completeSpy(fakeFolder); // 1) a NEW/NEW conflict @@ -620,9 +408,6 @@ private Q_SLOTS: QVERIFY(itemConflict(completeSpy, QStringLiteral("B/b1"))); QVERIFY(conflicts[1].contains(QStringLiteral("B/b1"))); QCOMPARE(conflicts[1].toUtf8(), conflictRecords[1]); - - // Also verifies that conflicts were uploaded - QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); } void testTypeConflictWithMove()