Skip to content

Commit

Permalink
Upload: Added tests and fixed one existing
Browse files Browse the repository at this point in the history
Signed-off-by: Juergen Kellerer <juergen@k123.eu>
  • Loading branch information
jkellerer committed Aug 11, 2022
1 parent bb2e0ab commit 9ef12fb
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 4 deletions.
41 changes: 41 additions & 0 deletions test/testaccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,47 @@ private slots:
AccountPtr account = Account::create();
account->davPath();
}

void testAccountMaxRequestSize_initial_minusOne()
{
QCOMPARE( Account::create()->getMaxRequestSize(), -1 );
}

void testAccountMaxRequestSize_readWrite()
{
auto account = Account::create();
QVERIFY( account->getMaxRequestSize() == -1 );

for (qint64 i = -2; i < 100000000000; i += 100000) {
QVERIFY( i != account->getMaxRequestSize() );

account->setMaxRequestSize(i);
QCOMPARE( i, account->getMaxRequestSize() );
}
}

void testAccountMaxRequestSize_writeIfLower()
{
using Test = std::pair<qint64,qint64>; // <input,expected-output>
std::vector<Test> tests{
Test(10000, 10000),
Test(-1, -1), // reset with -1
Test(1, 1),
Test(2, 1),
Test(0, 0), // reset with 0
Test(1000, 1000),
Test(1100, 1000),
Test(900, 900),
Test(80, 80),
Test(1000, 80),
};

auto account = Account::create();
for (auto test : tests) {
account->setMaxRequestSizeIfLower(test.first);
QCOMPARE( test.second, account->getMaxRequestSize() );
}
}
};

QTEST_APPLESS_MAIN(TestAccount)
Expand Down
41 changes: 41 additions & 0 deletions test/testnextcloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <QtTest>
#include <QDebug>

#include "account.h"
#include "propagatedownload.h"
#include "owncloudpropagator_p.h"

Expand Down Expand Up @@ -76,6 +77,46 @@ private slots:
QCOMPARE(parseEtag(test.first), QByteArray(test.second));
}
}

void testRespectsLowestPossibleChunkSize()
{
QSet<QString> __blacklist;
OwncloudPropagator propagator(OCC::Account::create(), "", "", nullptr, __blacklist);
auto opts = propagator.syncOptions();

opts._minChunkSize =
opts._initialChunkSize =
opts._maxChunkSize = 0;

propagator.setSyncOptions(opts);

opts = propagator.syncOptions();
QCOMPARE( opts._minChunkSize, 512 * 1024 );
QCOMPARE( opts._initialChunkSize, 512 * 1024 );
QCOMPARE( opts._maxChunkSize, 512 * 1024 );
}

void testLimitsMaxChunkSizeByAccount()
{
QSet<QString> __blacklist;
OwncloudPropagator propagator(OCC::Account::create(), "", "", nullptr, __blacklist);
auto opts = propagator.syncOptions();

SyncOptions defaultOpts;
QCOMPARE( opts._minChunkSize, defaultOpts._minChunkSize );
QVERIFY( opts._minChunkSize < defaultOpts._maxChunkSize );
QVERIFY( opts._minChunkSize < defaultOpts._initialChunkSize );
QCOMPARE( opts._initialChunkSize, defaultOpts._initialChunkSize );
QCOMPARE( opts._maxChunkSize, defaultOpts._maxChunkSize );

propagator.account()->setMaxRequestSizeIfLower(defaultOpts._minChunkSize);
propagator.setSyncOptions(opts);

opts = propagator.syncOptions();
QCOMPARE( opts._minChunkSize, defaultOpts._minChunkSize );
QCOMPARE( opts._initialChunkSize, defaultOpts._minChunkSize );
QCOMPARE( opts._maxChunkSize, defaultOpts._minChunkSize );
}
};

QTEST_APPLESS_MAIN(TestNextcloudPropagator)
Expand Down
100 changes: 96 additions & 4 deletions test/testsyncengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,97 @@ private slots:
QCOMPARE(n507, 3);
}

/**
* Checks whether a HTTP-413 reply reduces the maxChunkSize in the propagator
*/
void testReplyOfRequestEntityToLargeReducesChunkSize()
{
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };

const int minRequestSize = 512 * 1024;
int maxAllowedRequestSize = 4 * minRequestSize;

SyncOptions options;
options._minChunkSize = minRequestSize;
options._failsafeMaxChunkSize = maxAllowedRequestSize;
options._initialChunkSize = options._maxChunkSize = 4 * maxAllowedRequestSize;
options._parallelNetworkJobs = 0;

