ProjectZipStreamManagerTests.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /* eslint-disable
  2. camelcase,
  3. max-len,
  4. no-return-assign,
  5. no-unused-vars,
  6. one-var,
  7. */
  8. // TODO: This file was created by bulk-decaffeinate.
  9. // Fix any style issues and re-enable lint.
  10. /*
  11. * decaffeinate suggestions:
  12. * DS101: Remove unnecessary use of Array.from
  13. * DS102: Remove unnecessary code created because of implicit returns
  14. * DS201: Simplify complex destructure assignments
  15. * DS205: Consider reworking code to avoid use of IIFEs
  16. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  17. */
  18. const sinon = require('sinon')
  19. const chai = require('chai')
  20. const should = chai.should()
  21. const { expect } = chai
  22. const modulePath =
  23. '../../../../app/src/Features/Downloads/ProjectZipStreamManager.js'
  24. const SandboxedModule = require('sandboxed-module')
  25. const { EventEmitter } = require('events')
  26. describe('ProjectZipStreamManager', function() {
  27. beforeEach(function() {
  28. this.project_id = 'project-id-123'
  29. this.callback = sinon.stub()
  30. this.archive = {
  31. on() {},
  32. append: sinon.stub()
  33. }
  34. return (this.ProjectZipStreamManager = SandboxedModule.require(modulePath, {
  35. globals: {
  36. console: console
  37. },
  38. requires: {
  39. archiver: (this.archiver = sinon.stub().returns(this.archive)),
  40. 'logger-sharelatex': (this.logger = {
  41. error: sinon.stub(),
  42. log: sinon.stub()
  43. }),
  44. '../Project/ProjectEntityHandler': (this.ProjectEntityHandler = {}),
  45. '../FileStore/FileStoreHandler': (this.FileStoreHandler = {}),
  46. '../Project/ProjectGetter': (this.ProjectGetter = {})
  47. }
  48. }))
  49. })
  50. describe('createZipStreamForMultipleProjects', () =>
  51. describe('successfully', function() {
  52. beforeEach(function(done) {
  53. this.project_ids = ['project-1', 'project-2']
  54. this.zip_streams = {
  55. 'project-1': new EventEmitter(),
  56. 'project-2': new EventEmitter()
  57. }
  58. this.project_names = {
  59. 'project-1': 'Project One Name',
  60. 'project-2': 'Project Two Name'
  61. }
  62. this.ProjectZipStreamManager.createZipStreamForProject = (
  63. project_id,
  64. callback
  65. ) => {
  66. callback(null, this.zip_streams[project_id])
  67. setTimeout(() => {
  68. return this.zip_streams[project_id].emit('end')
  69. })
  70. return 0
  71. }
  72. sinon.spy(this.ProjectZipStreamManager, 'createZipStreamForProject')
  73. this.ProjectGetter.getProject = (project_id, fields, callback) => {
  74. return callback(null, { name: this.project_names[project_id] })
  75. }
  76. sinon.spy(this.ProjectGetter, 'getProject')
  77. this.ProjectZipStreamManager.createZipStreamForMultipleProjects(
  78. this.project_ids,
  79. (...args) => {
  80. return this.callback(...Array.from(args || []))
  81. }
  82. )
  83. return (this.archive.finalize = () => done())
  84. })
  85. it('should create a zip archive', function() {
  86. return this.archiver.calledWith('zip').should.equal(true)
  87. })
  88. it('should return a stream before any processing is done', function() {
  89. this.callback
  90. .calledWith(sinon.match.falsy, this.archive)
  91. .should.equal(true)
  92. return this.callback
  93. .calledBefore(this.ProjectZipStreamManager.createZipStreamForProject)
  94. .should.equal(true)
  95. })
  96. it('should get a zip stream for all of the projects', function() {
  97. return Array.from(this.project_ids).map(project_id =>
  98. this.ProjectZipStreamManager.createZipStreamForProject
  99. .calledWith(project_id)
  100. .should.equal(true)
  101. )
  102. })
  103. it('should get the names of each project', function() {
  104. return Array.from(this.project_ids).map(project_id =>
  105. this.ProjectGetter.getProject
  106. .calledWith(project_id, { name: true })
  107. .should.equal(true)
  108. )
  109. })
  110. it('should add all of the projects to the zip', function() {
  111. return Array.from(this.project_ids).map(project_id =>
  112. this.archive.append
  113. .calledWith(this.zip_streams[project_id], {
  114. name: this.project_names[project_id] + '.zip'
  115. })
  116. .should.equal(true)
  117. )
  118. })
  119. }))
  120. describe('createZipStreamForProject', function() {
  121. describe('successfully', function() {
  122. beforeEach(function() {
  123. this.ProjectZipStreamManager.addAllDocsToArchive = sinon
  124. .stub()
  125. .callsArg(2)
  126. this.ProjectZipStreamManager.addAllFilesToArchive = sinon
  127. .stub()
  128. .callsArg(2)
  129. this.archive.finalize = sinon.stub()
  130. return this.ProjectZipStreamManager.createZipStreamForProject(
  131. this.project_id,
  132. this.callback
  133. )
  134. })
  135. it('should create a zip archive', function() {
  136. return this.archiver.calledWith('zip').should.equal(true)
  137. })
  138. it('should return a stream before any processing is done', function() {
  139. this.callback
  140. .calledWith(sinon.match.falsy, this.archive)
  141. .should.equal(true)
  142. this.callback
  143. .calledBefore(this.ProjectZipStreamManager.addAllDocsToArchive)
  144. .should.equal(true)
  145. return this.callback
  146. .calledBefore(this.ProjectZipStreamManager.addAllFilesToArchive)
  147. .should.equal(true)
  148. })
  149. it('should add all of the project docs to the zip', function() {
  150. return this.ProjectZipStreamManager.addAllDocsToArchive
  151. .calledWith(this.project_id, this.archive)
  152. .should.equal(true)
  153. })
  154. it('should add all of the project files to the zip', function() {
  155. return this.ProjectZipStreamManager.addAllFilesToArchive
  156. .calledWith(this.project_id, this.archive)
  157. .should.equal(true)
  158. })
  159. it('should finalise the stream', function() {
  160. return this.archive.finalize.called.should.equal(true)
  161. })
  162. })
  163. describe('with an error adding docs', function() {
  164. beforeEach(function() {
  165. this.ProjectZipStreamManager.addAllDocsToArchive = sinon
  166. .stub()
  167. .callsArgWith(2, new Error('something went wrong'))
  168. this.ProjectZipStreamManager.addAllFilesToArchive = sinon
  169. .stub()
  170. .callsArg(2)
  171. this.archive.finalize = sinon.stub()
  172. return this.ProjectZipStreamManager.createZipStreamForProject(
  173. this.project_id,
  174. this.callback
  175. )
  176. })
  177. it('should log out an error', function() {
  178. return this.logger.error
  179. .calledWith(sinon.match.any, 'error adding docs to zip stream')
  180. .should.equal(true)
  181. })
  182. it('should continue with the process', function() {
  183. this.ProjectZipStreamManager.addAllDocsToArchive.called.should.equal(
  184. true
  185. )
  186. this.ProjectZipStreamManager.addAllFilesToArchive.called.should.equal(
  187. true
  188. )
  189. return this.archive.finalize.called.should.equal(true)
  190. })
  191. })
  192. describe('with an error adding files', function() {
  193. beforeEach(function() {
  194. this.ProjectZipStreamManager.addAllDocsToArchive = sinon
  195. .stub()
  196. .callsArg(2)
  197. this.ProjectZipStreamManager.addAllFilesToArchive = sinon
  198. .stub()
  199. .callsArgWith(2, new Error('something went wrong'))
  200. this.archive.finalize = sinon.stub()
  201. return this.ProjectZipStreamManager.createZipStreamForProject(
  202. this.project_id,
  203. this.callback
  204. )
  205. })
  206. it('should log out an error', function() {
  207. return this.logger.error
  208. .calledWith(sinon.match.any, 'error adding files to zip stream')
  209. .should.equal(true)
  210. })
  211. it('should continue with the process', function() {
  212. this.ProjectZipStreamManager.addAllDocsToArchive.called.should.equal(
  213. true
  214. )
  215. this.ProjectZipStreamManager.addAllFilesToArchive.called.should.equal(
  216. true
  217. )
  218. return this.archive.finalize.called.should.equal(true)
  219. })
  220. })
  221. })
  222. describe('addAllDocsToArchive', function() {
  223. beforeEach(function(done) {
  224. this.docs = {
  225. '/main.tex': {
  226. lines: [
  227. '\\documentclass{article}',
  228. '\\begin{document}',
  229. 'Hello world',
  230. '\\end{document}'
  231. ]
  232. },
  233. '/chapters/chapter1.tex': {
  234. lines: ['chapter1', 'content']
  235. }
  236. }
  237. this.ProjectEntityHandler.getAllDocs = sinon
  238. .stub()
  239. .callsArgWith(1, null, this.docs)
  240. return this.ProjectZipStreamManager.addAllDocsToArchive(
  241. this.project_id,
  242. this.archive,
  243. error => {
  244. this.callback(error)
  245. return done()
  246. }
  247. )
  248. })
  249. it('should get the docs for the project', function() {
  250. return this.ProjectEntityHandler.getAllDocs
  251. .calledWith(this.project_id)
  252. .should.equal(true)
  253. })
  254. it('should add each doc to the archive', function() {
  255. return (() => {
  256. const result = []
  257. for (let path in this.docs) {
  258. const doc = this.docs[path]
  259. path = path.slice(1) // remove "/"
  260. result.push(
  261. this.archive.append
  262. .calledWith(doc.lines.join('\n'), { name: path })
  263. .should.equal(true)
  264. )
  265. }
  266. return result
  267. })()
  268. })
  269. })
  270. describe('addAllFilesToArchive', function() {
  271. beforeEach(function() {
  272. this.files = {
  273. '/image.png': {
  274. _id: 'file-id-1'
  275. },
  276. '/folder/picture.png': {
  277. _id: 'file-id-2'
  278. }
  279. }
  280. this.streams = {
  281. 'file-id-1': new EventEmitter(),
  282. 'file-id-2': new EventEmitter()
  283. }
  284. this.ProjectEntityHandler.getAllFiles = sinon
  285. .stub()
  286. .callsArgWith(1, null, this.files)
  287. this.FileStoreHandler.getFileStream = (project_id, file_id, ...rest) => {
  288. const obj = rest[0],
  289. callback = rest[1]
  290. return callback(null, this.streams[file_id])
  291. }
  292. sinon.spy(this.FileStoreHandler, 'getFileStream')
  293. this.ProjectZipStreamManager.addAllFilesToArchive(
  294. this.project_id,
  295. this.archive,
  296. this.callback
  297. )
  298. return (() => {
  299. const result = []
  300. for (let path in this.streams) {
  301. const stream = this.streams[path]
  302. result.push(stream.emit('end'))
  303. }
  304. return result
  305. })()
  306. })
  307. it('should get the files for the project', function() {
  308. return this.ProjectEntityHandler.getAllFiles
  309. .calledWith(this.project_id)
  310. .should.equal(true)
  311. })
  312. it('should get a stream for each file', function() {
  313. return (() => {
  314. const result = []
  315. for (let path in this.files) {
  316. const file = this.files[path]
  317. result.push(
  318. this.FileStoreHandler.getFileStream
  319. .calledWith(this.project_id, file._id)
  320. .should.equal(true)
  321. )
  322. }
  323. return result
  324. })()
  325. })
  326. it('should add each file to the archive', function() {
  327. return (() => {
  328. const result = []
  329. for (let path in this.files) {
  330. const file = this.files[path]
  331. path = path.slice(1) // remove "/"
  332. result.push(
  333. this.archive.append
  334. .calledWith(this.streams[file._id], { name: path })
  335. .should.equal(true)
  336. )
  337. }
  338. return result
  339. })()
  340. })
  341. })
  342. })