| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- * 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;
- bool itemDidComplete(const QSignalSpy &spy, const QString &path)
- {
- for(const QList<QVariant> &args : spy) {
- auto item = args[0].value<SyncFileItemPtr>();
- if (item->destination() == path)
- return true;
- }
- return false;
- }
- bool itemDidCompleteSuccessfully(const QSignalSpy &spy, const QString &path)
- {
- for(const QList<QVariant> &args : spy) {
- auto item = args[0].value<SyncFileItemPtr>();
- if (item->destination() == path)
- return item->_status == SyncFileItem::Success;
- }
- return false;
- }
- class TestSyncEngine : public QObject
- {
- Q_OBJECT
- private slots:
- void testFileDownload() {
- FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.remoteModifier().insert("A/a0");
- fakeFolder.syncOnce();
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a0"));
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- }
- void testFileUpload() {
- FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.localModifier().insert("A/a0");
- fakeFolder.syncOnce();
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a0"));
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- }
- void testDirDownload() {
- FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.remoteModifier().mkdir("Y");
- fakeFolder.remoteModifier().mkdir("Z");
- fakeFolder.remoteModifier().insert("Z/d0");
- fakeFolder.syncOnce();
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Y"));
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z"));
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z/d0"));
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- }
- void testDirUpload() {
- FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.localModifier().mkdir("Y");
- fakeFolder.localModifier().mkdir("Z");
- fakeFolder.localModifier().insert("Z/d0");
- fakeFolder.syncOnce();
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Y"));
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z"));
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "Z/d0"));
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- }
- void testLocalDelete() {
- FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.remoteModifier().remove("A/a1");
- fakeFolder.syncOnce();
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a1"));
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- }
- void testRemoteDelete() {
- FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.localModifier().remove("A/a1");
- fakeFolder.syncOnce();
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a1"));
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- }
- void testEmlLocalChecksum() {
- FakeFolder fakeFolder{FileInfo{}};
- fakeFolder.localModifier().insert("a1.eml", 64, 'A');
- fakeFolder.localModifier().insert("a2.eml", 64, 'A');
- fakeFolder.localModifier().insert("a3.eml", 64, 'A');
- // Upload and calculate the checksums
- // fakeFolder.syncOnce();
- fakeFolder.syncOnce();
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- // Touch the file without changing the content, shouldn't upload
- fakeFolder.localModifier().setContents("a1.eml", 'A');
- // Change the content/size
- fakeFolder.localModifier().setContents("a2.eml", 'B');
- fakeFolder.localModifier().appendByte("a3.eml");
- fakeFolder.syncOnce();
- QVERIFY(!itemDidComplete(completeSpy, "a1.eml"));
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "a2.eml"));
- QVERIFY(itemDidCompleteSuccessfully(completeSpy, "a3.eml"));
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- }
- void testRemoteChangeInMovedFolder() {
- // issue #5192
- FakeFolder fakeFolder{FileInfo{ QString(), {
- FileInfo { QStringLiteral("folder"), {
- FileInfo{ QStringLiteral("folderA"), { { QStringLiteral("file.txt"), 400 } } },
- QStringLiteral("folderB")
- }
- }}}};
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- // Edit a file in a moved directory.
- fakeFolder.remoteModifier().setContents("folder/folderA/file.txt", 'a');
- fakeFolder.remoteModifier().rename("folder/folderA", "folder/folderB/folderA");
- fakeFolder.syncOnce();
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- auto oldState = fakeFolder.currentLocalState();
- QVERIFY(oldState.find("folder/folderB/folderA/file.txt"));
- QVERIFY(!oldState.find("folder/folderA/file.txt"));
- // This sync should not remove the file
- fakeFolder.syncOnce();
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- QCOMPARE(fakeFolder.currentLocalState(), oldState);
- }
- void testSelectiveSyncModevFolder() {
- // issue #5224
- FakeFolder fakeFolder{FileInfo{ QString(), {
- FileInfo { QStringLiteral("parentFolder"), {
- FileInfo{ QStringLiteral("subFolderA"), { { QStringLiteral("fileA.txt"), 400 } } },
- FileInfo{ QStringLiteral("subFolderB"), { { QStringLiteral("fileB.txt"), 400 } } }
- }
- }}}};
- QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
- auto expectedServerState = fakeFolder.currentRemoteState();
- // Remove subFolderA with selectiveSync:
- fakeFolder.syncEngine().journal()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList,
- {"parentFolder/subFolderA/"});
- fakeFolder.syncEngine().journal()->avoidReadFromDbOnNextSync("parentFolder/subFolderA/");
- fakeFolder.syncOnce();
- {
- // Nothing changed on the server
- QCOMPARE(fakeFolder.currentRemoteState(), expectedServerState);
- // The local state should not have subFolderA
- auto remoteState = fakeFolder.currentRemoteState();
- remoteState.remove("parentFolder/subFolderA");
- QCOMPARE(fakeFolder.currentLocalState(), remoteState);
- }
- // Rename parentFolder on the server
- fakeFolder.remoteModifier().rename("parentFolder", "parentFolderRenamed");
- expectedServerState = fakeFolder.currentRemoteState();
- fakeFolder.syncOnce();
- {
- QCOMPARE(fakeFolder.currentRemoteState(), expectedServerState);
- auto remoteState = fakeFolder.currentRemoteState();
- // The subFolderA should still be there on the server.
- QVERIFY(remoteState.find("parentFolderRenamed/subFolderA/fileA.txt"));
- // But not on the client because of the selective sync
- remoteState.remove("parentFolderRenamed/subFolderA");
- QCOMPARE(fakeFolder.currentLocalState(), remoteState);
- }
- // Rename it again, locally this time.
- fakeFolder.localModifier().rename("parentFolderRenamed", "parentThirdName");
- fakeFolder.syncOnce();
- {
- auto remoteState = fakeFolder.currentRemoteState();
- // The subFolderA should still be there on the server.
- QVERIFY(remoteState.find("parentThirdName/subFolderA/fileA.txt"));
- // But not on the client because of the selective sync
- remoteState.remove("parentThirdName/subFolderA");
- QCOMPARE(fakeFolder.currentLocalState(), remoteState);
- expectedServerState = fakeFolder.currentRemoteState();
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.syncOnce(); // This sync should do nothing
- QCOMPARE(completeSpy.count(), 0);
- QCOMPARE(fakeFolder.currentRemoteState(), expectedServerState);
- QCOMPARE(fakeFolder.currentLocalState(), remoteState);
- }
- }
- void abortAfterFailedMkdir() {
- FakeFolder fakeFolder{FileInfo{}};
- QSignalSpy finishedSpy(&fakeFolder.syncEngine(), SIGNAL(finished(bool)));
- fakeFolder.serverErrorPaths().append("NewFolder");
- fakeFolder.localModifier().mkdir("NewFolder");
- // This should be aborted and would otherwise fail in FileInfo::create.
- fakeFolder.localModifier().insert("NewFolder/NewFile");
- fakeFolder.syncOnce();
- QCOMPARE(finishedSpy.size(), 1);
- QCOMPARE(finishedSpy.first().first().toBool(), false);
- }
- void testDirDownloadWithError() {
- FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
- QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
- fakeFolder.remoteModifier().mkdir("Y");
- fakeFolder.remoteModifier().mkdir("Y/Z");
- fakeFolder.remoteModifier().insert("Y/Z/d0");
- fakeFolder.remoteModifier().insert("Y/Z/d1");
- fakeFolder.remoteModifier().insert("Y/Z/d2");
- fakeFolder.remoteModifier().insert("Y/Z/d3");
- fakeFolder.remoteModifier().insert("Y/Z/d4");
- fakeFolder.remoteModifier().insert("Y/Z/d5");
- fakeFolder.remoteModifier().insert("Y/Z/d6");
- fakeFolder.remoteModifier().insert("Y/Z/d7");
- fakeFolder.remoteModifier().insert("Y/Z/d8");
- fakeFolder.remoteModifier().insert("Y/Z/d9");
- fakeFolder.serverErrorPaths().append("Y/Z/d2", 503); // 503 is a fatal error
- fakeFolder.serverErrorPaths().append("Y/Z/d3", 503); // 503 is a fatal error
- QVERIFY(!fakeFolder.syncOnce());
- QCoreApplication::processEvents(); // should not crash
- QSet<QString> seen;
- for(const QList<QVariant> &args : completeSpy) {
- auto item = args[0].value<SyncFileItemPtr>();
- qDebug() << item->_file << item->_isDirectory << item->_status;
- QVERIFY(!seen.contains(item->_file)); // signal only sent once per item
- seen.insert(item->_file);
- if (item->_file == "Y/Z/d2") {
- QVERIFY(item->_status == SyncFileItem::FatalError);
- } else if(item->_file == "Y/Z/d3") {
- QVERIFY(item->_status != SyncFileItem::Success);
- }
- QVERIFY(item->_file != "Y/Z/d9"); // we should have aborted the sync before d9 starts
- }
- }
- };
- QTEST_GUILESS_MAIN(TestSyncEngine)
- #include "testsyncengine.moc"
|