Skip to content

Commit 7a41a56

Browse files
authored
Merge pull request #7580 from nextcloud/bugfix/fixAutomatedTestsOnWindows
fix regressions in automated tests for bulk upload
2 parents 588ff4b + 49267b8 commit 7a41a56

8 files changed

+100
-19
lines changed

src/libsync/bulkpropagatorjob.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ void BulkPropagatorJob::finalize(const QJsonObject &fullReply)
520520
}
521521
if (!singleFile._item->hasErrorStatus()) {
522522
finalizeOneFile(singleFile);
523+
singleFile._item->_status = OCC::SyncFileItem::Success;
523524
}
524525

525526
done(singleFile._item, singleFile._item->_status, {}, ErrorCategory::GenericError);

src/libsync/propagateupload.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,10 @@ qint64 UploadDevice::readData(char *data, qint64 maxlen)
532532
}
533533

534534
auto c = _file.read(data, maxlen);
535-
if (c < 0) {
535+
if (c == 0) {
536+
setErrorString({});
537+
return c;
538+
} else if (c < 0) {
536539
setErrorString(_file.errorString());
537540
return -1;
538541
}

src/libsync/vfs/cfapi/vfs_cfapi.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ Vfs::AvailabilityResult VfsCfApi::availability(const QString &folderPath, const
354354
break;
355355
};
356356
return VfsItemAvailability::Mixed;
357-
} else {
357+
} else if (basePinState) {
358358
const auto hydrationAndPinStates = computeRecursiveHydrationAndPinStates(folderPath, basePinState);
359359

360360
const auto pin = hydrationAndPinStates.pinState;
@@ -382,6 +382,8 @@ Vfs::AvailabilityResult VfsCfApi::availability(const QString &folderPath, const
382382
}
383383
}
384384
return AvailabilityError::NoSuchItem;
385+
} else {
386+
return AvailabilityError::NoSuchItem;
385387
}
386388
}
387389

test/syncenginetestutils.cpp

+50-7
Original file line numberDiff line numberDiff line change
@@ -552,12 +552,12 @@ QVector<FileInfo *> FakePutMultiFileReply::performMultiPart(FileInfo &remoteRoot
552552
auto onePartBody = onePart.mid(headerEndPosition + 4, onePart.size() - headerEndPosition - 6);
553553
auto onePartHeaders = onePartHeaderPart.split(QStringLiteral("\r\n"));
554554
QMap<QString, QString> allHeaders;
555-
for(auto oneHeader : onePartHeaders) {
555+
for(const auto &oneHeader : onePartHeaders) {
556556
auto headerParts = oneHeader.split(QStringLiteral(": "));
557-
allHeaders[headerParts.at(0)] = headerParts.at(1);
557+
allHeaders[headerParts.at(0).toLower()] = headerParts.at(1);
558558
}
559-
const auto fileName = allHeaders[QStringLiteral("X-File-Path")];
560-
const auto modtime = allHeaders[QByteArrayLiteral("X-File-Mtime")].toLongLong();
559+
const auto fileName = allHeaders[QStringLiteral("x-file-path")];
560+
const auto modtime = allHeaders[QByteArrayLiteral("x-file-mtime")].toLongLong();
561561
Q_ASSERT(!fileName.isEmpty());
562562
Q_ASSERT(modtime > 0);
563563
FileInfo *fileInfo = remoteRootFileInfo.find(fileName);
@@ -568,7 +568,7 @@ QVector<FileInfo *> FakePutMultiFileReply::performMultiPart(FileInfo &remoteRoot
568568
// Assume that the file is filled with the same character
569569
fileInfo = remoteRootFileInfo.create(fileName, onePartBody.size(), onePartBody.at(0).toLatin1());
570570
}
571-
fileInfo->lastModified = OCC::Utility::qDateTimeFromTime_t(request.rawHeader("X-OC-Mtime").toLongLong());
571+
fileInfo->lastModified = OCC::Utility::qDateTimeFromTime_t(request.rawHeader("x-oc-mtime").toLongLong());
572572
remoteRootFileInfo.find(fileName, /*invalidateEtags=*/true);
573573
result.push_back(fileInfo);
574574
}
@@ -1052,13 +1052,13 @@ QJsonObject FakeQNAM::forEachReplyPart(QIODevice *outgoingData,
10521052
QMap<QString, QByteArray> allHeaders;
10531053
for(const auto &oneHeader : qAsConst(onePartHeaders)) {
10541054
auto headerParts = oneHeader.split(QStringLiteral(": "));
1055-
allHeaders[headerParts.at(0)] = headerParts.at(1).toLatin1();
1055+
allHeaders[headerParts.at(0).toLower()] = headerParts.at(1).toLatin1();
10561056
}
10571057

10581058
auto reply = replyFunction(allHeaders);
10591059
if (reply.contains(QStringLiteral("error")) &&
10601060
reply.contains(QStringLiteral("etag"))) {
1061-
fullReply.insert(allHeaders[QStringLiteral("X-File-Path")], reply);
1061+
fullReply.insert(allHeaders[QStringLiteral("x-file-path")], reply);
10621062
}
10631063
}
10641064

@@ -1413,3 +1413,46 @@ FakeFileLockReply::FakeFileLockReply(FileInfo &remoteRootFileInfo,
14131413
xml.writeEndElement(); // prop
14141414
xml.writeEndDocument();
14151415
}
1416+
1417+
FakeJsonReply::FakeJsonReply(QNetworkAccessManager::Operation op,
1418+
const QNetworkRequest &request,
1419+
QObject *parent,
1420+
int httpReturnCode,
1421+
const QJsonDocument &reply)
1422+
: FakeReply{parent}
1423+
, _body{reply.toJson()}
1424+
{
1425+
setRequest(request);
1426+
setUrl(request.url());
1427+
setOperation(op);
1428+
open(QIODevice::ReadOnly);
1429+
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, httpReturnCode);
1430+
QMetaObject::invokeMethod(this, &FakeJsonReply::respond, Qt::QueuedConnection);
1431+
}
1432+
1433+
void FakeJsonReply::respond()
1434+
{
1435+
emit metaDataChanged();
1436+
emit readyRead();
1437+
// finishing can come strictly after readyRead was called
1438+
QTimer::singleShot(5, this, &FakeJsonReply::slotSetFinished);
1439+
}
1440+
1441+
void FakeJsonReply::slotSetFinished()
1442+
{
1443+
setFinished(true);
1444+
emit finished();
1445+
}
1446+
1447+
qint64 FakeJsonReply::readData(char *buf, qint64 max)
1448+
{
1449+
max = qMin<qint64>(max, _body.size());
1450+
memcpy(buf, _body.constData(), max);
1451+
_body = _body.mid(max);
1452+
return max;
1453+
}
1454+
1455+
qint64 FakeJsonReply::bytesAvailable() const
1456+
{
1457+
return _body.size();
1458+
}