auto &&engine = fakeFolder.syncEngine();
engine.setSyncOptions(options);

// Produce an error based on upload size
QObject parent;
int n413 = 0, nPUT = 0;
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) -> QNetworkReply * {
FakeErrorReply *reply = nullptr;
if (op == QNetworkAccessManager::PutOperation && outgoingData != nullptr) {
nPUT++;
auto requestSize = outgoingData->size();
auto closeConnection = getFilePathFromUrl(request.url()).contains("bigClose");

if (requestSize > maxAllowedRequestSize) {
if (closeConnection) {
reply = new FakeErrorReply(op, request, &parent, 500);
reply->setError(QNetworkReply::RemoteHostClosedError, "");
} else {
n413++;
reply = new FakeErrorReply(op, request, &parent, 413);
}
}
}
return reply;
});

// Test initial upload at max size succeeds
fakeFolder.localModifier().insert("A/big", maxAllowedRequestSize);
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(nPUT, 1);
QCOMPARE(n413, 0);
QCOMPARE(fakeFolder.account()->getMaxRequestSize(), -1);

// Test _failsafeMaxChunkSize applies on first failure
nPUT = n413 = 0;
fakeFolder.localModifier().insert("A/big1", maxAllowedRequestSize + 1);
QVERIFY(!fakeFolder.syncOnce() && engine.isAnotherSyncNeeded() == AnotherSyncNeeded::ImmediateFollowUp);
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(nPUT, 2);
QCOMPARE(n413, 1);
QCOMPARE(fakeFolder.account()->getMaxRequestSize(), options._failsafeMaxChunkSize);

// Test "Connection: Close" applies _failsafeMaxChunkSize as limit
nPUT = n413 = 0;
fakeFolder.account()->setMaxRequestSize(-1);
fakeFolder.localModifier().insert("A/bigClose", options._failsafeMaxChunkSize + 1);
QVERIFY(!fakeFolder.syncOnce() && engine.isAnotherSyncNeeded() == AnotherSyncNeeded::ImmediateFollowUp);
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(nPUT, 3);
QCOMPARE(n413, 0);
QCOMPARE(fakeFolder.account()->getMaxRequestSize(), options._failsafeMaxChunkSize);

// Test _maxChunkSize is reduced until upload succeeds
nPUT = n413 = 0;
maxAllowedRequestSize = options._minChunkSize;
fakeFolder.localModifier().insert("A/big2", options._failsafeMaxChunkSize);
QVERIFY(!fakeFolder.syncOnce() && engine.isAnotherSyncNeeded() == AnotherSyncNeeded::ImmediateFollowUp);
QVERIFY(!fakeFolder.syncOnce() && engine.isAnotherSyncNeeded() == AnotherSyncNeeded::ImmediateFollowUp);
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(nPUT, 4);
QCOMPARE(n413, 2);
QCOMPARE(fakeFolder.account()->getMaxRequestSize(), options._minChunkSize);

// Test _maxChunkSize is not reduced below _minChunkSize and retry is not requested
nPUT = n413 = 0;
maxAllowedRequestSize = options._minChunkSize / 2;
fakeFolder.localModifier().insert("A/big3", options._minChunkSize);
QVERIFY(!fakeFolder.syncOnce() && engine.isAnotherSyncNeeded() == AnotherSyncNeeded::NoFollowUpSync);
QVERIFY(!fakeFolder.syncOnce());
QVERIFY(!fakeFolder.syncOnce());
QCOMPARE(nPUT, 2);
QCOMPARE(n413, 2);
QCOMPARE(fakeFolder.account()->getMaxRequestSize(), options._minChunkSize);
}

// Checks whether downloads with bad checksums are accepted
void testChecksumValidation()
{
Expand Down Expand Up @@ -818,9 +909,10 @@ private slots:
{
FakeFolder fakeFolder{ FileInfo{} };
SyncOptions options;
options._initialChunkSize = 10;
options._maxChunkSize = 10;
options._minChunkSize = 10;
options._initialChunkSize =
options._maxChunkSize =
options._minChunkSize = 1000 * 1000;

fakeFolder.syncEngine().setSyncOptions(options);

QObject parent;
Expand All @@ -833,7 +925,7 @@ private slots:
return nullptr;
});

fakeFolder.localModifier().insert("file", 100, 'W');
fakeFolder.localModifier().insert("file", 10 * options._maxChunkSize, 'W');
QTimer::singleShot(100, &fakeFolder.syncEngine(), [&]() { fakeFolder.syncEngine().abort(); });
QVERIFY(!fakeFolder.syncOnce());

Expand Down

0 comments on commit 9ef12fb

Please sign in to comment.