BackFillDeletedFilesTests.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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, stdout: stdOut } = result
  80. expect(stdOut).to.include(projectId1.toString())
  81. expect(stdOut).to.include(projectId2.toString())
  82. expect(stdErr).to.include(`Completed batch ending ${projectId5}`)
  83. }
  84. function checkAreFilesBackFilled() {
  85. it('should back fill file and set projectId', async function () {
  86. const docs = await db.deletedFiles
  87. .find({}, { sort: { _id: 1 } })
  88. .toArray()
  89. expect(docs).to.deep.equal([
  90. { _id: fileId1, projectId: projectId1, ...otherFileDetails },
  91. { _id: fileId2, projectId: projectId1, ...otherFileDetails },
  92. { _id: fileId3, projectId: projectId2, ...otherFileDetails },
  93. { _id: fileId4, projectId: projectId5, ...otherFileDetails },
  94. ])
  95. })
  96. }
  97. describe('back fill only', function () {
  98. beforeEach('run script', runScript)
  99. checkAreFilesBackFilled()
  100. it('should leave the deletedFiles as is', async function () {
  101. expect(await getDeletedFiles(projectId1)).to.deep.equal(deletedFiles1)
  102. expect(await getDeletedFiles(projectId2)).to.deep.equal(deletedFiles2)
  103. expect(await getDeletedFiles(projectId5)).to.deep.equal(deletedFiles3)
  104. })
  105. })
  106. describe('back fill and cleanup', function () {
  107. beforeEach('run script with cleanup flag', async function () {
  108. await runScript(['--perform-cleanup'])
  109. })
  110. checkAreFilesBackFilled()
  111. it('should cleanup the deletedFiles', async function () {
  112. expect(await getDeletedFiles(projectId1)).to.deep.equal([])
  113. expect(await getDeletedFiles(projectId2)).to.deep.equal([])
  114. expect(await getDeletedFiles(projectId5)).to.deep.equal([])
  115. })
  116. })
  117. describe('fix partial inserts and cleanup', function () {
  118. beforeEach('simulate one missing insert', async function () {
  119. await setDeletedFiles(projectId1, [deletedFiles1[0]])
  120. })
  121. beforeEach('run script with cleanup flag', async function () {
  122. await runScript(['--perform-cleanup'])
  123. })
  124. beforeEach('add case for one missing file', async function () {
  125. await setDeletedFiles(projectId1, deletedFiles1)
  126. })
  127. beforeEach('add cases for no more files to insert', async function () {
  128. await setDeletedFiles(projectId2, deletedFiles2)
  129. await setDeletedFiles(projectId5, deletedFiles3)
  130. })
  131. beforeEach('fixing partial insert and cleanup', async function () {
  132. await runScript(['--fix-partial-inserts', '--perform-cleanup'])
  133. })
  134. checkAreFilesBackFilled()
  135. it('should cleanup the deletedFiles', async function () {
  136. expect(await getDeletedFiles(projectId1)).to.deep.equal([])
  137. expect(await getDeletedFiles(projectId2)).to.deep.equal([])
  138. expect(await getDeletedFiles(projectId5)).to.deep.equal([])
  139. })
  140. })
  141. })