diff --git a/src/libsync/bulkpropagatorjob.cpp b/src/libsync/bulkpropagatorjob.cpp index 58e1ab82f0c95..2d06298fe1088 100644 --- a/src/libsync/bulkpropagatorjob.cpp +++ b/src/libsync/bulkpropagatorjob.cpp @@ -520,6 +520,7 @@ void BulkPropagatorJob::finalize(const QJsonObject &fullReply) } if (!singleFile._item->hasErrorStatus()) { finalizeOneFile(singleFile); + singleFile._item->_status = OCC::SyncFileItem::Success; } done(singleFile._item, singleFile._item->_status, {}, ErrorCategory::GenericError); diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index d486f861da03f..16e68c96b5ac6 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -532,7 +532,10 @@ qint64 UploadDevice::readData(char *data, qint64 maxlen) } auto c = _file.read(data, maxlen); - if (c < 0) { + if (c == 0) { + setErrorString({}); + return c; + } else if (c < 0) { setErrorString(_file.errorString()); return -1; } diff --git a/test/syncenginetestutils.cpp b/test/syncenginetestutils.cpp index 39edfc6537abd..d3f351f1c725d 100644 --- a/test/syncenginetestutils.cpp +++ b/test/syncenginetestutils.cpp @@ -552,12 +552,12 @@ QVector FakePutMultiFileReply::performMultiPart(FileInfo &remoteRoot auto onePartBody = onePart.mid(headerEndPosition + 4, onePart.size() - headerEndPosition - 6); auto onePartHeaders = onePartHeaderPart.split(QStringLiteral("\r\n")); QMap allHeaders; - for(auto oneHeader : onePartHeaders) { + for(const auto &oneHeader : onePartHeaders) { auto headerParts = oneHeader.split(QStringLiteral(": ")); - allHeaders[headerParts.at(0)] = headerParts.at(1); + allHeaders[headerParts.at(0).toLower()] = headerParts.at(1); } - const auto fileName = allHeaders[QStringLiteral("X-File-Path")]; - const auto modtime = allHeaders[QByteArrayLiteral("X-File-Mtime")].toLongLong(); + const auto fileName = allHeaders[QStringLiteral("x-file-path")]; + const auto modtime = allHeaders[QByteArrayLiteral("x-file-mtime")].toLongLong(); Q_ASSERT(!fileName.isEmpty()); Q_ASSERT(modtime > 0); FileInfo *fileInfo = remoteRootFileInfo.find(fileName); @@ -568,7 +568,7 @@ QVector FakePutMultiFileReply::performMultiPart(FileInfo &remoteRoot // Assume that the file is filled with the same character fileInfo = remoteRootFileInfo.create(fileName, onePartBody.size(), onePartBody.at(0).toLatin1()); } - fileInfo->lastModified = OCC::Utility::qDateTimeFromTime_t(request.rawHeader("X-OC-Mtime").toLongLong()); + fileInfo->lastModified = OCC::Utility::qDateTimeFromTime_t(request.rawHeader("x-oc-mtime").toLongLong()); remoteRootFileInfo.find(fileName, /*invalidateEtags=*/true); result.push_back(fileInfo); } @@ -1052,13 +1052,13 @@ QJsonObject FakeQNAM::forEachReplyPart(QIODevice *outgoingData, QMap allHeaders; for(const auto &oneHeader : qAsConst(onePartHeaders)) { auto headerParts = oneHeader.split(QStringLiteral(": ")); - allHeaders[headerParts.at(0)] = headerParts.at(1).toLatin1(); + allHeaders[headerParts.at(0).toLower()] = headerParts.at(1).toLatin1(); } auto reply = replyFunction(allHeaders); if (reply.contains(QStringLiteral("error")) && reply.contains(QStringLiteral("etag"))) { - fullReply.insert(allHeaders[QStringLiteral("X-File-Path")], reply); + fullReply.insert(allHeaders[QStringLiteral("x-file-path")], reply); } } @@ -1413,3 +1413,46 @@ FakeFileLockReply::FakeFileLockReply(FileInfo &remoteRootFileInfo, xml.writeEndElement(); // prop xml.writeEndDocument(); } + +FakeJsonReply::FakeJsonReply(QNetworkAccessManager::Operation op, + const QNetworkRequest &request, + QObject *parent, + int httpReturnCode, + const QJsonDocument &reply) + : FakeReply{parent} + , _body{reply.toJson()} +{ + setRequest(request); + setUrl(request.url()); + setOperation(op); + open(QIODevice::ReadOnly); + setAttribute(QNetworkRequest::HttpStatusCodeAttribute, httpReturnCode); + QMetaObject::invokeMethod(this, &FakeJsonReply::respond, Qt::QueuedConnection); +} + +void FakeJsonReply::respond() +{ + emit metaDataChanged(); + emit readyRead(); + // finishing can come strictly after readyRead was called + QTimer::singleShot(5, this, &FakeJsonReply::slotSetFinished); +} + +void FakeJsonReply::slotSetFinished() +{ + setFinished(true); + emit finished(); +} + +qint64 FakeJsonReply::readData(char *buf, qint64 max) +{ + max = qMin(max, _body.size()); + memcpy(buf, _body.constData(), max); + _body = _body.mid(max); + return max; +} + +qint64 FakeJsonReply::bytesAvailable() const +{ + return _body.size(); +} diff --git a/test/syncenginetestutils.h b/test/syncenginetestutils.h index dca0eb02b92a4..fee77f1494c89 100644 --- a/test/syncenginetestutils.h +++ b/test/syncenginetestutils.h @@ -214,6 +214,29 @@ class FakeReply : public QNetworkReply using QNetworkReply::setRawHeader; }; +class FakeJsonReply : public FakeReply +{ + Q_OBJECT +public: + FakeJsonReply(QNetworkAccessManager::Operation op, + const QNetworkRequest &request, + QObject *parent, + int httpReturnCode, + const QJsonDocument &reply = QJsonDocument()); + + Q_INVOKABLE virtual void respond(); + +public slots: + void slotSetFinished(); + +public: + void abort() override { } + qint64 readData(char *buf, qint64 max) override; + [[nodiscard]] qint64 bytesAvailable() const override; + + QByteArray _body; +}; + class FakePropfindReply : public FakeReply { Q_OBJECT diff --git a/test/testsyncengine.cpp b/test/testsyncengine.cpp index c46a9f7ab0143..c745ddcad4ffe 100644 --- a/test/testsyncengine.cpp +++ b/test/testsyncengine.cpp @@ -984,15 +984,17 @@ private slots: if (op == QNetworkAccessManager::PostOperation) { ++nPOST; if (contentType.startsWith(QStringLiteral("multipart/related; boundary="))) { - auto jsonReplyObject = fakeFolder.forEachReplyPart(outgoingData, contentType, [] (const QMap &allHeaders) -> QJsonObject { + auto hasAnError = false; + auto jsonReplyObject = fakeFolder.forEachReplyPart(outgoingData, contentType, [&hasAnError] (const QMap &allHeaders) -> QJsonObject { auto reply = QJsonObject{}; - const auto fileName = allHeaders[QStringLiteral("X-File-Path")]; + const auto fileName = allHeaders[QStringLiteral("x-file-path")]; if (fileName.endsWith("A/big2") || fileName.endsWith("A/big3") || fileName.endsWith("A/big4") || fileName.endsWith("A/big5") || fileName.endsWith("A/big7") || fileName.endsWith("B/big8")) { + hasAnError = true; reply.insert(QStringLiteral("error"), true); reply.insert(QStringLiteral("etag"), {}); return reply; @@ -1005,7 +1007,11 @@ private slots: if (jsonReplyObject.size()) { auto jsonReply = QJsonDocument{}; jsonReply.setObject(jsonReplyObject); - return new FakeJsonErrorReply{op, request, this, 200, jsonReply}; + if (hasAnError) { + return new FakeJsonErrorReply{op, request, this, 200, jsonReply}; + } else { + return new FakeJsonReply{op, request, this, 200, jsonReply}; + } } return nullptr; }