testlockfile.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. #include "lockfilejobs.h"
  2. #include "account.h"
  3. #include "accountstate.h"
  4. #include "common/syncjournaldb.h"
  5. #include "common/syncjournalfilerecord.h"
  6. #include "syncenginetestutils.h"
  7. #include <QTest>
  8. #include <QSignalSpy>
  9. class TestLockFile : public QObject
  10. {
  11. Q_OBJECT
  12. public:
  13. TestLockFile() = default;
  14. private slots:
  15. void initTestCase()
  16. {
  17. }
  18. void testLockFile_lockFile_lockSuccess()
  19. {
  20. const auto testFileName = QStringLiteral("file.txt");
  21. FakeFolder fakeFolder{FileInfo{}};
  22. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  23. QSignalSpy lockFileSuccessSpy(fakeFolder.account().data(), &OCC::Account::lockFileSuccess);
  24. QSignalSpy lockFileErrorSpy(fakeFolder.account().data(), &OCC::Account::lockFileError);
  25. fakeFolder.localModifier().insert(testFileName);
  26. QVERIFY(fakeFolder.syncOnce());
  27. fakeFolder.account()->setLockFileState(QStringLiteral("/") + testFileName, &fakeFolder.syncJournal(), OCC::SyncFileItem::LockStatus::LockedItem);
  28. QVERIFY(lockFileSuccessSpy.wait());
  29. QCOMPARE(lockFileErrorSpy.count(), 0);
  30. }
  31. void testLockFile_lockFile_lockError()
  32. {
  33. const auto testFileName = QStringLiteral("file.txt");
  34. static constexpr auto LockedHttpErrorCode = 423;
  35. const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
  36. "<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
  37. " <nc:lock/>\n"
  38. " <nc:lock-owner-type>0</nc:lock-owner-type>\n"
  39. " <nc:lock-owner>john</nc:lock-owner>\n"
  40. " <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
  41. " <nc:lock-owner-editor>john</nc:lock-owner-editor>\n"
  42. " <nc:lock-time>1650619678</nc:lock-time>\n"
  43. " <nc:lock-timeout>300</nc:lock-timeout>\n"
  44. " <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
  45. "</d:prop>\n");
  46. FakeFolder fakeFolder{FileInfo{}};
  47. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  48. fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
  49. QNetworkReply *reply = nullptr;
  50. if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
  51. reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
  52. }
  53. return reply;
  54. });
  55. QSignalSpy lockFileSuccessSpy(fakeFolder.account().data(), &OCC::Account::lockFileSuccess);
  56. QSignalSpy lockFileErrorSpy(fakeFolder.account().data(), &OCC::Account::lockFileError);
  57. fakeFolder.localModifier().insert(testFileName);
  58. QVERIFY(fakeFolder.syncOnce());
  59. fakeFolder.account()->setLockFileState(QStringLiteral("/") + testFileName, &fakeFolder.syncJournal(), OCC::SyncFileItem::LockStatus::LockedItem);
  60. QVERIFY(lockFileErrorSpy.wait());
  61. QCOMPARE(lockFileSuccessSpy.count(), 0);
  62. }
  63. void testLockFile_fileLockStatus_queryLockStatus()
  64. {
  65. const auto testFileName = QStringLiteral("file.txt");
  66. FakeFolder fakeFolder{FileInfo{}};
  67. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  68. QSignalSpy lockFileSuccessSpy(fakeFolder.account().data(), &OCC::Account::lockFileSuccess);
  69. QSignalSpy lockFileErrorSpy(fakeFolder.account().data(), &OCC::Account::lockFileError);
  70. fakeFolder.localModifier().insert(testFileName);
  71. QVERIFY(fakeFolder.syncOnce());
  72. fakeFolder.account()->setLockFileState(QStringLiteral("/") + testFileName, &fakeFolder.syncJournal(), OCC::SyncFileItem::LockStatus::LockedItem);
  73. QVERIFY(lockFileSuccessSpy.wait());
  74. QCOMPARE(lockFileErrorSpy.count(), 0);
  75. auto lockStatus = fakeFolder.account()->fileLockStatus(&fakeFolder.syncJournal(), testFileName);
  76. QCOMPARE(lockStatus, OCC::SyncFileItem::LockStatus::LockedItem);
  77. }
  78. void testLockFile_fileCanBeUnlocked_canUnlock()
  79. {
  80. const auto testFileName = QStringLiteral("file.txt");
  81. FakeFolder fakeFolder{FileInfo{}};
  82. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  83. QSignalSpy lockFileSuccessSpy(fakeFolder.account().data(), &OCC::Account::lockFileSuccess);
  84. QSignalSpy lockFileErrorSpy(fakeFolder.account().data(), &OCC::Account::lockFileError);
  85. fakeFolder.localModifier().insert(testFileName);
  86. QVERIFY(fakeFolder.syncOnce());
  87. fakeFolder.account()->setLockFileState(QStringLiteral("/") + testFileName, &fakeFolder.syncJournal(), OCC::SyncFileItem::LockStatus::LockedItem);
  88. QVERIFY(lockFileSuccessSpy.wait());
  89. QCOMPARE(lockFileErrorSpy.count(), 0);
  90. auto lockStatus = fakeFolder.account()->fileCanBeUnlocked(&fakeFolder.syncJournal(), testFileName);
  91. QCOMPARE(lockStatus, true);
  92. }
  93. void testLockFile_lockFile_jobSuccess()
  94. {
  95. const auto testFileName = QStringLiteral("file.txt");
  96. FakeFolder fakeFolder{FileInfo{}};
  97. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  98. fakeFolder.localModifier().insert(testFileName);
  99. QVERIFY(fakeFolder.syncOnce());
  100. auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
  101. QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
  102. QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
  103. job->start();
  104. QVERIFY(jobSuccess.wait());
  105. QCOMPARE(jobFailure.count(), 0);
  106. auto fileRecord = OCC::SyncJournalFileRecord{};
  107. QVERIFY(fakeFolder.syncJournal().getFileRecord(testFileName, &fileRecord));
  108. QCOMPARE(fileRecord._lockstate._locked, true);
  109. QCOMPARE(fileRecord._lockstate._lockEditorApp, QString{});
  110. QCOMPARE(fileRecord._lockstate._lockOwnerDisplayName, QStringLiteral("John Doe"));
  111. QCOMPARE(fileRecord._lockstate._lockOwnerId, QStringLiteral("admin"));
  112. QCOMPARE(fileRecord._lockstate._lockOwnerType, static_cast<qint64>(OCC::SyncFileItem::LockOwnerType::UserLock));
  113. QCOMPARE(fileRecord._lockstate._lockTime, 1234560);
  114. QCOMPARE(fileRecord._lockstate._lockTimeout, 1800);
  115. QVERIFY(fakeFolder.syncOnce());
  116. }
  117. void testLockFile_lockFile_unlockFile_jobSuccess()
  118. {
  119. const auto testFileName = QStringLiteral("file.txt");
  120. FakeFolder fakeFolder{FileInfo{}};
  121. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  122. fakeFolder.localModifier().insert(testFileName);
  123. QVERIFY(fakeFolder.syncOnce());
  124. auto lockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
  125. QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
  126. QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
  127. lockFileJob->start();
  128. QVERIFY(lockFileJobSuccess.wait());
  129. QCOMPARE(lockFileJobFailure.count(), 0);
  130. QVERIFY(fakeFolder.syncOnce());
  131. auto unlockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
  132. QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
  133. QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
  134. unlockFileJob->start();
  135. QVERIFY(unlockFileJobSuccess.wait());
  136. QCOMPARE(unlockFileJobFailure.count(), 0);
  137. auto fileRecord = OCC::SyncJournalFileRecord{};
  138. QVERIFY(fakeFolder.syncJournal().getFileRecord(testFileName, &fileRecord));
  139. QCOMPARE(fileRecord._lockstate._locked, false);
  140. QVERIFY(fakeFolder.syncOnce());
  141. }
  142. void testLockFile_lockFile_alreadyLockedByUser()
  143. {
  144. static constexpr auto LockedHttpErrorCode = 423;
  145. static constexpr auto PreconditionFailedHttpErrorCode = 412;
  146. const auto testFileName = QStringLiteral("file.txt");
  147. const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
  148. "<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
  149. " <nc:lock>1</nc:lock>\n"
  150. " <nc:lock-owner-type>0</nc:lock-owner-type>\n"
  151. " <nc:lock-owner>john</nc:lock-owner>\n"
  152. " <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
  153. " <nc:lock-owner-editor>john</nc:lock-owner-editor>\n"
  154. " <nc:lock-time>1650619678</nc:lock-time>\n"
  155. " <nc:lock-timeout>300</nc:lock-timeout>\n"
  156. " <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
  157. "</d:prop>\n");
  158. FakeFolder fakeFolder{FileInfo{}};
  159. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  160. fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
  161. QNetworkReply *reply = nullptr;
  162. if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
  163. reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
  164. } else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
  165. reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
  166. }
  167. return reply;
  168. });
  169. fakeFolder.localModifier().insert(testFileName);
  170. QVERIFY(fakeFolder.syncOnce());
  171. auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
  172. QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
  173. QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
  174. job->start();
  175. QVERIFY(jobFailure.wait());
  176. QCOMPARE(jobSuccess.count(), 0);
  177. }
  178. void testLockFile_lockFile_alreadyLockedByApp()
  179. {
  180. static constexpr auto LockedHttpErrorCode = 423;
  181. static constexpr auto PreconditionFailedHttpErrorCode = 412;
  182. const auto testFileName = QStringLiteral("file.txt");
  183. const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
  184. "<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
  185. " <nc:lock>1</nc:lock>\n"
  186. " <nc:lock-owner-type>1</nc:lock-owner-type>\n"
  187. " <nc:lock-owner>john</nc:lock-owner>\n"
  188. " <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
  189. " <nc:lock-owner-editor>Text</nc:lock-owner-editor>\n"
  190. " <nc:lock-time>1650619678</nc:lock-time>\n"
  191. " <nc:lock-timeout>300</nc:lock-timeout>\n"
  192. " <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
  193. "</d:prop>\n");
  194. FakeFolder fakeFolder{FileInfo{}};
  195. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  196. fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
  197. QNetworkReply *reply = nullptr;
  198. if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
  199. reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
  200. } else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
  201. reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
  202. }
  203. return reply;
  204. });
  205. fakeFolder.localModifier().insert(testFileName);
  206. QVERIFY(fakeFolder.syncOnce());
  207. auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
  208. QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
  209. QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
  210. job->start();
  211. QVERIFY(jobFailure.wait());
  212. QCOMPARE(jobSuccess.count(), 0);
  213. }
  214. void testLockFile_unlockFile_alreadyUnlocked()
  215. {
  216. static constexpr auto LockedHttpErrorCode = 423;
  217. static constexpr auto PreconditionFailedHttpErrorCode = 412;
  218. const auto testFileName = QStringLiteral("file.txt");
  219. const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
  220. "<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
  221. " <nc:lock/>\n"
  222. " <nc:lock-owner-type>0</nc:lock-owner-type>\n"
  223. " <nc:lock-owner>john</nc:lock-owner>\n"
  224. " <nc:lock-owner-displayname>John Doe</nc:lock-owner-displayname>\n"
  225. " <nc:lock-owner-editor>john</nc:lock-owner-editor>\n"
  226. " <nc:lock-time>1650619678</nc:lock-time>\n"
  227. " <nc:lock-timeout>300</nc:lock-timeout>\n"
  228. " <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
  229. "</d:prop>\n");
  230. FakeFolder fakeFolder{FileInfo{}};
  231. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  232. fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
  233. QNetworkReply *reply = nullptr;
  234. if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK")) {
  235. reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
  236. } else if (op == QNetworkAccessManager::CustomOperation && request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK")) {
  237. reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
  238. }
  239. return reply;
  240. });
  241. fakeFolder.localModifier().insert(testFileName);
  242. QVERIFY(fakeFolder.syncOnce());
  243. auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
  244. QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
  245. QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
  246. job->start();
  247. QVERIFY(jobSuccess.wait());
  248. QCOMPARE(jobFailure.count(), 0);
  249. }
  250. void testLockFile_unlockFile_lockedBySomeoneElse()
  251. {
  252. static constexpr auto LockedHttpErrorCode = 423;
  253. const auto testFileName = QStringLiteral("file.txt");
  254. const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
  255. "<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
  256. " <nc:lock>1</nc:lock>\n"
  257. " <nc:lock-owner-type>0</nc:lock-owner-type>\n"
  258. " <nc:lock-owner>alice</nc:lock-owner>\n"
  259. " <nc:lock-owner-displayname>Alice Doe</nc:lock-owner-displayname>\n"
  260. " <nc:lock-owner-editor>Text</nc:lock-owner-editor>\n"
  261. " <nc:lock-time>1650619678</nc:lock-time>\n"
  262. " <nc:lock-timeout>300</nc:lock-timeout>\n"
  263. " <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
  264. "</d:prop>\n");
  265. FakeFolder fakeFolder{FileInfo{}};
  266. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  267. fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
  268. QNetworkReply *reply = nullptr;
  269. if (op == QNetworkAccessManager::CustomOperation && (request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK") ||
  270. request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK"))) {
  271. reply = new FakeErrorReply(op, request, nullptr, LockedHttpErrorCode, replyData);
  272. }
  273. return reply;
  274. });
  275. fakeFolder.localModifier().insert(testFileName);
  276. QVERIFY(fakeFolder.syncOnce());
  277. auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
  278. QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
  279. QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
  280. job->start();
  281. QVERIFY(jobFailure.wait());
  282. QCOMPARE(jobSuccess.count(), 0);
  283. }
  284. void testLockFile_lockFile_jobError()
  285. {
  286. const auto testFileName = QStringLiteral("file.txt");
  287. static constexpr auto InternalServerErrorHttpErrorCode = 500;
  288. FakeFolder fakeFolder{FileInfo{}};
  289. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  290. fakeFolder.setServerOverride([] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
  291. QNetworkReply *reply = nullptr;
  292. if (op == QNetworkAccessManager::CustomOperation && (request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK") ||
  293. request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK"))) {
  294. reply = new FakeErrorReply(op, request, nullptr, InternalServerErrorHttpErrorCode, {});
  295. }
  296. return reply;
  297. });
  298. fakeFolder.localModifier().insert(QStringLiteral("file.txt"));
  299. QVERIFY(fakeFolder.syncOnce());
  300. auto lockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::LockedItem);
  301. QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
  302. QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
  303. lockFileJob->start();
  304. QVERIFY(lockFileJobFailure.wait());
  305. QCOMPARE(lockFileJobSuccess.count(), 0);
  306. QVERIFY(fakeFolder.syncOnce());
  307. auto unlockFileJob = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
  308. QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
  309. QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
  310. unlockFileJob->start();
  311. QVERIFY(unlockFileJobFailure.wait());
  312. QCOMPARE(unlockFileJobSuccess.count(), 0);
  313. QVERIFY(fakeFolder.syncOnce());
  314. }
  315. void testLockFile_lockFile_preconditionFailedError()
  316. {
  317. static constexpr auto PreconditionFailedHttpErrorCode = 412;
  318. const auto testFileName = QStringLiteral("file.txt");
  319. const auto replyData = QByteArray("<?xml version=\"1.0\"?>\n"
  320. "<d:prop xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n"
  321. " <nc:lock>1</nc:lock>\n"
  322. " <nc:lock-owner-type>0</nc:lock-owner-type>\n"
  323. " <nc:lock-owner>alice</nc:lock-owner>\n"
  324. " <nc:lock-owner-displayname>Alice Doe</nc:lock-owner-displayname>\n"
  325. " <nc:lock-owner-editor>Text</nc:lock-owner-editor>\n"
  326. " <nc:lock-time>1650619678</nc:lock-time>\n"
  327. " <nc:lock-timeout>300</nc:lock-timeout>\n"
  328. " <nc:lock-token>files_lock/310997d7-0aae-4e48-97e1-eeb6be6e2202</nc:lock-token>\n"
  329. "</d:prop>\n");
  330. FakeFolder fakeFolder{FileInfo{}};
  331. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  332. fakeFolder.setServerOverride([replyData] (FakeQNAM::Operation op, const QNetworkRequest &request, QIODevice *) {
  333. QNetworkReply *reply = nullptr;
  334. if (op == QNetworkAccessManager::CustomOperation && (request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("LOCK") ||
  335. request.attribute(QNetworkRequest::CustomVerbAttribute).toString() == QStringLiteral("UNLOCK"))) {
  336. reply = new FakeErrorReply(op, request, nullptr, PreconditionFailedHttpErrorCode, replyData);
  337. }
  338. return reply;
  339. });
  340. fakeFolder.localModifier().insert(testFileName);
  341. QVERIFY(fakeFolder.syncOnce());
  342. auto job = new OCC::LockFileJob(fakeFolder.account(), &fakeFolder.syncJournal(), QStringLiteral("/") + testFileName, OCC::SyncFileItem::LockStatus::UnlockedItem);
  343. QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
  344. QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
  345. job->start();
  346. QVERIFY(jobFailure.wait());
  347. QCOMPARE(jobSuccess.count(), 0);
  348. }
  349. };
  350. QTEST_GUILESS_MAIN(TestLockFile)
  351. #include "testlockfile.moc"