: PropagateItemJob(propagator, item)
, _finished(false)
, _deleteExisting(false)
+ , _aborting(false)
, _parallelism(FullParallelism)
, _uploadEncryptedHelper(nullptr)
, _uploadingEncrypted(false)
// 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);
}
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));
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);
+
/* This is a minified version of the SyncFileItem,
* that holds only the specifics about the file that's
* being uploaded.
QMetaObject::invokeMethod(this, "respond", Qt::QueuedConnection);
}
- Q_INVOKABLE void respond() {
+ Q_INVOKABLE virtual void respond() {
emit metaDataChanged();
emit readyRead();
// finishing can come strictly after readyRead was called
_account->setUrl(QUrl(QStringLiteral("http://admin:admin@localhost/owncloud")));
_account->setCredentials(new FakeCredentials{_fakeQnam});
_account->setDavDisplayName("fakename");
+ _account->setServerVersion("10.0.0");
_journalDb = std::make_unique<OCC::SyncJournalDb>(localPath() + "._sync_test.db");
_syncEngine = std::make_unique<OCC::SyncEngine>(_account, localPath(), "", _journalDb.get());
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)