UpdateMergerTests.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. const SandboxedModule = require('sandboxed-module')
  2. const sinon = require('sinon')
  3. const { expect } = require('chai')
  4. const BufferedStream = require('bufferedstream')
  5. const MODULE_PATH =
  6. '../../../../app/src/Features/ThirdPartyDataStore/UpdateMerger.js'
  7. describe('UpdateMerger :', function () {
  8. beforeEach(function () {
  9. this.projectId = 'project_id_here'
  10. this.userId = 'mock-user-id'
  11. this.docPath = this.newDocPath = '/folder/doc.tex'
  12. this.filePath = this.newFilePath = '/folder/file.png'
  13. this.existingDocPath = '/folder/other.tex'
  14. this.existingFilePath = '/folder/fig1.pdf'
  15. this.linkedFileData = { provider: 'url' }
  16. this.existingDocs = [{ path: '/main.tex' }, { path: '/folder/other.tex' }]
  17. this.existingFiles = [{ path: '/figure.pdf' }, { path: '/folder/fig1.pdf' }]
  18. this.fsPath = '/tmp/file/path'
  19. this.fileContents = `\\documentclass{article}
  20. \\usepackage[utf8]{inputenc}
  21. \\title{42}
  22. \\author{Jane Doe}
  23. \\date{June 2011}`
  24. this.docLines = this.fileContents.split('\n')
  25. this.source = 'dropbox'
  26. this.updateRequest = new BufferedStream()
  27. this.fsPromises = {
  28. unlink: sinon.stub().resolves(),
  29. readFile: sinon.stub().withArgs(this.fsPath).resolves(this.fileContents),
  30. }
  31. this.EditorController = {
  32. promises: {
  33. deleteEntityWithPath: sinon.stub().resolves(),
  34. upsertDocWithPath: sinon.stub().resolves(),
  35. upsertFileWithPath: sinon.stub().resolves(),
  36. },
  37. }
  38. this.FileTypeManager = {
  39. promises: {
  40. getType: sinon.stub(),
  41. },
  42. }
  43. this.FileWriter = {
  44. promises: {
  45. writeStreamToDisk: sinon.stub().resolves(this.fsPath),
  46. },
  47. }
  48. this.ProjectEntityHandler = {
  49. promises: {
  50. getAllEntities: sinon.stub().resolves({
  51. docs: this.existingDocs,
  52. files: this.existingFiles,
  53. }),
  54. },
  55. }
  56. this.Settings = { path: { dumpPath: 'dump_here' } }
  57. this.UpdateMerger = SandboxedModule.require(MODULE_PATH, {
  58. requires: {
  59. 'fs/promises': this.fsPromises,
  60. '../Editor/EditorController': this.EditorController,
  61. '../Uploads/FileTypeManager': this.FileTypeManager,
  62. '../../infrastructure/FileWriter': this.FileWriter,
  63. '../Project/ProjectEntityHandler': this.ProjectEntityHandler,
  64. '@overleaf/settings': this.Settings,
  65. },
  66. })
  67. })
  68. describe('mergeUpdate', function () {
  69. describe('doc updates for a new doc', function () {
  70. beforeEach(async function () {
  71. this.FileTypeManager.promises.getType.resolves({
  72. binary: false,
  73. encoding: 'utf-8',
  74. })
  75. await this.UpdateMerger.promises.mergeUpdate(
  76. this.userId,
  77. this.projectId,
  78. this.docPath,
  79. this.updateRequest,
  80. this.source
  81. )
  82. })
  83. it('should look at the file contents', function () {
  84. expect(this.FileTypeManager.promises.getType).to.have.been.called
  85. })
  86. it('should process update as doc', function () {
  87. expect(
  88. this.EditorController.promises.upsertDocWithPath
  89. ).to.have.been.calledWith(
  90. this.projectId,
  91. this.docPath,
  92. this.docLines,
  93. this.source,
  94. this.userId
  95. )
  96. })
  97. it('removes the temp file from disk', function () {
  98. expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
  99. })
  100. })
  101. describe('file updates for a new file ', function () {
  102. beforeEach(async function () {
  103. this.FileTypeManager.promises.getType.resolves({ binary: true })
  104. await this.UpdateMerger.promises.mergeUpdate(
  105. this.userId,
  106. this.projectId,
  107. this.filePath,
  108. this.updateRequest,
  109. this.source
  110. )
  111. })
  112. it('should look at the file contents', function () {
  113. expect(this.FileTypeManager.promises.getType).to.have.been.called
  114. })
  115. it('should process update as file', function () {
  116. expect(
  117. this.EditorController.promises.upsertFileWithPath
  118. ).to.have.been.calledWith(
  119. this.projectId,
  120. this.filePath,
  121. this.fsPath,
  122. null,
  123. this.source,
  124. this.userId
  125. )
  126. })
  127. it('removes the temp file from disk', function () {
  128. expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
  129. })
  130. })
  131. describe('doc updates for an existing doc', function () {
  132. beforeEach(async function () {
  133. this.FileTypeManager.promises.getType.resolves({
  134. binary: false,
  135. encoding: 'utf-8',
  136. })
  137. await this.UpdateMerger.promises.mergeUpdate(
  138. this.userId,
  139. this.projectId,
  140. this.existingDocPath,
  141. this.updateRequest,
  142. this.source
  143. )
  144. })
  145. it('should look at the file contents', function () {
  146. expect(this.FileTypeManager.promises.getType).to.have.been.called
  147. })
  148. it('should process update as doc', function () {
  149. expect(
  150. this.EditorController.promises.upsertDocWithPath
  151. ).to.have.been.calledWith(
  152. this.projectId,
  153. this.existingDocPath,
  154. this.docLines,
  155. this.source,
  156. this.userId
  157. )
  158. })
  159. it('removes the temp file from disk', function () {
  160. expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
  161. })
  162. })
  163. describe('file updates for an existing file', function () {
  164. beforeEach(async function () {
  165. this.FileTypeManager.promises.getType.resolves({ binary: true })
  166. await this.UpdateMerger.promises.mergeUpdate(
  167. this.userId,
  168. this.projectId,
  169. this.existingFilePath,
  170. this.updateRequest,
  171. this.source
  172. )
  173. })
  174. it('should look at the file contents', function () {
  175. expect(this.FileTypeManager.promises.getType).to.have.been.called
  176. })
  177. it('should process update as file', function () {
  178. expect(
  179. this.EditorController.promises.upsertFileWithPath
  180. ).to.have.been.calledWith(
  181. this.projectId,
  182. this.existingFilePath,
  183. this.fsPath,
  184. null,
  185. this.source,
  186. this.userId
  187. )
  188. })
  189. it('removes the temp file from disk', function () {
  190. expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
  191. })
  192. })
  193. })
  194. describe('file updates for an existing doc', function () {
  195. beforeEach(async function () {
  196. this.FileTypeManager.promises.getType.resolves({ binary: true })
  197. await this.UpdateMerger.promises.mergeUpdate(
  198. this.userId,
  199. this.projectId,
  200. this.existingDocPath,
  201. this.updateRequest,
  202. this.source
  203. )
  204. })
  205. it('should look at the file contents', function () {
  206. expect(this.FileTypeManager.promises.getType).to.have.been.called
  207. })
  208. it('should delete the existing doc', function () {
  209. expect(
  210. this.EditorController.promises.deleteEntityWithPath
  211. ).to.have.been.calledWith(
  212. this.projectId,
  213. this.existingDocPath,
  214. this.source,
  215. this.userId
  216. )
  217. })
  218. it('should process update as file', function () {
  219. expect(
  220. this.EditorController.promises.upsertFileWithPath
  221. ).to.have.been.calledWith(
  222. this.projectId,
  223. this.existingDocPath,
  224. this.fsPath,
  225. null,
  226. this.source,
  227. this.userId
  228. )
  229. })
  230. it('removes the temp file from disk', function () {
  231. expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
  232. })
  233. })
  234. describe('doc updates for an existing file', function () {
  235. beforeEach(async function () {
  236. this.FileTypeManager.promises.getType.resolves({ binary: true })
  237. await this.UpdateMerger.promises.mergeUpdate(
  238. this.userId,
  239. this.projectId,
  240. this.existingFilePath,
  241. this.updateRequest,
  242. this.source
  243. )
  244. })
  245. it('should look at the file contents', function () {
  246. expect(this.FileTypeManager.promises.getType).to.have.been.called
  247. })
  248. it('should not delete the existing file', function () {
  249. expect(this.EditorController.promises.deleteEntityWithPath).to.not.have
  250. .been.called
  251. })
  252. it('should process update as file', function () {
  253. expect(
  254. this.EditorController.promises.upsertFileWithPath
  255. ).to.have.been.calledWith(
  256. this.projectId,
  257. this.existingFilePath,
  258. this.fsPath,
  259. null,
  260. this.source,
  261. this.userId
  262. )
  263. })
  264. it('removes the temp file from disk', function () {
  265. expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
  266. })
  267. })
  268. describe('deleteUpdate', function () {
  269. beforeEach(async function () {
  270. await this.UpdateMerger.promises.deleteUpdate(
  271. this.userId,
  272. this.projectId,
  273. this.docPath,
  274. this.source
  275. )
  276. })
  277. it('should delete the entity in the editor controller', function () {
  278. expect(
  279. this.EditorController.promises.deleteEntityWithPath
  280. ).to.have.been.calledWith(
  281. this.projectId,
  282. this.docPath,
  283. this.source,
  284. this.userId
  285. )
  286. })
  287. })
  288. })