test/syncenginetestutils.h

+23
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,29 @@ class FakeReply : public QNetworkReply
214214
using QNetworkReply::setRawHeader;
215215
};
216216

217+
class FakeJsonReply : public FakeReply
218+
{
219+
Q_OBJECT
220+
public:
221+
FakeJsonReply(QNetworkAccessManager::Operation op,
222+
const QNetworkRequest &request,
223+
QObject *parent,
224+
int httpReturnCode,
225+
const QJsonDocument &reply = QJsonDocument());
226+
227+
Q_INVOKABLE virtual void respond();
228+
229+
public slots:
230+
void slotSetFinished();
231+
232+
public:
233+
void abort() override { }
234+
qint64 readData(char *buf, qint64 max) override;
235+
[[nodiscard]] qint64 bytesAvailable() const override;
236+
237+
QByteArray _body;
238+
};
239+
217240
class FakePropfindReply : public FakeReply
218241
{
219242
Q_OBJECT

test/testlocaldiscovery.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ private slots:
378378
const QString fileWithSpaces4("A/ foo");
379379
const QString fileWithSpaces5("A/ bar ");
380380
const QString fileWithSpaces6("A/bla ");
381+
const auto extraFileNameWithSpaces = QStringLiteral(" with spaces ");
381382

382383
fakeFolder.localModifier().insert(fileWithSpaces1);
383384
fakeFolder.localModifier().insert(fileWithSpaces2);
@@ -386,7 +387,7 @@ private slots:
386387
fakeFolder.localModifier().insert(fileWithSpaces4);
387388
fakeFolder.localModifier().insert(fileWithSpaces5);
388389
fakeFolder.localModifier().insert(fileWithSpaces6);
389-
fakeFolder.localModifier().mkdir(QStringLiteral(" with spaces "));
390+
fakeFolder.localModifier().mkdir(extraFileNameWithSpaces);
390391

391392
ItemCompletedSpy completeSpy(fakeFolder);
392393
completeSpy.clear();
@@ -400,15 +401,15 @@ private slots:
400401
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
401402
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
402403
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
403-
QCOMPARE(completeSpy.findItem(QStringLiteral(" with spaces "))->_status, SyncFileItem::Status::FileNameInvalid);
404+
QCOMPARE(completeSpy.findItem(extraFileNameWithSpaces)->_status, SyncFileItem::Status::FileNameInvalid);
404405
#else
405406
QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::Success);
406407
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::Success);
407408
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::Success);
408409
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
409410
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
410411
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
411-
QCOMPARE(completeSpy.findItem(QStringLiteral(" with spaces "))->_status, SyncFileItem::Status::Success);
412+
QCOMPARE(completeSpy.findItem(extraFileNameWithSpaces)->_status, SyncFileItem::Status::Success);
412413
#endif
413414

