BackFillDeletedFilesTests.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. const { exec } = require('child_process')
  2. const { promisify } = require('util')
  3. const { expect } = require('chai')
  4. const logger = require('@overleaf/logger')
  5. const { db, ObjectId } = require('../../../app/src/infrastructure/mongodb')
  6. const User = require('./helpers/User').promises
  7. async function getDeletedFiles(projectId) {
  8. return (await db.projects.findOne({ _id: projectId })).deletedFiles
  9. }
  10. async function setDeletedFiles(projectId, deletedFiles) {
  11. await db.projects.updateOne({ _id: projectId }, { $set: { deletedFiles } })
  12. }
  13. async function unsetDeletedFiles(projectId) {
  14. await db.projects.updateOne(
  15. { _id: projectId },
  16. { $unset: { deletedFiles: 1 } }
  17. )
  18. }
  19. describe('BackFillDeletedFiles', function () {
  20. let user, projectId1, projectId2, projectId3, projectId4, projectId5
  21. beforeEach('create projects', async function () {
  22. user = new User()
  23. await user.login()
  24. projectId1 = ObjectId(await user.createProject('project1'))
  25. projectId2 = ObjectId(await user.createProject('project2'))
  26. projectId3 = ObjectId(await user.createProject('project3'))
  27. projectId4 = ObjectId(await user.createProject('project4'))
  28. projectId5 = ObjectId(await user.createProject('project5'))
  29. })
  30. let fileId1, fileId2, fileId3, fileId4
  31. beforeEach('create files', function () {
  32. // take a short cut and just allocate file ids
  33. fileId1 = ObjectId()
  34. fileId2 = ObjectId()
  35. fileId3 = ObjectId()
  36. fileId4 = ObjectId()
  37. })
  38. const otherFileDetails = {
  39. name: 'universe.jpg',
  40. linkedFileData: null,
  41. hash: 'ed19e7d6779b47d8c63f6fa5a21954dcfb6cac00',
  42. deletedAt: new Date(),
  43. __v: 0,
  44. }
  45. let deletedFiles1, deletedFiles2, deletedFiles3
  46. beforeEach('set deletedFiles details', async function () {
  47. deletedFiles1 = [
  48. { _id: fileId1, ...otherFileDetails },
  49. { _id: fileId2, ...otherFileDetails },
  50. ]
  51. deletedFiles2 = [{ _id: fileId3, ...otherFileDetails }]
  52. await setDeletedFiles(projectId1, deletedFiles1)
  53. await setDeletedFiles(projectId2, deletedFiles2)
  54. // a project without deletedFiles entries
  55. await setDeletedFiles(projectId3, [])
  56. // a project without deletedFiles array
  57. await unsetDeletedFiles(projectId4)
  58. // duplicate entry
  59. deletedFiles3 = [
  60. { _id: fileId4, ...otherFileDetails },
  61. { _id: fileId4, ...otherFileDetails },
  62. ]
  63. await setDeletedFiles(projectId5, deletedFiles3)
  64. })
  65. async function runScript(args = []) {
  66. let result
  67. try {
  68. result = await promisify(exec)(
  69. ['LET_USER_DOUBLE_CHECK_INPUTS_FOR=1']
  70. .concat(['node', 'scripts/back_fill_deleted_files'])
  71. .concat(args)
  72. .join(' ')
  73. )
  74. } catch (error) {
  75. // dump details like exit code, stdErr and stdOut
  76. logger.error({ error }, 'script failed')
  77. throw error
  78. }
  79. const { stderr: stdErr } = result
  80. expect(stdErr).to.include(`Completed batch ending ${projectId5}`)
  81. }
  82. function checkAreFilesBackFilled() {
  83. it('should back fill file and set projectId', async function () {
  84. const docs = await db.deletedFiles
  85. .find({}, { sort: { _id: 1 } })
  86. .toArray()
  87. expect(docs).to.deep.equal([
  88. { _id: fileId1, projectId: projectId1, ...otherFileDetails },
  89. { _id: fileId2, projectId: projectId1, ...otherFileDetails },
  90. { _id: fileId3, projectId: projectId2, ...otherFileDetails },
  91. { _id: fileId4, projectId: projectId5, ...otherFileDetails },
  92. ])
  93. })
  94. }
  95. describe('back fill only', function () {
  96. beforeEach('run script', runScript)
  97. checkAreFilesBackFilled()
  98. it('should leave the deletedFiles as is', async function () {
  99. expect(await getDeletedFiles(projectId1)).to.deep.equal(deletedFiles1)
  100. expect(await getDeletedFiles(projectId2)).to.deep.equal(deletedFiles2)
  101. expect(await getDeletedFiles(projectId5)).to.deep.equal(deletedFiles3)
  102. })
  103. })
  104. describe('back fill and cleanup', function () {
  105. beforeEach('run script with cleanup flag', async function () {
  106. await runScript(['--perform-cleanup'])
  107. })
  108. checkAreFilesBackFilled()
  109. it('should cleanup the deletedFiles', async function () {
  110. expect(await getDeletedFiles(projectId1)).to.deep.equal([])
  111. expect(await getDeletedFiles(projectId2)).to.deep.equal([])
  112. expect(await getDeletedFiles(projectId5)).to.deep.equal([])
  113. })
  114. })
  115. describe('fix partial inserts and cleanup', function () {
  116. beforeEach('simulate one missing insert', async function () {
  117. await setDeletedFiles(projectId1, [deletedFiles1[0]])
  118. })
  119. beforeEach('run script with cleanup flag', async function () {
  120. await runScript(['--perform-cleanup'])
  121. })
  122. beforeEach('add case for one missing file', async function () {
  123. await setDeletedFiles(projectId1, deletedFiles1)
  124. })
  125. beforeEach('add cases for no more files to insert', async function () {
  126. await setDeletedFiles(projectId2, deletedFiles2)
  127. await setDeletedFiles(projectId5, deletedFiles3)
  128. })
  129. beforeEach('fixing partial insert and cleanup', async function () {
  130. await runScript(['--fix-partial-inserts', '--perform-cleanup'])
  131. })
  132. checkAreFilesBackFilled()
  133. it('should cleanup the deletedFiles', async function () {
  134. expect(await getDeletedFiles(projectId1)).to.deep.equal([])
  135. expect(await getDeletedFiles(projectId2)).to.deep.equal([])
  136. expect(await getDeletedFiles(projectId5)).to.deep.equal([])
  137. })
  138. })
  139. })