testlocaldiscovery.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * This software is in the public domain, furnished "as is", without technical
  3. * support, and with no warranty, express or implied, as to its usefulness for
  4. * any purpose.
  5. *
  6. */
  7. #include <QtTest>
  8. #include "syncenginetestutils.h"
  9. #include <syncengine.h>
  10. #include <localdiscoverytracker.h>
  11. using namespace OCC;
  12. class TestLocalDiscovery : public QObject
  13. {
  14. Q_OBJECT
  15. private slots:
  16. // Check correct behavior when local discovery is partially drawn from the db
  17. void testLocalDiscoveryStyle()
  18. {
  19. FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
  20. LocalDiscoveryTracker tracker;
  21. connect(&fakeFolder.syncEngine(), &SyncEngine::itemCompleted, &tracker, &LocalDiscoveryTracker::slotItemCompleted);
  22. connect(&fakeFolder.syncEngine(), &SyncEngine::finished, &tracker, &LocalDiscoveryTracker::slotSyncFinished);
  23. // More subdirectories are useful for testing
  24. fakeFolder.localModifier().mkdir("A/X");
  25. fakeFolder.localModifier().mkdir("A/Y");
  26. fakeFolder.localModifier().insert("A/X/x1");
  27. fakeFolder.localModifier().insert("A/Y/y1");
  28. tracker.addTouchedPath("A/X");
  29. tracker.startSyncFullDiscovery();
  30. QVERIFY(fakeFolder.syncOnce());
  31. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  32. QVERIFY(tracker.localDiscoveryPaths().empty());
  33. // Test begins
  34. fakeFolder.localModifier().insert("A/a3");
  35. fakeFolder.localModifier().insert("A/X/x2");
  36. fakeFolder.localModifier().insert("A/Y/y2");
  37. fakeFolder.localModifier().insert("B/b3");
  38. fakeFolder.remoteModifier().insert("C/c3");
  39. fakeFolder.remoteModifier().appendByte("C/c1");
  40. tracker.addTouchedPath("A/X");
  41. fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths());
  42. tracker.startSyncPartialDiscovery();
  43. QVERIFY(fakeFolder.syncOnce());
  44. QVERIFY(fakeFolder.currentRemoteState().find("A/a3"));
  45. QVERIFY(fakeFolder.currentRemoteState().find("A/X/x2"));
  46. QVERIFY(!fakeFolder.currentRemoteState().find("A/Y/y2"));
  47. QVERIFY(!fakeFolder.currentRemoteState().find("B/b3"));
  48. QVERIFY(fakeFolder.currentLocalState().find("C/c3"));
  49. QCOMPARE(fakeFolder.syncEngine().lastLocalDiscoveryStyle(), LocalDiscoveryStyle::DatabaseAndFilesystem);
  50. QVERIFY(tracker.localDiscoveryPaths().empty());
  51. QVERIFY(fakeFolder.syncOnce());
  52. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  53. QCOMPARE(fakeFolder.syncEngine().lastLocalDiscoveryStyle(), LocalDiscoveryStyle::FilesystemOnly);
  54. QVERIFY(tracker.localDiscoveryPaths().empty());
  55. }
  56. void testLocalDiscoveryDecision()
  57. {
  58. FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
  59. auto &engine = fakeFolder.syncEngine();
  60. QVERIFY(engine.shouldDiscoverLocally(""));
  61. QVERIFY(engine.shouldDiscoverLocally("A"));
  62. QVERIFY(engine.shouldDiscoverLocally("A/X"));
  63. fakeFolder.syncEngine().setLocalDiscoveryOptions(
  64. LocalDiscoveryStyle::DatabaseAndFilesystem,
  65. { "A/X", "A/X space", "A/X/beta", "foo bar space/touch", "foo/", "zzz", "zzzz" });
  66. QVERIFY(engine.shouldDiscoverLocally(""));
  67. QVERIFY(engine.shouldDiscoverLocally("A"));
  68. QVERIFY(engine.shouldDiscoverLocally("A/X"));
  69. QVERIFY(!engine.shouldDiscoverLocally("B"));
  70. QVERIFY(!engine.shouldDiscoverLocally("A B"));
  71. QVERIFY(!engine.shouldDiscoverLocally("B/X"));
  72. QVERIFY(engine.shouldDiscoverLocally("foo bar space"));
  73. QVERIFY(engine.shouldDiscoverLocally("foo"));
  74. QVERIFY(!engine.shouldDiscoverLocally("foo bar"));
  75. QVERIFY(!engine.shouldDiscoverLocally("foo bar/touch"));
  76. // These are within "A/X" so they should be discovered
  77. QVERIFY(engine.shouldDiscoverLocally("A/X/alpha"));
  78. QVERIFY(engine.shouldDiscoverLocally("A/X beta"));
  79. QVERIFY(engine.shouldDiscoverLocally("A/X/Y"));
  80. QVERIFY(engine.shouldDiscoverLocally("A/X space"));
  81. QVERIFY(engine.shouldDiscoverLocally("A/X space/alpha"));
  82. QVERIFY(!engine.shouldDiscoverLocally("A/Xylo/foo"));
  83. QVERIFY(engine.shouldDiscoverLocally("zzzz/hello"));
  84. QVERIFY(!engine.shouldDiscoverLocally("zzza/hello"));
  85. QEXPECT_FAIL("", "There is a possibility of false positives if the set contains a path "
  86. "which is a prefix, and that prefix is followed by a character less than '/'", Continue);
  87. QVERIFY(!engine.shouldDiscoverLocally("A/X o"));
  88. fakeFolder.syncEngine().setLocalDiscoveryOptions(
  89. LocalDiscoveryStyle::DatabaseAndFilesystem,
  90. {});
  91. QVERIFY(!engine.shouldDiscoverLocally(""));
  92. }
  93. // Check whether item success and item failure adjusts the
  94. // tracker correctly.
  95. void testTrackerItemCompletion()
  96. {
  97. FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
  98. LocalDiscoveryTracker tracker;
  99. connect(&fakeFolder.syncEngine(), &SyncEngine::itemCompleted, &tracker, &LocalDiscoveryTracker::slotItemCompleted);
  100. connect(&fakeFolder.syncEngine(), &SyncEngine::finished, &tracker, &LocalDiscoveryTracker::slotSyncFinished);
  101. auto trackerContains = [&](const char *path) {
  102. return tracker.localDiscoveryPaths().find(path) != tracker.localDiscoveryPaths().end();
  103. };
  104. tracker.addTouchedPath("A/spurious");
  105. fakeFolder.localModifier().insert("A/a3");
  106. tracker.addTouchedPath("A/a3");
  107. fakeFolder.localModifier().insert("A/a4");
  108. fakeFolder.serverErrorPaths().append("A/a4");
  109. // We're not adding a4 as touched, it's in the same folder as a3 and will be seen.
  110. // And due to the error it should be added to the explicit list while a3 gets removed.
  111. fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths());
  112. tracker.startSyncPartialDiscovery();
  113. QVERIFY(!fakeFolder.syncOnce());
  114. QVERIFY(fakeFolder.currentRemoteState().find("A/a3"));
  115. QVERIFY(!fakeFolder.currentRemoteState().find("A/a4"));
  116. QVERIFY(!trackerContains("A/a3"));
  117. QVERIFY(trackerContains("A/a4"));
  118. QVERIFY(trackerContains("A/spurious")); // not removed since overall sync not successful
  119. fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::FilesystemOnly);
  120. tracker.startSyncFullDiscovery();
  121. QVERIFY(!fakeFolder.syncOnce());
  122. QVERIFY(!fakeFolder.currentRemoteState().find("A/a4"));
  123. QVERIFY(trackerContains("A/a4")); // had an error, still here
  124. QVERIFY(!trackerContains("A/spurious")); // removed due to full discovery
  125. fakeFolder.serverErrorPaths().clear();
  126. fakeFolder.syncJournal().wipeErrorBlacklist();
  127. tracker.addTouchedPath("A/newspurious"); // will be removed due to successful sync
  128. fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, tracker.localDiscoveryPaths());
  129. tracker.startSyncPartialDiscovery();
  130. QVERIFY(fakeFolder.syncOnce());
  131. QVERIFY(fakeFolder.currentRemoteState().find("A/a4"));
  132. QVERIFY(tracker.localDiscoveryPaths().empty());
  133. }
  134. void testDirectoryAndSubDirectory()
  135. {
  136. FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
  137. fakeFolder.localModifier().mkdir("A/newDir");
  138. fakeFolder.localModifier().mkdir("A/newDir/subDir");
  139. fakeFolder.localModifier().insert("A/newDir/subDir/file", 10);
  140. auto expectedState = fakeFolder.currentLocalState();
  141. // Only "A" was modified according to the file system tracker
  142. fakeFolder.syncEngine().setLocalDiscoveryOptions(
  143. LocalDiscoveryStyle::DatabaseAndFilesystem,
  144. { "A" });
  145. QVERIFY(fakeFolder.syncOnce());
  146. QCOMPARE(fakeFolder.currentLocalState(), expectedState);
  147. QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
  148. }
  149. // Tests the behavior of invalid filename detection
  150. void testServerBlacklist()
  151. {
  152. FakeFolder fakeFolder { FileInfo::A12_B12_C12_S12() };
  153. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  154. fakeFolder.syncEngine().account()->setCapabilities({ { "files",
  155. QVariantMap { { "blacklisted_files", QVariantList { ".foo", "bar" } } } } });
  156. fakeFolder.localModifier().insert("C/.foo");
  157. fakeFolder.localModifier().insert("C/bar");
  158. fakeFolder.localModifier().insert("C/moo");
  159. fakeFolder.localModifier().insert("C/.moo");
  160. QVERIFY(fakeFolder.syncOnce());
  161. QVERIFY(fakeFolder.currentRemoteState().find("C/moo"));
  162. QVERIFY(fakeFolder.currentRemoteState().find("C/.moo"));
  163. QVERIFY(!fakeFolder.currentRemoteState().find("C/.foo"));
  164. QVERIFY(!fakeFolder.currentRemoteState().find("C/bar"));
  165. }
  166. };
  167. QTEST_GUILESS_MAIN(TestLocalDiscovery)
  168. #include "testlocaldiscovery.moc"