414415
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces1);
@@ -417,7 +418,7 @@ private slots:
417418
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces4);
418419
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces5);
419420
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces6);
420-
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + QStringLiteral(" with spaces "));
421+
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + extraFileNameWithSpaces);
421422

422423
completeSpy.clear();
423424

@@ -431,7 +432,7 @@ private slots:
431432
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
432433
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
433434
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
434-
QCOMPARE(completeSpy.findItem(QStringLiteral(" with spaces "))->_status, SyncFileItem::Status::NormalError);
435+
QCOMPARE(completeSpy.findItem(extraFileNameWithSpaces)->_status, SyncFileItem::Status::Success);
435436
#endif
436437
}
437438

test/testsyncconflictsmodel.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <QTest>
2525
#include <QAbstractItemModelTester>
2626
#include <QSignalSpy>
27+
#include <QLocale>
2728

2829
namespace {
2930

@@ -47,6 +48,7 @@ class TestSyncConflictsModel : public QObject
4748
Q_OBJECT
4849

4950
private:
51+
QLocale _locale;
5052

5153
private slots:
5254
void initTestCase()
@@ -104,8 +106,8 @@ private slots:
104106

105107
QCOMPARE(model.rowCount(), 1);
106108
QCOMPARE(model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ExistingFileName)), QString{"a2"});
107-
QCOMPARE(model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ExistingSize)), QString{"6 bytes"});
108-
QCOMPARE(model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ConflictSize)), QString{"5 bytes"});
109+
QCOMPARE(model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ExistingSize)), _locale.formattedDataSize(6));
110+
QCOMPARE(model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ConflictSize)), _locale.formattedDataSize(5));
109111
QVERIFY(!model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ExistingDate)).toString().isEmpty());
110112
QVERIFY(!model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ConflictDate)).toString().isEmpty());
111113
QCOMPARE(model.data(model.index(0), static_cast<int>(SyncConflictsModel::SyncConflictRoles::ExistingPreviewUrl)), QVariant::fromValue(QUrl{QStringLiteral("image://tray-image-provider/:/fileicon%1A/a2").arg(fakeFolder.localPath())}));

test/testsyncengine.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -984,15 +984,17 @@ private slots:
984984
if (op == QNetworkAccessManager::PostOperation) {
985985
++nPOST;
986986
if (contentType.startsWith(QStringLiteral("multipart/related; boundary="))) {
987-
auto jsonReplyObject = fakeFolder.forEachReplyPart(outgoingData, contentType, [] (const QMap<QString, QByteArray> &allHeaders) -> QJsonObject {
987+
auto hasAnError = false;
988+
auto jsonReplyObject = fakeFolder.forEachReplyPart(outgoingData, contentType, [&hasAnError] (const QMap<QString, QByteArray> &allHeaders) -> QJsonObject {
988989
auto reply = QJsonObject{};
989-
const auto fileName = allHeaders[QStringLiteral("X-File-Path")];
990+
const auto fileName = allHeaders[QStringLiteral("x-file-path")];
990991
if (fileName.endsWith("A/big2") ||
991992
fileName.endsWith("A/big3") ||
992993
fileName.endsWith("A/big4") ||
993994
fileName.endsWith("A/big5") ||
994995
fileName.endsWith("A/big7") ||
995996
fileName.endsWith("B/big8")) {
997+
hasAnError = true;
996998
reply.insert(QStringLiteral("error"), true);
997999
reply.insert(QStringLiteral("etag"), {});
9981000
return reply;
@@ -1005,7 +1007,11 @@ private slots:
10051007
if (jsonReplyObject.size()) {
10061008
auto jsonReply = QJsonDocument{};
10071009
jsonReply.setObject(jsonReplyObject);
1008-
return new FakeJsonErrorReply{op, request, this, 200, jsonReply};
1010+
if (hasAnError) {
1011+
return new FakeJsonErrorReply{op, request, this, 200, jsonReply};
1012+
} else {
1013+
return new FakeJsonReply{op, request, this, 200, jsonReply};
1014+
}
10091015
}
10101016
return nullptr;
10111017
}

0 commit comments

Comments
 (0)