diff options
-rw-r--r-- | src/libsync/propagateupload.cpp | 6 | ||||
-rw-r--r-- | src/libsync/propagateupload.h | 9 | ||||
-rw-r--r-- | test/syncenginetestutils.h | 3 | ||||
-rw-r--r-- | test/testsyncengine.cpp | 27 |
4 files changed, 44 insertions, 1 deletions
diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index c2d5c387d..a8b260515 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -564,6 +564,8 @@ void PropagateUploadFileCommon::slotJobDestroyed(QObject *job) // This function is used whenever there is an error occuring and jobs might be in progress void PropagateUploadFileCommon::abortWithError(SyncFileItem::Status status, const QString &error) { + if (_aborting) + return; abort(AbortType::Synchronous); done(status, error); } @@ -636,6 +638,10 @@ void PropagateUploadFileCommon::abortNetworkJobs( PropagatorJob::AbortType abortType, const std::function<bool(AbstractNetworkJob *)> &mayAbortJob) { + if (_aborting) + return; + _aborting = true; + // Count the number of jobs that need aborting, and emit the overall // abort signal when they're all done. QSharedPointer<int> runningCount(new int(0)); diff --git a/src/libsync/propagateupload.h b/src/libsync/propagateupload.h index b0c609d2c..f7bd69803 100644 --- a/src/libsync/propagateupload.h +++ b/src/libsync/propagateupload.h @@ -209,6 +209,14 @@ protected: QVector<AbstractNetworkJob *> _jobs; /// network jobs that are currently in transit bool _finished BITFIELD(1); /// Tells that all the jobs have been finished bool _deleteExisting BITFIELD(1); + + /** Whether an abort is currently ongoing. + * + * Important to avoid duplicate aborts since each finishing PUTFileJob might + * trigger an abort on error. + */ + bool _aborting BITFIELD(1); + QByteArray _transmissionChecksumHeader; public: @@ -216,6 +224,7 @@ public: : PropagateItemJob(propagator, item) , _finished(false) , _deleteExisting(false) + , _aborting(false) { } diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index f1790b588..a515c7e1d 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -728,7 +728,7 @@ public: QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection); } - Q_INVOKABLE void respond() { + Q_INVOKABLE virtual void respond() { setAttribute(QNetworkRequest::HttpStatusCodeAttribute, _httpErrorCode); setError(InternalServerError, "Internal Server Fake Error"); emit metaDataChanged(); @@ -910,6 +910,7 @@ public: _account->setUrl(QUrl(QStringLiteral("http://admin:admin@localhost/owncloud"))); _account->setCredentials(new FakeCredentials{_fakeQnam}); _account->setDavDisplayName("fakename"); + _account->setServerVersion("10.0.0"); _journalDb.reset(new OCC::SyncJournalDb(localPath() + "._sync_test.db")); _syncEngine.reset(new OCC::SyncEngine(_account, localPath(), "", _journalDb.get())); diff --git a/test/testsyncengine.cpp b/test/testsyncengine.cpp index ef45c0aa1..65321bfed 100644 --- a/test/testsyncengine.cpp +++ b/test/testsyncengine.cpp @@ -649,6 +649,33 @@ private slots: QTextCodec::setCodecForLocale(utf8Locale); #endif } + + // Aborting has had bugs when there are parallel upload jobs + void testUploadV1Multiabort() + { + FakeFolder fakeFolder{ FileInfo{} }; + SyncOptions options; + options._initialChunkSize = 10; + options._maxChunkSize = 10; + options._minChunkSize = 10; + fakeFolder.syncEngine().setSyncOptions(options); + + QObject parent; + int nPUT = 0; + fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *) -> QNetworkReply * { + if (op == QNetworkAccessManager::PutOperation) { + ++nPUT; + return new FakeHangingReply(op, request, &parent); + } + return nullptr; + }); + + fakeFolder.localModifier().insert("file", 100, 'W'); + QTimer::singleShot(100, &fakeFolder.syncEngine(), [&]() { fakeFolder.syncEngine().abort(); }); + QVERIFY(!fakeFolder.syncOnce()); + + QCOMPARE(nPUT, 3); + } }; QTEST_GUILESS_MAIN(TestSyncEngine) |