ProjectUploadManagerTests.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. const sinon = require('sinon')
  13. const chai = require('chai')
  14. const should = chai.should()
  15. const modulePath =
  16. '../../../../app/src/Features/Uploads/ProjectUploadManager.js'
  17. const SandboxedModule = require('sandboxed-module')
  18. const promiseStub = val => new Promise(resolve => resolve(val))
  19. const failedPromiseStub = err => new Promise((resolve, reject) => reject(err))
  20. describe('ProjectUploadManager', function() {
  21. beforeEach(function() {
  22. this.project_id = 'project-id-123'
  23. this.folder_id = 'folder-id-123'
  24. this.owner_id = 'owner-id-123'
  25. this.callback = sinon.stub()
  26. this.source = '/path/to/zip/file-name.zip'
  27. this.destination = '/path/to/zile/file-extracted'
  28. this.root_folder_id = this.folder_id
  29. this.owner_id = 'owner-id-123'
  30. this.name = 'Project name'
  31. this.othername = 'Other name'
  32. this.project = {
  33. _id: this.project_id,
  34. rootFolder: [{ _id: this.root_folder_id }]
  35. }
  36. this.ProjectUploadManager = SandboxedModule.require(modulePath, {
  37. globals: {
  38. console: console
  39. },
  40. requires: {
  41. './FileSystemImportManager': (this.FileSystemImportManager = {}),
  42. './ArchiveManager': (this.ArchiveManager = { promises: {} }),
  43. '../Project/ProjectCreationHandler': (this.ProjectCreationHandler = {
  44. promises: {}
  45. }),
  46. '../Project/ProjectRootDocManager': (this.ProjectRootDocManager = {
  47. promises: {}
  48. }),
  49. '../Project/ProjectDetailsHandler': (this.ProjectDetailsHandler = {
  50. promises: {}
  51. }),
  52. '../Project/ProjectDeleter': (this.ProjectDeleter = {
  53. promises: {}
  54. }),
  55. '../Documents/DocumentHelper': (this.DocumentHelper = {}),
  56. rimraf: (this.rimraf = sinon.stub().callsArg(1))
  57. }
  58. })
  59. this.ArchiveManager.extractZipArchive = sinon.stub().callsArg(2)
  60. this.ArchiveManager.promises.extractZipArchive = sinon
  61. .stub()
  62. .returns(promiseStub())
  63. this.ArchiveManager.findTopLevelDirectory = sinon
  64. .stub()
  65. .callsArgWith(
  66. 1,
  67. null,
  68. (this.topLevelDestination = '/path/to/zip/file-extracted/nested')
  69. )
  70. this.ProjectCreationHandler.promises.createBlankProject = sinon
  71. .stub()
  72. .returns(promiseStub(this.project))
  73. this.ProjectRootDocManager.promises.setRootDocAutomatically = sinon
  74. .stub()
  75. .returns(promiseStub())
  76. this.FileSystemImportManager.addFolderContents = sinon.stub().callsArg(5)
  77. this.ProjectRootDocManager.promises.findRootDocFileFromDirectory = sinon
  78. .stub()
  79. .returns(promiseStub({ path: 'main.tex', content: this.othername }))
  80. this.ProjectRootDocManager.promises.setRootDocFromName = sinon
  81. .stub()
  82. .returns(promiseStub())
  83. this.DocumentHelper.getTitleFromTexContent = sinon
  84. .stub()
  85. .returns(this.othername)
  86. return (this.ProjectDetailsHandler.fixProjectName = sinon
  87. .stub()
  88. .returnsArg(0))
  89. })
  90. describe('createProjectFromZipArchive', function() {
  91. describe('when the title can be read from the root document', function() {
  92. beforeEach(function(done) {
  93. this.ProjectUploadManager._getDestinationDirectory = sinon
  94. .stub()
  95. .returns(this.destination)
  96. this.ProjectDetailsHandler.promises.generateUniqueName = sinon
  97. .stub()
  98. .returns(promiseStub(this.othername))
  99. return this.ProjectUploadManager.createProjectFromZipArchive(
  100. this.owner_id,
  101. this.name,
  102. this.source,
  103. (err, project) => {
  104. this.callback(err, project)
  105. return done()
  106. }
  107. )
  108. })
  109. it('should set up the directory to extract the archive to', function() {
  110. this.ProjectUploadManager._getDestinationDirectory
  111. .calledWith(this.source)
  112. .should.equal(true)
  113. })
  114. it('should extract the archive', function() {
  115. this.ArchiveManager.promises.extractZipArchive
  116. .calledWith(this.source, this.destination)
  117. .should.equal(true)
  118. })
  119. it('should find the top level directory', function() {
  120. this.ArchiveManager.findTopLevelDirectory
  121. .calledWith(this.destination)
  122. .should.equal(true)
  123. })
  124. it('should insert the extracted archive into the folder', function() {
  125. this.FileSystemImportManager.addFolderContents
  126. .calledWith(
  127. this.owner_id,
  128. this.project_id,
  129. this.folder_id,
  130. this.topLevelDestination,
  131. false
  132. )
  133. .should.equal(true)
  134. })
  135. it('should create a project owned by the owner_id', function() {
  136. this.ProjectCreationHandler.promises.createBlankProject
  137. .calledWith(this.owner_id)
  138. .should.equal(true)
  139. })
  140. it('should create a project with the correct name', function() {
  141. this.ProjectCreationHandler.promises.createBlankProject
  142. .calledWith(sinon.match.any, this.othername)
  143. .should.equal(true)
  144. })
  145. it('should read the title from the tex contents', function() {
  146. this.DocumentHelper.getTitleFromTexContent.called.should.equal(true)
  147. })
  148. it('should set the root document', function() {
  149. this.ProjectRootDocManager.promises.setRootDocFromName
  150. .calledWith(this.project_id, 'main.tex')
  151. .should.equal(true)
  152. })
  153. it('should call the callback', function() {
  154. this.callback
  155. .calledWith(sinon.match.falsy, this.project)
  156. .should.equal(true)
  157. })
  158. it('should ensure the name is valid', function() {
  159. return this.ProjectDetailsHandler.fixProjectName.called.should.equal(
  160. true
  161. )
  162. })
  163. })
  164. describe("when the root document can't be determined", function() {
  165. beforeEach(function(done) {
  166. this.ProjectRootDocManager.promises.findRootDocFileFromDirectory = sinon
  167. .stub()
  168. .returns(promiseStub())
  169. this.ProjectUploadManager._getDestinationDirectory = sinon
  170. .stub()
  171. .returns(this.destination)
  172. this.ProjectDetailsHandler.promises.generateUniqueName = sinon
  173. .stub()
  174. .returns(promiseStub(this.name))
  175. return this.ProjectUploadManager.createProjectFromZipArchive(
  176. this.owner_id,
  177. this.name,
  178. this.source,
  179. (err, project) => {
  180. this.callback(err, project)
  181. return done()
  182. }
  183. )
  184. })
  185. it('should not try to set the root doc', function() {
  186. this.ProjectRootDocManager.promises.setRootDocFromName.called.should.equal(
  187. false
  188. )
  189. })
  190. })
  191. })
  192. describe('createProjectFromZipArchiveWithName', function() {
  193. beforeEach(function(done) {
  194. this.ProjectDetailsHandler.promises.generateUniqueName = sinon
  195. .stub()
  196. .returns(promiseStub(this.name))
  197. this.ProjectCreationHandler.promises.createBlankProject = sinon
  198. .stub()
  199. .returns(promiseStub(this.project))
  200. this.ProjectUploadManager.promises.insertZipArchiveIntoFolder = sinon
  201. .stub()
  202. .returns(promiseStub())
  203. this.ProjectUploadManager.createProjectFromZipArchiveWithName(
  204. this.owner_id,
  205. this.name,
  206. this.source,
  207. (err, project) => {
  208. this.callback(err, project)
  209. return done()
  210. }
  211. )
  212. })
  213. it('should create a project owned by the owner_id', function() {
  214. this.ProjectCreationHandler.promises.createBlankProject
  215. .calledWith(this.owner_id)
  216. .should.equal(true)
  217. })
  218. it('should create a project with the correct name', function() {
  219. this.ProjectCreationHandler.promises.createBlankProject
  220. .calledWith(sinon.match.any, this.name)
  221. .should.equal(true)
  222. })
  223. it('should insert the zip file contents into the root folder', function() {
  224. this.ProjectUploadManager.promises.insertZipArchiveIntoFolder
  225. .calledWith(
  226. this.owner_id,
  227. this.project_id,
  228. this.root_folder_id,
  229. this.source
  230. )
  231. .should.equal(true)
  232. })
  233. it('should automatically set the root doc', function() {
  234. this.ProjectRootDocManager.promises.setRootDocAutomatically
  235. .calledWith(this.project_id)
  236. .should.equal(true)
  237. })
  238. it('should call the callback', function() {
  239. return this.callback
  240. .calledWith(sinon.match.falsy, this.project)
  241. .should.equal(true)
  242. })
  243. describe('when inserting the zip file contents into the root folder fails', function() {
  244. beforeEach(function(done) {
  245. this.callback = sinon.stub()
  246. this.ProjectUploadManager.promises.insertZipArchiveIntoFolder = sinon
  247. .stub()
  248. .returns(failedPromiseStub('insert-zip-error'))
  249. this.ProjectDeleter.promises.deleteProject = sinon
  250. .stub()
  251. .returns(promiseStub())
  252. this.ProjectUploadManager.createProjectFromZipArchiveWithName(
  253. this.owner_id,
  254. this.name,
  255. this.source,
  256. (err, project) => {
  257. this.callback(err, project)
  258. return done()
  259. }
  260. )
  261. })
  262. it('should pass an error to the callback', function() {
  263. return this.callback
  264. .calledWith('insert-zip-error', sinon.match.falsy)
  265. .should.equal(true)
  266. })
  267. it('should cleanup the blank project created', function() {
  268. return this.ProjectDeleter.promises.deleteProject
  269. .calledWith(this.project_id)
  270. .should.equal(true)
  271. })
  272. })
  273. describe('when setting automatically the root doc fails', function() {
  274. beforeEach(function(done) {
  275. this.callback = sinon.stub()
  276. this.ProjectRootDocManager.promises.setRootDocAutomatically = sinon
  277. .stub()
  278. .returns(failedPromiseStub('set-root-auto-error'))
  279. this.ProjectDeleter.promises.deleteProject = sinon
  280. .stub()
  281. .returns(promiseStub())
  282. this.ProjectUploadManager.createProjectFromZipArchiveWithName(
  283. this.owner_id,
  284. this.name,
  285. this.source,
  286. (err, project) => {
  287. this.callback(err, project)
  288. return done()
  289. }
  290. )
  291. })
  292. it('should pass an error to the callback', function() {
  293. return this.callback
  294. .calledWith('set-root-auto-error', sinon.match.falsy)
  295. .should.equal(true)
  296. })
  297. it('should cleanup the blank project created', function() {
  298. return this.ProjectDeleter.promises.deleteProject
  299. .calledWith(this.project_id)
  300. .should.equal(true)
  301. })
  302. })
  303. })
  304. describe('insertZipArchiveIntoFolder', function() {
  305. beforeEach(function(done) {
  306. this.ProjectUploadManager._getDestinationDirectory = sinon
  307. .stub()
  308. .returns(this.destination)
  309. return this.ProjectUploadManager.insertZipArchiveIntoFolder(
  310. this.owner_id,
  311. this.project_id,
  312. this.folder_id,
  313. this.source,
  314. err => {
  315. this.callback(err)
  316. return done()
  317. }
  318. )
  319. })
  320. it('should set up the directory to extract the archive to', function() {
  321. this.ProjectUploadManager._getDestinationDirectory
  322. .calledWith(this.source)
  323. .should.equal(true)
  324. })
  325. it('should extract the archive', function() {
  326. this.ArchiveManager.extractZipArchive
  327. .calledWith(this.source, this.destination)
  328. .should.equal(true)
  329. })
  330. it('should find the top level directory', function() {
  331. this.ArchiveManager.findTopLevelDirectory
  332. .calledWith(this.destination)
  333. .should.equal(true)
  334. })
  335. it('should insert the extracted archive into the folder', function() {
  336. this.FileSystemImportManager.addFolderContents
  337. .calledWith(
  338. this.owner_id,
  339. this.project_id,
  340. this.folder_id,
  341. this.topLevelDestination,
  342. false
  343. )
  344. .should.equal(true)
  345. })
  346. it('should return the callback', function() {
  347. this.callback.called.should.equal(true)
  348. })
  349. it('should remove the desintation directory afterwards', function() {
  350. this.rimraf.calledWith(this.destination).should.equal(true)
  351. })
  352. })
  353. describe('_getDestinationDirectory', () =>
  354. it('should return the path with the time appended', function() {
  355. const date = Date.now()
  356. sinon.stub(Date, 'now', () => date)
  357. this.ProjectUploadManager._getDestinationDirectory(
  358. '/path/to/zip/file.zip'
  359. ).should.equal(`/path/to/zip/file-${date}`)
  360. Date.now.restore()
  361. }))
  362. })