testlocaldiscovery.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  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. void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameAndUploadFile()
  167. {
  168. FakeFolder fakeFolder{FileInfo{}};
  169. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  170. const QString fileWithSpaces1(" foo");
  171. const QString fileWithSpaces2(" bar ");
  172. const QString fileWithSpaces3("bla ");
  173. const QString fileWithSpaces4("A/ foo");
  174. const QString fileWithSpaces5("A/ bar ");
  175. const QString fileWithSpaces6("A/bla ");
  176. fakeFolder.localModifier().insert(fileWithSpaces1);
  177. fakeFolder.localModifier().insert(fileWithSpaces2);
  178. fakeFolder.localModifier().insert(fileWithSpaces3);
  179. fakeFolder.localModifier().mkdir("A");
  180. fakeFolder.localModifier().insert(fileWithSpaces4);
  181. fakeFolder.localModifier().insert(fileWithSpaces5);
  182. fakeFolder.localModifier().insert(fileWithSpaces6);
  183. QVERIFY(fakeFolder.syncOnce());
  184. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
  185. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
  186. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
  187. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
  188. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
  189. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
  190. QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
  191. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
  192. QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
  193. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
  194. QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
  195. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
  196. QVERIFY(fakeFolder.syncOnce());
  197. QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces1.trimmed()));
  198. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces1));
  199. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
  200. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
  201. QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces2.trimmed()));
  202. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces2));
  203. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
  204. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
  205. QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces3.trimmed()));
  206. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces3));
  207. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
  208. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
  209. QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
  210. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
  211. QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
  212. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
  213. QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
  214. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
  215. QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
  216. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
  217. QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
  218. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
  219. QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
  220. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
  221. }
  222. void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile()
  223. {
  224. FakeFolder fakeFolder{FileInfo{}};
  225. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  226. const QString fileWithSpaces4("A/ foo");
  227. const QString fileWithSpaces5("A/ bar ");
  228. const QString fileWithSpaces6("A/bla ");
  229. fakeFolder.remoteModifier().mkdir("A");
  230. fakeFolder.remoteModifier().insert(fileWithSpaces4);
  231. fakeFolder.remoteModifier().insert(fileWithSpaces5);
  232. fakeFolder.remoteModifier().insert(fileWithSpaces6);
  233. qDebug() << fakeFolder.currentRemoteState();
  234. QVERIFY(fakeFolder.syncOnce());
  235. qDebug() << fakeFolder.currentRemoteState();
  236. QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
  237. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
  238. QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
  239. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
  240. QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
  241. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
  242. QVERIFY(fakeFolder.syncOnce());
  243. QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
  244. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
  245. QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
  246. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
  247. QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
  248. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
  249. QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
  250. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
  251. QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
  252. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
  253. QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
  254. QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
  255. auto expectedState = fakeFolder.currentLocalState();
  256. QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
  257. }
  258. void testCreateFileWithTrailingSpaces_localTrimmedDoesExist_dontRenameAndUploadFile()
  259. {
  260. FakeFolder fakeFolder{FileInfo{}};
  261. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  262. const QString fileWithSpaces(" foo");
  263. const QString fileTrimmed("foo");
  264. fakeFolder.localModifier().insert(fileTrimmed);
  265. QVERIFY(fakeFolder.syncOnce());
  266. fakeFolder.localModifier().insert(fileWithSpaces);
  267. QVERIFY(!fakeFolder.syncOnce());
  268. QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
  269. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
  270. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces));
  271. QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
  272. }
  273. void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAndUploadFile()
  274. {
  275. FakeFolder fakeFolder{FileInfo{}};
  276. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  277. const QString fileWithSpaces(" foo");
  278. const QString fileTrimmed("foo");
  279. fakeFolder.localModifier().insert(fileTrimmed);
  280. fakeFolder.localModifier().insert(fileWithSpaces);
  281. QVERIFY(!fakeFolder.syncOnce());
  282. QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
  283. QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
  284. QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces));
  285. QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
  286. }
  287. void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedExists_renameFile()
  288. {
  289. FakeFolder fakeFolder{FileInfo{}};
  290. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  291. const QString fileWithSpaces1(" foo");
  292. const QString fileWithSpaces2(" bar ");
  293. const QString fileWithSpaces3("bla ");
  294. fakeFolder.localModifier().insert(fileWithSpaces1);
  295. fakeFolder.localModifier().insert(fileWithSpaces2);
  296. fakeFolder.localModifier().insert(fileWithSpaces3);
  297. fakeFolder.remoteModifier().insert(fileWithSpaces1);
  298. fakeFolder.remoteModifier().insert(fileWithSpaces2);
  299. fakeFolder.remoteModifier().insert(fileWithSpaces3);
  300. QVERIFY(fakeFolder.syncOnce());
  301. QVERIFY(fakeFolder.syncOnce());
  302. QVERIFY(fakeFolder.syncOnce());
  303. auto expectedState = fakeFolder.currentLocalState();
  304. qDebug() << expectedState;
  305. QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
  306. }
  307. void testBlockInvalidMtimeSyncRemote()
  308. {
  309. constexpr auto INVALID_MODTIME1 = 0;
  310. constexpr auto INVALID_MODTIME2 = -3600;
  311. FakeFolder fakeFolder{FileInfo{}};
  312. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  313. const QString fooFileRootFolder("foo");
  314. const QString barFileRootFolder("bar");
  315. const QString blaFileRootFolder("bla");
  316. const QString fooFileSubFolder("subfolder/foo");
  317. const QString barFileSubFolder("subfolder/bar");
  318. const QString blaFileSubFolder("subfolder/bla");
  319. fakeFolder.remoteModifier().insert(fooFileRootFolder);
  320. fakeFolder.remoteModifier().insert(barFileRootFolder);
  321. fakeFolder.remoteModifier().insert(blaFileRootFolder);
  322. fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder"));
  323. fakeFolder.remoteModifier().insert(fooFileSubFolder);
  324. fakeFolder.remoteModifier().insert(barFileSubFolder);
  325. fakeFolder.remoteModifier().insert(blaFileSubFolder);
  326. QVERIFY(fakeFolder.syncOnce());
  327. fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  328. fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  329. fakeFolder.remoteModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  330. fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  331. fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  332. fakeFolder.remoteModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  333. QVERIFY(!fakeFolder.syncOnce());
  334. QVERIFY(!fakeFolder.syncOnce());
  335. fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  336. fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  337. fakeFolder.remoteModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  338. fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  339. fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  340. fakeFolder.remoteModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  341. QVERIFY(!fakeFolder.syncOnce());
  342. QVERIFY(!fakeFolder.syncOnce());
  343. }
  344. void testBlockInvalidMtimeSyncLocal()
  345. {
  346. constexpr auto INVALID_MODTIME1 = 0;
  347. constexpr auto INVALID_MODTIME2 = -3600;
  348. FakeFolder fakeFolder{FileInfo{}};
  349. int nGET = 0;
  350. fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &, QIODevice *) {
  351. if (op == QNetworkAccessManager::GetOperation)
  352. ++nGET;
  353. return nullptr;
  354. });
  355. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  356. const QString fooFileRootFolder("foo");
  357. const QString barFileRootFolder("bar");
  358. const QString blaFileRootFolder("bla");
  359. const QString fooFileSubFolder("subfolder/foo");
  360. const QString barFileSubFolder("subfolder/bar");
  361. const QString blaFileSubFolder("subfolder/bla");
  362. fakeFolder.remoteModifier().insert(fooFileRootFolder);
  363. fakeFolder.remoteModifier().insert(barFileRootFolder);
  364. fakeFolder.remoteModifier().insert(blaFileRootFolder);
  365. fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder"));
  366. fakeFolder.remoteModifier().insert(fooFileSubFolder);
  367. fakeFolder.remoteModifier().insert(barFileSubFolder);
  368. fakeFolder.remoteModifier().insert(blaFileSubFolder);
  369. QVERIFY(fakeFolder.syncOnce());
  370. nGET = 0;
  371. fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  372. fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  373. fakeFolder.localModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  374. fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  375. fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  376. fakeFolder.localModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME1));
  377. QVERIFY(fakeFolder.syncOnce());
  378. QCOMPARE(nGET, 0);
  379. QVERIFY(fakeFolder.syncOnce());
  380. QCOMPARE(nGET, 0);
  381. fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  382. fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  383. fakeFolder.localModifier().setModTime(blaFileRootFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  384. fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  385. fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  386. fakeFolder.localModifier().setModTime(blaFileSubFolder, QDateTime::fromSecsSinceEpoch(INVALID_MODTIME2));
  387. QVERIFY(fakeFolder.syncOnce());
  388. QCOMPARE(nGET, 0);
  389. QVERIFY(fakeFolder.syncOnce());
  390. QCOMPARE(nGET, 0);
  391. }
  392. void testDoNotSyncInvalidFutureMtime()
  393. {
  394. constexpr auto FUTURE_MTIME = 0xFFFFFFFF;
  395. constexpr auto CURRENT_MTIME = 1646057277;
  396. FakeFolder fakeFolder{FileInfo{}};
  397. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  398. const QString fooFileRootFolder("foo");
  399. const QString barFileRootFolder("bar");
  400. const QString fooFileSubFolder("subfolder/foo");
  401. const QString barFileSubFolder("subfolder/bar");
  402. const QString fooFileAaaSubFolder("aaa/subfolder/foo");
  403. const QString barFileAaaSubFolder("aaa/subfolder/bar");
  404. fakeFolder.remoteModifier().insert(fooFileRootFolder);
  405. fakeFolder.remoteModifier().insert(barFileRootFolder);
  406. fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder"));
  407. fakeFolder.remoteModifier().insert(fooFileSubFolder);
  408. fakeFolder.remoteModifier().insert(barFileSubFolder);
  409. fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa"));
  410. fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa/subfolder"));
  411. fakeFolder.remoteModifier().insert(fooFileAaaSubFolder);
  412. fakeFolder.remoteModifier().insert(barFileAaaSubFolder);
  413. QVERIFY(fakeFolder.syncOnce());
  414. fakeFolder.remoteModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  415. fakeFolder.remoteModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  416. fakeFolder.remoteModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  417. fakeFolder.remoteModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  418. fakeFolder.remoteModifier().setModTime(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  419. fakeFolder.remoteModifier().setModTime(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  420. fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  421. fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  422. fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  423. fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  424. fakeFolder.localModifier().setModTime(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  425. fakeFolder.localModifier().setModTime(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  426. QVERIFY(!fakeFolder.syncOnce());
  427. }
  428. void testInvalidFutureMtimeRecovery()
  429. {
  430. constexpr auto FUTURE_MTIME = 0xFFFFFFFF;
  431. constexpr auto CURRENT_MTIME = 1646057277;
  432. FakeFolder fakeFolder{FileInfo{}};
  433. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  434. const QString fooFileRootFolder("foo");
  435. const QString barFileRootFolder("bar");
  436. const QString fooFileSubFolder("subfolder/foo");
  437. const QString barFileSubFolder("subfolder/bar");
  438. const QString fooFileAaaSubFolder("aaa/subfolder/foo");
  439. const QString barFileAaaSubFolder("aaa/subfolder/bar");
  440. fakeFolder.remoteModifier().insert(fooFileRootFolder);
  441. fakeFolder.remoteModifier().insert(barFileRootFolder);
  442. fakeFolder.remoteModifier().mkdir(QStringLiteral("subfolder"));
  443. fakeFolder.remoteModifier().insert(fooFileSubFolder);
  444. fakeFolder.remoteModifier().insert(barFileSubFolder);
  445. fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa"));
  446. fakeFolder.remoteModifier().mkdir(QStringLiteral("aaa/subfolder"));
  447. fakeFolder.remoteModifier().insert(fooFileAaaSubFolder);
  448. fakeFolder.remoteModifier().insert(barFileAaaSubFolder);
  449. QVERIFY(fakeFolder.syncOnce());
  450. fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  451. fakeFolder.remoteModifier().setModTimeKeepEtag(barFileRootFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  452. fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  453. fakeFolder.remoteModifier().setModTimeKeepEtag(barFileSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  454. fakeFolder.remoteModifier().setModTimeKeepEtag(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  455. fakeFolder.remoteModifier().setModTimeKeepEtag(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
  456. fakeFolder.localModifier().setModTime(fooFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  457. fakeFolder.localModifier().setModTime(barFileRootFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  458. fakeFolder.localModifier().setModTime(fooFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  459. fakeFolder.localModifier().setModTime(barFileSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  460. fakeFolder.localModifier().setModTime(fooFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  461. fakeFolder.localModifier().setModTime(barFileAaaSubFolder, QDateTime::fromSecsSinceEpoch(FUTURE_MTIME));
  462. QVERIFY(fakeFolder.syncOnce());
  463. QVERIFY(fakeFolder.syncOnce());
  464. auto expectedState = fakeFolder.currentLocalState();
  465. QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
  466. }
  467. };
  468. QTEST_GUILESS_MAIN(TestLocalDiscovery)
  469. #include "testlocaldiscovery.moc"