зеркало из https://github.com/nextcloud/desktop.git
add automated tests for LockFileJob to validate proper behavior
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
This commit is contained in:
Родитель
fcd07f26a3
Коммит
2ea68d75bd
|
@ -65,14 +65,14 @@ bool LockFileJob::finished()
|
|||
const auto httpErrorCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (httpErrorCode == LOCKED_HTTP_ERROR_CODE) {
|
||||
const auto record = handleReply();
|
||||
if (static_cast<SyncFileItem::LockOwnerType>(record._lockOwnerType) == SyncFileItem::LockOwnerType::UserLock) {
|
||||
Q_EMIT finishedWithError(httpErrorCode, {}, record._lockOwnerDisplayName);
|
||||
if (static_cast<SyncFileItem::LockOwnerType>(record._lockstate._lockOwnerType) == SyncFileItem::LockOwnerType::UserLock) {
|
||||
Q_EMIT finishedWithError(httpErrorCode, {}, record._lockstate._lockOwnerDisplayName);
|
||||
} else {
|
||||
Q_EMIT finishedWithError(httpErrorCode, {}, record._lockEditorApp);
|
||||
Q_EMIT finishedWithError(httpErrorCode, {}, record._lockstate._lockEditorApp);
|
||||
}
|
||||
} else if (httpErrorCode == PRECONDITION_FAILED_ERROR_CODE) {
|
||||
const auto record = handleReply();
|
||||
if (_requestedLockState == SyncFileItem::LockStatus::UnlockedItem && !record._locked) {
|
||||
if (_requestedLockState == SyncFileItem::LockStatus::UnlockedItem && !record._lockstate._locked) {
|
||||
Q_EMIT finishedWithoutError();
|
||||
} else {
|
||||
Q_EMIT finishedWithError(httpErrorCode, reply()->errorString(), {});
|
||||
|
@ -90,13 +90,13 @@ bool LockFileJob::finished()
|
|||
|
||||
void LockFileJob::setFileRecordLocked(SyncJournalFileRecord &record) const
|
||||
{
|
||||
record._locked = (_lockStatus == SyncFileItem::LockStatus::LockedItem);
|
||||
record._lockOwnerType = static_cast<int>(_lockOwnerType);
|
||||
record._lockOwnerDisplayName = _userDisplayName;
|
||||
record._lockOwnerId = _userId;
|
||||
record._lockEditorApp = _editorName;
|
||||
record._lockTime = _lockTime;
|
||||
record._lockTimeout = _lockTimeout;
|
||||
record._lockstate._locked = (_lockStatus == SyncFileItem::LockStatus::LockedItem);
|
||||
record._lockstate._lockOwnerType = static_cast<int>(_lockOwnerType);
|
||||
record._lockstate._lockOwnerDisplayName = _userDisplayName;
|
||||
record._lockstate._lockOwnerId = _userId;
|
||||
record._lockstate._lockEditorApp = _editorName;
|
||||
record._lockstate._lockTime = _lockTime;
|
||||
record._lockstate._lockTimeout = _lockTimeout;
|
||||
}
|
||||
|
||||
void LockFileJob::resetState()
|
||||
|
|
|
@ -64,6 +64,7 @@ nextcloud_add_test(UnifiedSearchListmodel)
|
|||
nextcloud_add_test(ActivityListModel)
|
||||
nextcloud_add_test(ActivityData)
|
||||
nextcloud_add_test(TalkReply)
|
||||
nextcloud_add_test(LockFile)
|
||||
|
||||
if( UNIX AND NOT APPLE )
|
||||
nextcloud_add_test(InotifyWatcher)
|
||||
|
|
|
@ -1000,6 +1000,8 @@ QNetworkReply *FakeQNAM::createRequest(QNetworkAccessManager::Operation op, cons
|
|||
if (contentType.startsWith(QStringLiteral("multipart/related; boundary="))) {
|
||||
reply = new FakePutMultiFileReply { info, op, newRequest, contentType, outgoingData->readAll(), this };
|
||||
}
|
||||
} else if (verb == QLatin1String("LOCK") || verb == QLatin1String("UNLOCK")) {
|
||||
reply = new FakeFileLockReply{info, op, newRequest, this};
|
||||
} else {
|
||||
qDebug() << verb << outgoingData;
|
||||
Q_UNREACHABLE();
|
||||
|
@ -1251,3 +1253,50 @@ FakeJsonErrorReply::FakeJsonErrorReply(QNetworkAccessManager::Operation op,
|
|||
: FakeErrorReply{ op, request, parent, httpErrorCode, reply.toJson() }
|
||||
{
|
||||
}
|
||||
|
||||
FakeFileLockReply::FakeFileLockReply(FileInfo &remoteRootFileInfo,
|
||||
QNetworkAccessManager::Operation op,
|
||||
const QNetworkRequest &request,
|
||||
QObject *parent)
|
||||
: FakePropfindReply(remoteRootFileInfo, op, request, parent)
|
||||
{
|
||||
const auto verb = request.attribute(QNetworkRequest::CustomVerbAttribute);
|
||||
|
||||
setRequest(request);
|
||||
setUrl(request.url());
|
||||
setOperation(op);
|
||||
open(QIODevice::ReadOnly);
|
||||
|
||||
QString fileName = getFilePathFromUrl(request.url());
|
||||
Q_ASSERT(!fileName.isNull()); // for root, it should be empty
|
||||
FileInfo *fileInfo = remoteRootFileInfo.find(fileName);
|
||||
if (!fileInfo) {
|
||||
QMetaObject::invokeMethod(this, "respond404", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
const QString prefix = request.url().path().left(request.url().path().size() - fileName.size());
|
||||
|
||||
// Don't care about the request and just return a full propfind
|
||||
const QString davUri { QStringLiteral("DAV:") };
|
||||
const QString ocUri { QStringLiteral("http://owncloud.org/ns") };
|
||||
const QString ncUri { QStringLiteral("http://nextcloud.org/ns") };
|
||||
payload.clear();
|
||||
QBuffer buffer { &payload };
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
QXmlStreamWriter xml(&buffer);
|
||||
xml.writeNamespace(davUri, QStringLiteral("d"));
|
||||
xml.writeNamespace(ocUri, QStringLiteral("oc"));
|
||||
xml.writeNamespace(ncUri, QStringLiteral("nc"));
|
||||
xml.writeStartDocument();
|
||||
xml.writeStartElement(davUri, QStringLiteral("prop"));
|
||||
xml.writeTextElement(ncUri, QStringLiteral("lock"), verb == QStringLiteral("LOCK") ? "1" : "0");
|
||||
xml.writeTextElement(ncUri, QStringLiteral("lock-owner-type"), QString::number(0));
|
||||
xml.writeTextElement(ncUri, QStringLiteral("lock-owner"), QStringLiteral("admin"));
|
||||
xml.writeTextElement(ncUri, QStringLiteral("lock-owner-displayname"), QStringLiteral("John Doe"));
|
||||
xml.writeTextElement(ncUri, QStringLiteral("lock-owner-editor"), {});
|
||||
xml.writeTextElement(ncUri, QStringLiteral("lock-time"), QString::number(1234560));
|
||||
xml.writeTextElement(ncUri, QStringLiteral("lock-timeout"), QString::number(1800));
|
||||
xml.writeEndElement(); // prop
|
||||
xml.writeEndDocument();
|
||||
}
|
||||
|
|
|
@ -402,6 +402,16 @@ public:
|
|||
qint64 readData(char *, qint64) override { return 0; }
|
||||
};
|
||||
|
||||
class FakeFileLockReply : public FakePropfindReply
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FakeFileLockReply(FileInfo &remoteRootFileInfo,
|
||||
QNetworkAccessManager::Operation op,
|
||||
const QNetworkRequest &request,
|
||||
QObject *parent);
|
||||
};
|
||||
|
||||
// A delayed reply
|
||||
template <class OriginalReply>
|
||||
class DelayedReply : public OriginalReply
|
||||
|
|
|
@ -597,8 +597,6 @@ private slots:
|
|||
|
||||
void testDiscoverLockChanges()
|
||||
{
|
||||
// Logger::instance()->setLogDebug(true);
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
fakeFolder.syncEngine().account()->setCapabilities({{"activity", QVariantMap{{"apiv2", QVariantList{"filters", "filters-api", "previews", "rich-strings"}}}},
|
||||
{"bruteforce", QVariantMap{{"delay", 0}}},
|
||||
|
@ -626,7 +624,7 @@ private slots:
|
|||
"<nc:lock-owner>user1</nc:lock-owner>"
|
||||
"<nc:lock-owner-displayname>user1</nc:lock-owner-displayname>"
|
||||
"<nc:lock-owner-editor>user1</nc:lock-owner-editor>"
|
||||
"<nc:lock-time>1648046707</nc:lock-time><oc:size>20020</oc:size>";
|
||||
"<nc:lock-time>1648046707</nc:lock-time>";
|
||||
|
||||
fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder"));
|
||||
fakeFolder.remoteModifier().insert(fooFileSubFolder);
|
||||
|
|
|
@ -0,0 +1,381 @@
|
|||
#include "lockfilejobs.h"
|
||||
|
||||
#include "account.h"
|
||||
#include "accountstate.h"
|
||||
#include "common/syncjournaldb.h"
|
||||
#include "common/syncjournalfilerecord.h"
|
||||
#include "syncenginetestutils.h"
|
||||
|
||||
#include <QTest>
|
||||
#include <QSignalSpy>
|
||||
|
||||
class TestLockFile : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestLockFile() = default;
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void testLockFile_lockFile_jobSuccess()
|
||||
{
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobSuccess.wait());
|
||||
QCOMPARE(jobFailure.count(), 0);
|
||||
|
||||
auto fileRecord = OCC::SyncJournalFileRecord{};
|
||||
QVERIFY(fakeFolder.syncJournal().getFileRecord(testFileName, &fileRecord));
|
||||
QCOMPARE(fileRecord._lockstate._locked, true);
|
||||
QCOMPARE(fileRecord._lockstate._lockEditorApp, QString{});
|
||||
QCOMPARE(fileRecord._lockstate._lockOwnerDisplayName, QStringLiteral("John Doe"));
|
||||
QCOMPARE(fileRecord._lockstate._lockOwnerId, QStringLiteral("admin"));
|
||||
QCOMPARE(fileRecord._lockstate._lockOwnerType, static_cast<qint64>(OCC::SyncFileItem::LockOwnerType::UserLock));
|
||||
QCOMPARE(fileRecord._lockstate._lockTime, 1234560);
|
||||
QCOMPARE(fileRecord._lockstate._lockTimeout, 1800);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
}
|
||||
|
||||
void testLockFile_lockFile_unlockFile_jobSuccess()
|
||||
{
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto lockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
lockFileJob->start();
|
||||
|
||||
QVERIFY(lockFileJobSuccess.wait());
|
||||
QCOMPARE(lockFileJobFailure.count(), 0);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto unlockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
|
||||
|
||||
QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
unlockFileJob->start();
|
||||
|
||||
QVERIFY(unlockFileJobSuccess.wait());
|
||||
QCOMPARE(unlockFileJobFailure.count(), 0);
|
||||
|
||||
auto fileRecord = OCC::SyncJournalFileRecord{};
|
||||
QVERIFY(fakeFolder.syncJournal().getFileRecord(testFileName, &fileRecord));
|
||||
QCOMPARE(fileRecord._lockstate._locked, false);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
}
|
||||
|
||||
void testLockFile_lockFile_alreadyLockedByUser()
|
||||
{
|
||||
static constexpr auto LockedHttpErrorCode = 423;
|
||||
static constexpr auto PreconditionFailedHttpErrorCode = 412;
|
||||
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
|
||||
const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
|
||||
"<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
|
||||
" <nc:lock>1</nc:lock>\n"
|
||||
" <nc:lock-owner-type>0</nc:lock-owner-type>\n"
|
||||
" <nc:lock-owner>john</nc:lock-owner>\n"
|
||||
" <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
|
||||
" <nc:lock-owner-editor>john</nc:lock-owner-editor>\n"
|
||||
" <nc:lock-time>1650619678</nc:lock-time>\n"
|
||||
" <nc:lock-timeout>300</nc:lock-timeout>\n"
|
||||
" <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
|
||||
"</d:prop>\n");
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
|
||||
} else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobFailure.wait());
|
||||
QCOMPARE(jobSuccess.count(), 0);
|
||||
}
|
||||
|
||||
void testLockFile_lockFile_alreadyLockedByApp()
|
||||
{
|
||||
static constexpr auto LockedHttpErrorCode = 423;
|
||||
static constexpr auto PreconditionFailedHttpErrorCode = 412;
|
||||
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
|
||||
const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
|
||||
"<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
|
||||
" <nc:lock>1</nc:lock>\n"
|
||||
" <nc:lock-owner-type>1</nc:lock-owner-type>\n"
|
||||
" <nc:lock-owner>john</nc:lock-owner>\n"
|
||||
" <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
|
||||
" <nc:lock-owner-editor>Text</nc:lock-owner-editor>\n"
|
||||
" <nc:lock-time>1650619678</nc:lock-time>\n"
|
||||
" <nc:lock-timeout>300</nc:lock-timeout>\n"
|
||||
" <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
|
||||
"</d:prop>\n");
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
|
||||
} else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobFailure.wait());
|
||||
QCOMPARE(jobSuccess.count(), 0);
|
||||
}
|
||||
|
||||
void testLockFile_unlockFile_alreadyUnlocked()
|
||||
{
|
||||
static constexpr auto LockedHttpErrorCode = 423;
|
||||
static constexpr auto PreconditionFailedHttpErrorCode = 412;
|
||||
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
|
||||
const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
|
||||
"<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
|
||||
" <nc:lock/>\n"
|
||||
" <nc:lock-owner-type>0</nc:lock-owner-type>\n"
|
||||
" <nc:lock-owner>john</nc:lock-owner>\n"
|
||||
" <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
|
||||
" <nc:lock-owner-editor>john</nc:lock-owner-editor>\n"
|
||||
" <nc:lock-time>1650619678</nc:lock-time>\n"
|
||||
" <nc:lock-timeout>300</nc:lock-timeout>\n"
|
||||
" <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
|
||||
"</d:prop>\n");
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
|
||||
} else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobSuccess.wait());
|
||||
QCOMPARE(jobFailure.count(), 0);
|
||||
}
|
||||
|
||||
void testLockFile_unlockFile_lockedBySomeoneElse()
|
||||
{
|
||||
static constexpr auto LockedHttpErrorCode = 423;
|
||||
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
|
||||
const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
|
||||
"<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
|
||||
" <nc:lock>1</nc:lock>\n"
|
||||
" <nc:lock-owner-type>0</nc:lock-owner-type>\n"
|
||||
" <nc:lock-owner>alice</nc:lock-owner>\n"
|
||||
" <nc:lock-owner-displayname>Alice Doe</nc:lock-owner-displayname>\n"
|
||||
" <nc:lock-owner-editor>Text</nc:lock-owner-editor>\n"
|
||||
" <nc:lock-time>1650619678</nc:lock-time>\n"
|
||||
" <nc:lock-timeout>300</nc:lock-timeout>\n"
|
||||
" <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
|
||||
"</d:prop>\n");
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && (request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK") ||
|
||||
request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK"))) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobFailure.wait());
|
||||
QCOMPARE(jobSuccess.count(), 0);
|
||||
}
|
||||
|
||||
void testLockFile_lockFile_jobError()
|
||||
{
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
static constexpr auto InternalServerErrorHttpErrorCode = 500;
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && (request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK") ||
|
||||
request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK"))) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, InternalServerErrorHttpErrorCode, {});
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(QStringLiteral("file.txt"));
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto lockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
lockFileJob->start();
|
||||
|
||||
QVERIFY(lockFileJobFailure.wait());
|
||||
QCOMPARE(lockFileJobSuccess.count(), 0);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto unlockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
|
||||
|
||||
QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
unlockFileJob->start();
|
||||
|
||||
QVERIFY(unlockFileJobFailure.wait());
|
||||
QCOMPARE(unlockFileJobSuccess.count(), 0);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
}
|
||||
|
||||
void testLockFile_lockFile_preconditionFailedError()
|
||||
{
|
||||
static constexpr auto PreconditionFailedHttpErrorCode = 412;
|
||||
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
|
||||
const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
|
||||
"<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
|
||||
" <nc:lock>1</nc:lock>\n"
|
||||
" <nc:lock-owner-type>0</nc:lock-owner-type>\n"
|
||||
" <nc:lock-owner>alice</nc:lock-owner>\n"
|
||||
" <nc:lock-owner-displayname>Alice Doe</nc:lock-owner-displayname>\n"
|
||||
" <nc:lock-owner-editor>Text</nc:lock-owner-editor>\n"
|
||||
" <nc:lock-time>1650619678</nc:lock-time>\n"
|
||||
" <nc:lock-timeout>300</nc:lock-timeout>\n"
|
||||
" <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
|
||||
"</d:prop>\n");
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && (request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK") ||
|
||||
request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK"))) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobFailure.wait());
|
||||
QCOMPARE(jobSuccess.count(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(TestLockFile)
|
||||
#include "testlockfile.moc"
|
|
@ -0,0 +1,242 @@
|
|||
#include "lockfilejobs.h"
|
||||
|
||||
#include "account.h"
|
||||
#include "accountstate.h"
|
||||
#include "common/syncjournaldb.h"
|
||||
#include "common/syncjournalfilerecord.h"
|
||||
#include "syncenginetestutils.h"
|
||||
|
||||
#include <QTest>
|
||||
#include <QSignalSpy>
|
||||
|
||||
class TestLockFileJobs : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestLockFileJobs() = default;
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
void testLockFileJob_lockFile_jobSuccess()
|
||||
{
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobSuccess.wait());
|
||||
QCOMPARE(jobFailure.count(), 0);
|
||||
|
||||
auto fileRecord = OCC::SyncJournalFileRecord{};
|
||||
QVERIFY(fakeFolder.syncJournal().getFileRecord(testFileName, &fileRecord));
|
||||
QCOMPARE(fileRecord._locked, true);
|
||||
QCOMPARE(fileRecord._lockEditorApp, QString{});
|
||||
QCOMPARE(fileRecord._lockOwnerDisplayName, QStringLiteral("John Doe"));
|
||||
QCOMPARE(fileRecord._lockOwnerId, QStringLiteral("john"));
|
||||
QCOMPARE(fileRecord._lockOwnerType, static_cast<qint64>(OCC::SyncFileItem::LockOwnerType::UserLock));
|
||||
QCOMPARE(fileRecord._lockTime, 1234560);
|
||||
QCOMPARE(fileRecord._lockTimeout, 1800);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
}
|
||||
|
||||
void testLockFileJob_lockFile_unlockFile_jobSuccess()
|
||||
{
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto lockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
lockFileJob->start();
|
||||
|
||||
QVERIFY(lockFileJobSuccess.wait());
|
||||
QCOMPARE(lockFileJobFailure.count(), 0);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto unlockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
|
||||
|
||||
QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
unlockFileJob->start();
|
||||
|
||||
QVERIFY(unlockFileJobSuccess.wait());
|
||||
QCOMPARE(unlockFileJobFailure.count(), 0);
|
||||
|
||||
auto fileRecord = OCC::SyncJournalFileRecord{};
|
||||
QVERIFY(fakeFolder.syncJournal().getFileRecord(testFileName, &fileRecord));
|
||||
QCOMPARE(fileRecord._locked, false);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
}
|
||||
|
||||
void testLockFileJob_lockFile_alreadyLocked()
|
||||
{
|
||||
static constexpr auto LockedHttpErrorCode = 423;
|
||||
static constexpr auto PreconditionFailedHttpErrorCode = 412;
|
||||
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
|
||||
const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
|
||||
"<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
|
||||
" <nc:lock>1</nc:lock>\n"
|
||||
" <nc:lock-owner-type>0</nc:lock-owner-type>\n"
|
||||
" <nc:lock-owner>john</nc:lock-owner>\n"
|
||||
" <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
|
||||
" <nc:lock-owner-editor>john</nc:lock-owner-editor>\n"
|
||||
" <nc:lock-time>1650619678</nc:lock-time>\n"
|
||||
" <nc:lock-timeout>300</nc:lock-timeout>\n"
|
||||
" <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
|
||||
"</d:prop>\n");
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
|
||||
} else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobFailure.wait());
|
||||
QCOMPARE(jobSuccess.count(), 0);
|
||||
}
|
||||
|
||||
void testLockFileJob_unlockFile_alreadyUnlocked()
|
||||
{
|
||||
static constexpr auto LockedHttpErrorCode = 423;
|
||||
static constexpr auto PreconditionFailedHttpErrorCode = 412;
|
||||
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
|
||||
const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
|
||||
"<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
|
||||
" <nc:lock/>\n"
|
||||
" <nc:lock-owner-type>0</nc:lock-owner-type>\n"
|
||||
" <nc:lock-owner>john</nc:lock-owner>\n"
|
||||
" <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
|
||||
" <nc:lock-owner-editor>john</nc:lock-owner-editor>\n"
|
||||
" <nc:lock-time>1650619678</nc:lock-time>\n"
|
||||
" <nc:lock-timeout>300</nc:lock-timeout>\n"
|
||||
" <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
|
||||
"</d:prop>\n");
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
|
||||
} else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(testFileName);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
job->start();
|
||||
|
||||
QVERIFY(jobFailure.wait());
|
||||
QCOMPARE(jobSuccess.count(), 0);
|
||||
}
|
||||
|
||||
void testLockFileJob_lockFile_jobError()
|
||||
{
|
||||
const auto testFileName = QStringLiteral("file.txt");
|
||||
static constexpr auto InternalServerErrorHttpErrorCode = 500;
|
||||
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
fakeFolder.setServerOverride([] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
|
||||
QNetworkReply *reply = nullptr;
|
||||
if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, InternalServerErrorHttpErrorCode, {});
|
||||
} else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
|
||||
reply = new FakeErrorReply(op, request, nullptr, InternalServerErrorHttpErrorCode, {});
|
||||
}
|
||||
|
||||
return reply;
|
||||
});
|
||||
|
||||
fakeFolder.localModifier().insert(QStringLiteral("file.txt"));
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto lockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
|
||||
|
||||
QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
lockFileJob->start();
|
||||
|
||||
QVERIFY(lockFileJobFailure.wait());
|
||||
QCOMPARE(lockFileJobSuccess.count(), 0);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
auto unlockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
|
||||
|
||||
QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
|
||||
QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
|
||||
|
||||
unlockFileJob->start();
|
||||
|
||||
QVERIFY(unlockFileJobFailure.wait());
|
||||
QCOMPARE(unlockFileJobSuccess.count(), 0);
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(TestLockFileJobs)
|
||||
#include "testlockfilejobs.moc"
|
Загрузка…
Ссылка в новой задаче