diff options
-rw-r--r-- | src/gui/folder.cpp | 2 | ||||
-rw-r--r-- | src/libsync/syncjournaldb.cpp | 11 | ||||
-rw-r--r-- | src/libsync/syncjournaldb.h | 7 | ||||
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/testallfilesdeleted.cpp | 118 |
5 files changed, 138 insertions, 1 deletions
diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index 845b5b68d..3bfb54cb0 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -908,7 +908,7 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel } *cancel = msgBox.clickedButton() == keepBtn; if (*cancel) { - wipe(); + journalDb()->clearFileTable(); _lastEtag.clear(); slotScheduleThisFolder(); } diff --git a/src/libsync/syncjournaldb.cpp b/src/libsync/syncjournaldb.cpp index 7ee83db46..43ef9b37a 100644 --- a/src/libsync/syncjournaldb.cpp +++ b/src/libsync/syncjournaldb.cpp @@ -1836,6 +1836,17 @@ void SyncJournalDb::setDataFingerprint(const QByteArray &dataFingerprint) } } +void SyncJournalDb::clearFileTable() +{ + SqlQuery query(_db); + query.prepare("DELETE FROM metadata;"); + if (!query.exec()) { + qWarning() << "SQL error in clearFileTable" << query.error(); + } else { + qDebug() << query.lastQuery() << "(" << query.numRowsAffected() << " rows)"; + } +} + void SyncJournalDb::commit(const QString& context, bool startTrans) { QMutexLocker lock(&_mutex); diff --git a/src/libsync/syncjournaldb.h b/src/libsync/syncjournaldb.h index fe00051a3..cd4572644 100644 --- a/src/libsync/syncjournaldb.h +++ b/src/libsync/syncjournaldb.h @@ -173,6 +173,13 @@ public: void setDataFingerprint(const QByteArray &dataFingerprint); QByteArray dataFingerprint(); + /** + * Delete any file entry. This will force the next sync to re-sync everything as if it was new, + * restoring everyfile on every remote. If a file is there both on the client and server side, + * it will be a conflict that will be automatically resolved if the file is the same. + */ + void clearFileTable(); + private: bool updateDatabaseStructure(); bool updateMetadataTableStructure(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 16b4b6589..2f94501ee 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -40,6 +40,7 @@ if(HAVE_QT5 AND NOT BUILD_WITH_QT4) owncloud_add_test(SyncFileStatusTracker "syncenginetestutils.h") owncloud_add_test(ChunkingNg "syncenginetestutils.h") owncloud_add_test(UploadReset "syncenginetestutils.h") + owncloud_add_test(AllFilesDeleted "syncenginetestutils.h") owncloud_add_test(FolderWatcher "${FolderWatcher_SRC}") if( UNIX AND NOT APPLE ) diff --git a/test/testallfilesdeleted.cpp b/test/testallfilesdeleted.cpp new file mode 100644 index 000000000..d9356c844 --- /dev/null +++ b/test/testallfilesdeleted.cpp @@ -0,0 +1,118 @@ +/* + * This software is in the public domain, furnished "as is", without technical + * support, and with no warranty, express or implied, as to its usefulness for + * any purpose. + * + */ + +#include <QtTest> +#include "syncenginetestutils.h" +#include <syncengine.h> + +using namespace OCC; + +/* + * This test ensure that the SyncEngine::aboutToRemoveAllFiles is correctly called and that when + * we the user choose to remove all files SyncJournalDb::clearFileTable makes works as expected + */ +class TestAllFilesDeleted : public QObject +{ + Q_OBJECT + +private slots: + + void testAllFilesDeletedKeep_data() + { + QTest::addColumn<bool>("deleteOnRemote"); + QTest::newRow("local") << false; + QTest::newRow("remote") << true; + + } + + /* + * In this test, all files are deleted in the client, or the server, and we simulate + * that the users press "keep" + */ + void testAllFilesDeletedKeep() + { + QFETCH(bool, deleteOnRemote); + FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()}; + + //Just set a blacklist so we can check it is still there. This directory does not exists but + // that does not matter for our purposes. + QStringList selectiveSyncBlackList = { "Q/" }; + fakeFolder.syncEngine().journal()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, + selectiveSyncBlackList); + + auto initialState = fakeFolder.currentLocalState(); + int aboutToRemoveAllFilesCalled = 0; + QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveAllFiles, + [&](SyncFileItem::Direction dir, bool *cancel) { + QCOMPARE(aboutToRemoveAllFilesCalled, 0); + aboutToRemoveAllFilesCalled++; + QCOMPARE(dir, deleteOnRemote ? SyncFileItem::Down : SyncFileItem::Up); + *cancel = true; + fakeFolder.syncEngine().journal()->clearFileTable(); // That's what Folder is doing + }); + + auto &modifier = deleteOnRemote ? fakeFolder.remoteModifier() : fakeFolder.localModifier(); + for (const auto &s : fakeFolder.currentRemoteState().children.keys()) + modifier.remove(s); + + QVERIFY(!fakeFolder.syncOnce()); // Should fail because we cancel the sync + QCOMPARE(aboutToRemoveAllFilesCalled, 1); + + // Next sync should recover all files + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), initialState); + QCOMPARE(fakeFolder.currentRemoteState(), initialState); + + // The selective sync blacklist should be not have been deleted. + bool ok = true; + QCOMPARE(fakeFolder.syncEngine().journal()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok), + selectiveSyncBlackList); + } + + void testAllFilesDeletedDelete_data() + { + testAllFilesDeletedKeep_data(); + } + + /* + * This test is like the previous one but we simulate that the user presses "delete" + */ + void testAllFilesDeletedDelete() + { + QFETCH(bool, deleteOnRemote); + FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()}; + + int aboutToRemoveAllFilesCalled = 0; + QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveAllFiles, + [&](SyncFileItem::Direction dir, bool *cancel) { + QCOMPARE(aboutToRemoveAllFilesCalled, 0); + aboutToRemoveAllFilesCalled++; + QCOMPARE(dir, deleteOnRemote ? SyncFileItem::Down : SyncFileItem::Up); + *cancel = false; + }); + + auto &modifier = deleteOnRemote ? fakeFolder.remoteModifier() : fakeFolder.localModifier(); + for (const auto &s : fakeFolder.currentRemoteState().children.keys()) + modifier.remove(s); + + QVERIFY(fakeFolder.syncOnce()); // Should succeed, and all files must then be deleted + + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + QCOMPARE(fakeFolder.currentLocalState().children.count(), 0); + + // Try another sync to be sure. + + QVERIFY(fakeFolder.syncOnce()); // Should succeed (doing nothing) + QCOMPARE(aboutToRemoveAllFilesCalled, 1); // should not have been called. + + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + QCOMPARE(fakeFolder.currentLocalState().children.count(), 0); + } +}; + +QTEST_GUILESS_MAIN(TestAllFilesDeleted) +#include "testallfilesdeleted.moc" |