testblacklist.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. using namespace OCC;
  11. SyncJournalFileRecord journalRecord(FakeFolder &folder, const QByteArray &path)
  12. {
  13. SyncJournalFileRecord rec;
  14. folder.syncJournal().getFileRecord(path, &rec);
  15. return rec;
  16. }
  17. class TestBlacklist : public QObject
  18. {
  19. Q_OBJECT
  20. private slots:
  21. void testBlacklistBasic_data()
  22. {
  23. QTest::addColumn<bool>("remote");
  24. QTest::newRow("remote") << true;
  25. QTest::newRow("local") << false;
  26. }
  27. void testBlacklistBasic()
  28. {
  29. QFETCH(bool, remote);
  30. FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
  31. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  32. ItemCompletedSpy completeSpy(fakeFolder);
  33. auto &modifier = remote ? fakeFolder.remoteModifier() : fakeFolder.localModifier();
  34. int counter = 0;
  35. QByteArray reqId;
  36. fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *) -> QNetworkReply * {
  37. reqId = req.rawHeader("X-Request-ID");
  38. if (!remote && op == QNetworkAccessManager::PutOperation)
  39. ++counter;
  40. if (remote && op == QNetworkAccessManager::GetOperation)
  41. ++counter;
  42. return nullptr;
  43. });
  44. auto cleanup = [&]() {
  45. completeSpy.clear();
  46. };
  47. auto initialEtag = journalRecord(fakeFolder, "A")._etag;
  48. QVERIFY(!initialEtag.isEmpty());
  49. // The first sync and the download will fail - the item will be blacklisted
  50. modifier.insert("A/new");
  51. fakeFolder.serverErrorPaths().append("A/new", 500); // will be blacklisted
  52. QVERIFY(!fakeFolder.syncOnce());
  53. {
  54. auto it = completeSpy.findItem("A/new");
  55. QVERIFY(it);
  56. QCOMPARE(it->_status, SyncFileItem::NormalError); // initial error visible
  57. QCOMPARE(it->_instruction, CSYNC_INSTRUCTION_NEW);
  58. auto entry = fakeFolder.syncJournal().errorBlacklistEntry("A/new");
  59. QVERIFY(entry.isValid());
  60. QCOMPARE(entry._errorCategory, SyncJournalErrorBlacklistRecord::Normal);
  61. QCOMPARE(entry._retryCount, 1);
  62. QCOMPARE(counter, 1);
  63. QVERIFY(entry._ignoreDuration > 0);
  64. QCOMPARE(entry._requestId, reqId);
  65. if (remote)
  66. QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
  67. }
  68. cleanup();
  69. // Ignored during the second run - but soft errors are also errors
  70. QVERIFY(!fakeFolder.syncOnce());
  71. {
  72. auto it = completeSpy.findItem("A/new");
  73. QVERIFY(it);
  74. QCOMPARE(it->_status, SyncFileItem::BlacklistedError);
  75. QCOMPARE(it->_instruction, CSYNC_INSTRUCTION_IGNORE); // no retry happened!
  76. auto entry = fakeFolder.syncJournal().errorBlacklistEntry("A/new");
  77. QVERIFY(entry.isValid());
  78. QCOMPARE(entry._errorCategory, SyncJournalErrorBlacklistRecord::Normal);
  79. QCOMPARE(entry._retryCount, 1);
  80. QCOMPARE(counter, 1);
  81. QVERIFY(entry._ignoreDuration > 0);
  82. QCOMPARE(entry._requestId, reqId);
  83. if (remote)
  84. QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
  85. }
  86. cleanup();
  87. // Let's expire the blacklist entry to verify it gets retried
  88. {
  89. auto entry = fakeFolder.syncJournal().errorBlacklistEntry("A/new");
  90. entry._ignoreDuration = 1;
  91. entry._lastTryTime -= 1;
  92. fakeFolder.syncJournal().setErrorBlacklistEntry(entry);
  93. }
  94. QVERIFY(!fakeFolder.syncOnce());
  95. {
  96. auto it = completeSpy.findItem("A/new");
  97. QVERIFY(it);
  98. QCOMPARE(it->_status, SyncFileItem::BlacklistedError); // blacklisted as it's just a retry
  99. QCOMPARE(it->_instruction, CSYNC_INSTRUCTION_NEW); // retry!
  100. auto entry = fakeFolder.syncJournal().errorBlacklistEntry("A/new");
  101. QVERIFY(entry.isValid());
  102. QCOMPARE(entry._errorCategory, SyncJournalErrorBlacklistRecord::Normal);
  103. QCOMPARE(entry._retryCount, 2);
  104. QCOMPARE(counter, 2);
  105. QVERIFY(entry._ignoreDuration > 0);
  106. QCOMPARE(entry._requestId, reqId);
  107. if (remote)
  108. QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
  109. }
  110. cleanup();
  111. // When the file changes a retry happens immediately
  112. modifier.appendByte("A/new");
  113. QVERIFY(!fakeFolder.syncOnce());
  114. {
  115. auto it = completeSpy.findItem("A/new");
  116. QVERIFY(it);
  117. QCOMPARE(it->_status, SyncFileItem::BlacklistedError);
  118. QCOMPARE(it->_instruction, CSYNC_INSTRUCTION_NEW); // retry!
  119. auto entry = fakeFolder.syncJournal().errorBlacklistEntry("A/new");
  120. QVERIFY(entry.isValid());
  121. QCOMPARE(entry._errorCategory, SyncJournalErrorBlacklistRecord::Normal);
  122. QCOMPARE(entry._retryCount, 3);
  123. QCOMPARE(counter, 3);
  124. QVERIFY(entry._ignoreDuration > 0);
  125. QCOMPARE(entry._requestId, reqId);
  126. if (remote)
  127. QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
  128. }
  129. cleanup();
  130. // When the error goes away and the item is retried, the sync succeeds
  131. fakeFolder.serverErrorPaths().clear();
  132. {
  133. auto entry = fakeFolder.syncJournal().errorBlacklistEntry("A/new");
  134. entry._ignoreDuration = 1;
  135. entry._lastTryTime -= 1;
  136. fakeFolder.syncJournal().setErrorBlacklistEntry(entry);
  137. }
  138. QVERIFY(fakeFolder.syncOnce());
  139. {
  140. auto it = completeSpy.findItem("A/new");
  141. QVERIFY(it);
  142. QCOMPARE(it->_status, SyncFileItem::Success);
  143. QCOMPARE(it->_instruction, CSYNC_INSTRUCTION_NEW);
  144. auto entry = fakeFolder.syncJournal().errorBlacklistEntry("A/new");
  145. QVERIFY(!entry.isValid());
  146. QCOMPARE(counter, 4);
  147. if (remote)
  148. QCOMPARE(journalRecord(fakeFolder, "A")._etag, fakeFolder.currentRemoteState().find("A")->etag.toUtf8());
  149. }
  150. cleanup();
  151. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  152. }
  153. };
  154. QTEST_GUILESS_MAIN(TestBlacklist)
  155. #include "testblacklist.moc"