BackFillDummyDocMetaTests.mjs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import { exec } from 'node:child_process'
  2. import { promisify } from 'node:util'
  3. import { expect } from 'chai'
  4. import logger from '@overleaf/logger'
  5. import { filterOutput } from './helpers/settings.mjs'
  6. import { db, ObjectId } from '../../../app/src/infrastructure/mongodb.mjs'
  7. const DUMMY_NAME = 'unknown.tex'
  8. const DUMMY_TIME = new Date('2021-04-12T00:00:00.000Z')
  9. function getObjectIdFromDate(date) {
  10. const seconds = new Date(date).getTime() / 1000
  11. return ObjectId.createFromTime(seconds)
  12. }
  13. describe('BackFillDummyDocMeta', function () {
  14. let docIds
  15. let projectIds
  16. beforeEach('create docs', async function () {
  17. docIds = []
  18. docIds[0] = getObjectIdFromDate('2021-04-01T00:00:00.000Z')
  19. docIds[1] = getObjectIdFromDate('2021-04-02T00:00:00.000Z')
  20. docIds[2] = getObjectIdFromDate('2021-04-11T00:00:00.000Z')
  21. docIds[3] = getObjectIdFromDate('2021-04-12T00:00:00.000Z')
  22. docIds[4] = getObjectIdFromDate('2021-04-13T00:00:00.000Z')
  23. docIds[5] = getObjectIdFromDate('2021-04-14T00:00:00.000Z')
  24. docIds[6] = getObjectIdFromDate('2021-04-15T00:00:00.000Z')
  25. docIds[7] = getObjectIdFromDate('2021-04-16T00:01:00.000Z')
  26. docIds[8] = getObjectIdFromDate('2021-04-16T00:02:00.000Z')
  27. docIds[9] = getObjectIdFromDate('2021-04-16T00:03:00.000Z')
  28. docIds[10] = getObjectIdFromDate('2021-04-16T00:04:00.000Z')
  29. docIds[11] = getObjectIdFromDate('2021-04-16T00:05:00.000Z')
  30. projectIds = []
  31. projectIds[0] = getObjectIdFromDate('2021-04-01T00:00:00.000Z')
  32. projectIds[1] = getObjectIdFromDate('2021-04-02T00:00:00.000Z')
  33. projectIds[2] = getObjectIdFromDate('2021-04-11T00:00:00.000Z')
  34. projectIds[3] = getObjectIdFromDate('2021-04-12T00:00:00.000Z')
  35. projectIds[4] = getObjectIdFromDate('2021-04-13T00:00:00.000Z')
  36. projectIds[5] = getObjectIdFromDate('2021-04-14T00:00:00.000Z')
  37. projectIds[6] = getObjectIdFromDate('2021-04-15T00:00:00.000Z')
  38. projectIds[7] = getObjectIdFromDate('2021-04-16T00:01:00.000Z')
  39. projectIds[8] = getObjectIdFromDate('2021-04-16T00:02:00.000Z')
  40. projectIds[9] = getObjectIdFromDate('2021-04-16T00:03:00.000Z')
  41. // two docs in the same project
  42. projectIds[10] = projectIds[9]
  43. projectIds[11] = projectIds[4]
  44. })
  45. const now = new Date()
  46. beforeEach('insert doc stubs into docs collection', async function () {
  47. // don't look here, just drop duplicates from the list of projectIds :)
  48. await db.projects.insertMany(
  49. Array.from(new Set(projectIds.map(id => id.toString()))).map(_id => ({
  50. _id: new ObjectId(_id),
  51. }))
  52. )
  53. await db.docs.insertMany([
  54. // incomplete, without deletedDocs context
  55. { _id: docIds[0], project_id: projectIds[0], deleted: true },
  56. { _id: docIds[1], project_id: projectIds[1], deleted: true },
  57. { _id: docIds[2], project_id: projectIds[2], deleted: true },
  58. { _id: docIds[3], project_id: projectIds[3], deleted: true },
  59. // incomplete, with deletedDocs context
  60. { _id: docIds[4], project_id: projectIds[4], deleted: true },
  61. // complete
  62. {
  63. _id: docIds[5],
  64. project_id: projectIds[5],
  65. deleted: true,
  66. name: 'foo.tex',
  67. deletedAt: now,
  68. },
  69. // not deleted
  70. { _id: docIds[6], project_id: projectIds[6] },
  71. // multiple in a single batch
  72. { _id: docIds[7], project_id: projectIds[7], deleted: true },
  73. { _id: docIds[8], project_id: projectIds[8], deleted: true },
  74. { _id: docIds[9], project_id: projectIds[9], deleted: true },
  75. // two docs in one project
  76. { _id: docIds[10], project_id: projectIds[10], deleted: true },
  77. { _id: docIds[11], project_id: projectIds[11], deleted: true },
  78. ])
  79. })
  80. beforeEach('insert deleted project context', async function () {
  81. await db.deletedProjects.insertMany([
  82. // projectIds[0] and projectIds[1] have no entry
  83. // hard-deleted
  84. { deleterData: { deletedProjectId: projectIds[2] } },
  85. // soft-deleted, no entry for doc
  86. {
  87. deleterData: { deletedProjectId: projectIds[3] },
  88. project: { deletedDocs: [] },
  89. },
  90. // soft-deleted, has entry for doc
  91. {
  92. deleterData: { deletedProjectId: projectIds[4] },
  93. project: {
  94. deletedDocs: [
  95. { _id: docIds[4], name: 'main.tex', deletedAt: now },
  96. { _id: docIds[11], name: 'main.tex', deletedAt: now },
  97. ],
  98. },
  99. },
  100. ])
  101. })
  102. async function runScript() {
  103. let result
  104. try {
  105. result = await promisify(exec)(
  106. 'cd ../../tools/migrations && east migrate -t saas --force 20210728115327_ce_sp_backfill_dummy_doc_meta'
  107. )
  108. } catch (error) {
  109. // dump details like exit code, stdErr and stdOut
  110. logger.error({ error }, 'script failed')
  111. throw error
  112. }
  113. let { stdout: stdOut } = result
  114. stdOut = stdOut.split('\n').filter(filterOutput)
  115. expect(stdOut.filter(filterOutput)).to.include.members([
  116. `Orphaned deleted doc ${docIds[0]} (no deletedProjects entry)`,
  117. `Orphaned deleted doc ${docIds[1]} (no deletedProjects entry)`,
  118. `Orphaned deleted doc ${docIds[2]} (failed hard deletion)`,
  119. `Missing deletedDoc for ${docIds[3]}`,
  120. `Found deletedDoc for ${docIds[4]}`,
  121. `Found deletedDoc for ${docIds[11]}`,
  122. `Orphaned deleted doc ${docIds[7]} (no deletedProjects entry)`,
  123. `Orphaned deleted doc ${docIds[8]} (no deletedProjects entry)`,
  124. `Orphaned deleted doc ${docIds[9]} (no deletedProjects entry)`,
  125. `Orphaned deleted doc ${docIds[10]} (no deletedProjects entry)`,
  126. ])
  127. }
  128. describe('DRY_RUN=false', function () {
  129. beforeEach('run script', async function () {
  130. await runScript(false)
  131. })
  132. it('should back fill name and deletedAt dates into broken docs', async function () {
  133. const docs = await db.docs.find({}).toArray()
  134. expect(docs).to.deep.equal([
  135. {
  136. _id: docIds[0],
  137. project_id: projectIds[0],
  138. deleted: true,
  139. name: DUMMY_NAME,
  140. deletedAt: DUMMY_TIME,
  141. },
  142. {
  143. _id: docIds[1],
  144. project_id: projectIds[1],
  145. deleted: true,
  146. name: DUMMY_NAME,
  147. deletedAt: DUMMY_TIME,
  148. },
  149. {
  150. _id: docIds[2],
  151. project_id: projectIds[2],
  152. deleted: true,
  153. name: DUMMY_NAME,
  154. deletedAt: DUMMY_TIME,
  155. },
  156. {
  157. _id: docIds[3],
  158. project_id: projectIds[3],
  159. deleted: true,
  160. name: DUMMY_NAME,
  161. deletedAt: DUMMY_TIME,
  162. },
  163. {
  164. _id: docIds[4],
  165. project_id: projectIds[4],
  166. deleted: true,
  167. name: 'main.tex',
  168. deletedAt: now,
  169. },
  170. {
  171. _id: docIds[5],
  172. project_id: projectIds[5],
  173. deleted: true,
  174. name: 'foo.tex',
  175. deletedAt: now,
  176. },
  177. { _id: docIds[6], project_id: projectIds[6] },
  178. {
  179. _id: docIds[7],
  180. project_id: projectIds[7],
  181. deleted: true,
  182. name: DUMMY_NAME,
  183. deletedAt: DUMMY_TIME,
  184. },
  185. {
  186. _id: docIds[8],
  187. project_id: projectIds[8],
  188. deleted: true,
  189. name: DUMMY_NAME,
  190. deletedAt: DUMMY_TIME,
  191. },
  192. {
  193. _id: docIds[9],
  194. project_id: projectIds[9],
  195. deleted: true,
  196. name: DUMMY_NAME,
  197. deletedAt: DUMMY_TIME,
  198. },
  199. {
  200. _id: docIds[10],
  201. project_id: projectIds[10],
  202. deleted: true,
  203. name: DUMMY_NAME,
  204. deletedAt: DUMMY_TIME,
  205. },
  206. {
  207. _id: docIds[11],
  208. project_id: projectIds[11],
  209. deleted: true,
  210. name: 'main.tex',
  211. deletedAt: now,
  212. },
  213. ])
  214. })
  215. })
  216. })