mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-28 03:49:20 +03:00
Rollback local move when server move has failed.
Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
parent
6715450600
commit
3443de4388
4 changed files with 122 additions and 9 deletions
|
@ -208,6 +208,17 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
||||||
if (err != QNetworkReply::NoError) {
|
if (err != QNetworkReply::NoError) {
|
||||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&propagator()->_anotherSyncNeeded);
|
||||||
|
const auto filePath = propagator()->fullLocalPath(_item->_renameTarget);
|
||||||
|
const auto filePathOriginal = propagator()->fullLocalPath(_item->_originalFile);
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.rename(filePathOriginal)) {
|
||||||
|
qCWarning(lcPropagateRemoteMove) << "Could not MOVE file" << filePathOriginal << " to" << filePath
|
||||||
|
<< " with error:" << _job->errorString() << " and failed to restore it !";
|
||||||
|
} else {
|
||||||
|
qCWarning(lcPropagateRemoteMove)
|
||||||
|
<< "Could not MOVE file" << filePathOriginal << " to" << filePath
|
||||||
|
<< " with error:" << _job->errorString() << " and successfully restored it.";
|
||||||
|
}
|
||||||
done(status, _job->errorString());
|
done(status, _job->errorString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -982,6 +982,106 @@ private slots:
|
||||||
QCOMPARE(nPOST, 0);
|
QCOMPARE(nPOST, 0);
|
||||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testRemoteMoveFailedInsufficientStorageLocalMoveRolledBack()
|
||||||
|
{
|
||||||
|
FakeFolder fakeFolder{FileInfo{}};
|
||||||
|
|
||||||
|
// create a big shared folder with some files
|
||||||
|
fakeFolder.remoteModifier().mkdir("big_shared_folder");
|
||||||
|
fakeFolder.remoteModifier().mkdir("big_shared_folder/shared_files");
|
||||||
|
fakeFolder.remoteModifier().insert("big_shared_folder/shared_files/big_shared_file_A.data", 1000);
|
||||||
|
fakeFolder.remoteModifier().insert("big_shared_folder/shared_files/big_shared_file_B.data", 1000);
|
||||||
|
|
||||||
|
// make sure big shared folder is synced
|
||||||
|
QVERIFY(fakeFolder.syncOnce());
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_A.data"));
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_B.data"));
|
||||||
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||||
|
|
||||||
|
// try to move from a big shared folder to your own folder
|
||||||
|
fakeFolder.localModifier().mkdir("own_folder");
|
||||||
|
fakeFolder.localModifier().rename(
|
||||||
|
"big_shared_folder/shared_files/big_shared_file_A.data", "own_folder/big_shared_file_A.data");
|
||||||
|
fakeFolder.localModifier().rename(
|
||||||
|
"big_shared_folder/shared_files/big_shared_file_B.data", "own_folder/big_shared_file_B.data");
|
||||||
|
|
||||||
|
// emulate server MOVE 507 error
|
||||||
|
QObject parent;
|
||||||
|
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request,
|
||||||
|
QIODevice *outgoingData) -> QNetworkReply * {
|
||||||
|
Q_UNUSED(outgoingData)
|
||||||
|
|
||||||
|
if (op == QNetworkAccessManager::CustomOperation
|
||||||
|
&& request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("MOVE")) {
|
||||||
|
return new FakeErrorReply(op, request, &parent, 507);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
// make sure the first sync failes and files get restored to original folder
|
||||||
|
QVERIFY(!fakeFolder.syncOnce());
|
||||||
|
|
||||||
|
QVERIFY(fakeFolder.syncOnce());
|
||||||
|
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_A.data"));
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_B.data"));
|
||||||
|
QVERIFY(!fakeFolder.currentLocalState().find("own_folder/big_shared_file_A.data"));
|
||||||
|
QVERIFY(!fakeFolder.currentLocalState().find("own_folder/big_shared_file_B.data"));
|
||||||
|
|
||||||
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRemoteMoveFailedForbiddenLocalMoveRolledBack()
|
||||||
|
{
|
||||||
|
FakeFolder fakeFolder{FileInfo{}};
|
||||||
|
|
||||||
|
// create a big shared folder with some files
|
||||||
|
fakeFolder.remoteModifier().mkdir("big_shared_folder");
|
||||||
|
fakeFolder.remoteModifier().mkdir("big_shared_folder/shared_files");
|
||||||
|
fakeFolder.remoteModifier().insert("big_shared_folder/shared_files/big_shared_file_A.data", 1000);
|
||||||
|
fakeFolder.remoteModifier().insert("big_shared_folder/shared_files/big_shared_file_B.data", 1000);
|
||||||
|
|
||||||
|
// make sure big shared folder is synced
|
||||||
|
QVERIFY(fakeFolder.syncOnce());
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_A.data"));
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_B.data"));
|
||||||
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||||
|
|
||||||
|
// try to move from a big shared folder to your own folder
|
||||||
|
fakeFolder.localModifier().mkdir("own_folder");
|
||||||
|
fakeFolder.localModifier().rename(
|
||||||
|
"big_shared_folder/shared_files/big_shared_file_A.data", "own_folder/big_shared_file_A.data");
|
||||||
|
fakeFolder.localModifier().rename(
|
||||||
|
"big_shared_folder/shared_files/big_shared_file_B.data", "own_folder/big_shared_file_B.data");
|
||||||
|
|
||||||
|
// emulate server MOVE 507 error
|
||||||
|
QObject parent;
|
||||||
|
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request,
|
||||||
|
QIODevice *outgoingData) -> QNetworkReply * {
|
||||||
|
Q_UNUSED(outgoingData)
|
||||||
|
|
||||||
|
auto attributeCustomVerb = request.attribute(QNetworkRequest::CustomVerbAttribute).toString();
|
||||||
|
|
||||||
|
if (op == QNetworkAccessManager::CustomOperation
|
||||||
|
&& request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("MOVE")) {
|
||||||
|
return new FakeErrorReply(op, request, &parent, 403);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
// make sure the first sync failes and files get restored to original folder
|
||||||
|
QVERIFY(!fakeFolder.syncOnce());
|
||||||
|
|
||||||
|
QVERIFY(fakeFolder.syncOnce());
|
||||||
|
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_A.data"));
|
||||||
|
QVERIFY(fakeFolder.currentLocalState().find("big_shared_folder/shared_files/big_shared_file_B.data"));
|
||||||
|
QVERIFY(!fakeFolder.currentLocalState().find("own_folder/big_shared_file_A.data"));
|
||||||
|
QVERIFY(!fakeFolder.currentLocalState().find("own_folder/big_shared_file_B.data"));
|
||||||
|
|
||||||
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(TestSyncEngine)
|
QTEST_GUILESS_MAIN(TestSyncEngine)
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
|
|
||||||
SyncFileStatus statusOf(const QString &relativePath) const {
|
SyncFileStatus statusOf(const QString &relativePath) const {
|
||||||
QFileInfo file(_syncEngine.localPath(), relativePath);
|
QFileInfo file(_syncEngine.localPath(), relativePath);
|
||||||
|
auto locPath = _syncEngine.localPath();
|
||||||
// Start from the end to get the latest status
|
// Start from the end to get the latest status
|
||||||
for (int i = size() - 1; i >= 0; --i) {
|
for (int i = size() - 1; i >= 0; --i) {
|
||||||
if (QFileInfo(at(i)[0].toString()) == file)
|
if (QFileInfo(at(i)[0].toString()) == file)
|
||||||
|
@ -467,6 +468,7 @@ private slots:
|
||||||
}
|
}
|
||||||
|
|
||||||
void renameError() {
|
void renameError() {
|
||||||
|
// when rename has failed - the old file name must be restored
|
||||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||||
fakeFolder.serverErrorPaths().append("A/a1");
|
fakeFolder.serverErrorPaths().append("A/a1");
|
||||||
fakeFolder.localModifier().rename("A/a1", "A/a1m");
|
fakeFolder.localModifier().rename("A/a1", "A/a1m");
|
||||||
|
@ -488,22 +490,22 @@ private slots:
|
||||||
fakeFolder.execUntilFinished();
|
fakeFolder.execUntilFinished();
|
||||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||||
QCOMPARE(statusSpy.statusOf("A/a1m"), SyncFileStatus(SyncFileStatus::StatusError));
|
QCOMPARE(statusSpy.statusOf("A/a1m"), SyncFileStatus(SyncFileStatus::StatusError));
|
||||||
QCOMPARE(statusSpy.statusOf("A/a1"), statusSpy.statusOf("A/a1notexist"));
|
QCOMPARE(statusSpy.statusOf("A/a1"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
||||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||||
QCOMPARE(statusSpy.statusOf("B/b1m"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
QCOMPARE(statusSpy.statusOf("B/b1m"), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||||
statusSpy.clear();
|
statusSpy.clear();
|
||||||
|
|
||||||
QVERIFY(!fakeFolder.syncOnce());
|
QVERIFY(fakeFolder.syncOnce());
|
||||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||||
statusSpy.clear();
|
statusSpy.clear();
|
||||||
QVERIFY(!fakeFolder.syncOnce());
|
QVERIFY(fakeFolder.syncOnce());
|
||||||
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
verifyThatPushMatchesPull(fakeFolder, statusSpy);
|
||||||
QCOMPARE(statusSpy.statusOf("A/a1m"), SyncFileStatus(SyncFileStatus::StatusError));
|
QCOMPARE(statusSpy.statusOf("A/a1m"), SyncFileStatus(SyncFileStatus::StatusNone));
|
||||||
QCOMPARE(statusSpy.statusOf("A/a1"), statusSpy.statusOf("A/a1notexist"));
|
QCOMPARE(statusSpy.statusOf("A/a1"), statusSpy.statusOf("A/a1notexist"));
|
||||||
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusWarning));
|
QCOMPARE(statusSpy.statusOf("A"), SyncFileStatus(SyncFileStatus::StatusNone));
|
||||||
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusWarning));
|
QCOMPARE(statusSpy.statusOf(""), SyncFileStatus(SyncFileStatus::StatusUpToDate));
|
||||||
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusNone));
|
QCOMPARE(statusSpy.statusOf("B"), SyncFileStatus(SyncFileStatus::StatusNone));
|
||||||
QCOMPARE(statusSpy.statusOf("B/b1m"), SyncFileStatus(SyncFileStatus::StatusNone));
|
QCOMPARE(statusSpy.statusOf("B/b1m"), SyncFileStatus(SyncFileStatus::StatusNone));
|
||||||
statusSpy.clear();
|
statusSpy.clear();
|
||||||
|
|
|
@ -958,12 +958,12 @@ private slots:
|
||||||
fakeFolder.syncOnce();
|
fakeFolder.syncOnce();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVERIFY(!fakeFolder.currentLocalState().find(src));
|
QVERIFY(fakeFolder.currentLocalState().find(getName(src)));
|
||||||
QVERIFY(fakeFolder.currentLocalState().find(getName(dest)));
|
QVERIFY(!fakeFolder.currentLocalState().find(getName(dest)));
|
||||||
if (vfsMode == Vfs::WithSuffix)
|
if (vfsMode == Vfs::WithSuffix)
|
||||||
{
|
{
|
||||||
// the placeholder was not restored as it is still in error state
|
// the placeholder was not restored as it is still in error state
|
||||||
QVERIFY(!fakeFolder.currentLocalState().find(dest));
|
QVERIFY(!fakeFolder.currentLocalState().find(getName(dest)));
|
||||||
}
|
}
|
||||||
QVERIFY(fakeFolder.currentRemoteState().find(src));
|
QVERIFY(fakeFolder.currentRemoteState().find(src));
|
||||||
QVERIFY(!fakeFolder.currentRemoteState().find(dest));
|
QVERIFY(!fakeFolder.currentRemoteState().find(dest));
|
||||||
|
|
Loading…
Reference in a new issue