ProjectDuplicatorTests.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /* eslint-disable
  2. handle-callback-err,
  3. max-len,
  4. no-return-assign,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const sinon = require('sinon')
  15. const chai = require('chai').should()
  16. const modulePath = '../../../../app/src/Features/Project/ProjectDuplicator.js'
  17. const SandboxedModule = require('sandboxed-module')
  18. describe('ProjectDuplicator', function() {
  19. beforeEach(function() {
  20. this.level2folder = {
  21. name: 'level2folderName',
  22. _id: 'level2folderId',
  23. docs: [
  24. (this.doc2 = { _id: 'doc2_id', name: 'level2folderDocName' }),
  25. undefined
  26. ],
  27. folders: [],
  28. fileRefs: [{ name: 'file2', _id: 'file2' }]
  29. }
  30. this.level1folder = {
  31. name: 'level1folder',
  32. _id: 'level1folderId',
  33. docs: [(this.doc1 = { _id: 'doc1_id', name: 'level1folderDocName' })],
  34. folders: [this.level2folder],
  35. fileRefs: [{ name: 'file1', _id: 'file1' }, null] // the null is intentional to test null docs/files
  36. }
  37. this.rootFolder = {
  38. name: 'rootFolder',
  39. _id: 'rootFolderId',
  40. docs: [(this.doc0 = { _id: 'doc0_id', name: 'rootDocHere' })],
  41. folders: [this.level1folder, {}],
  42. fileRefs: [{ name: 'file0', _id: 'file0' }]
  43. }
  44. this.project = {
  45. _id: (this.old_project_id = 'this_is_the_old_project_id'),
  46. rootDoc_id: 'rootDoc_id',
  47. rootFolder: [this.rootFolder],
  48. compiler: 'this_is_a_Compiler'
  49. }
  50. this.docContents = [
  51. {
  52. _id: this.doc0._id,
  53. lines: (this.doc0_lines = ['zero'])
  54. },
  55. {
  56. _id: this.doc1._id,
  57. lines: (this.doc1_lines = ['one'])
  58. },
  59. {
  60. _id: this.doc2._id,
  61. lines: (this.doc2_lines = ['two'])
  62. }
  63. ]
  64. this.DocstoreManager = {
  65. getAllDocs: sinon.stub().callsArgWith(1, null, this.docContents)
  66. }
  67. this.owner = { _id: 'this_is_the_owner' }
  68. this.stubbedNewProject = {
  69. _id: (this.new_project_id = 'new_project_id'),
  70. readOnly_refs: [],
  71. collaberator_refs: [],
  72. rootFolder: [{ _id: 'new_root_folder_id' }]
  73. }
  74. this.foundRootDoc = { _id: 'rootDocId', name: 'rootDocHere' }
  75. this.creationHandler = {
  76. createBlankProject: sinon
  77. .stub()
  78. .callsArgWith(2, null, this.stubbedNewProject)
  79. }
  80. this.newFolder = { _id: 'newFolderId' }
  81. this.locator = {
  82. findRootDoc: sinon.stub().callsArgWith(1, null, this.foundRootDoc, {})
  83. }
  84. this.projectOptionsHandler = { setCompiler: sinon.stub().callsArg(2) }
  85. this.ProjectEntityUpdateHandler = {
  86. addDoc: sinon.stub().callsArgWith(5, null, { name: 'somDoc' }),
  87. copyFileFromExistingProjectWithProject: sinon.stub(),
  88. setRootDoc: sinon.stub(),
  89. addFolder: sinon.stub().callsArgWith(3, null, this.newFolder)
  90. }
  91. this.ProjectEntityUpdateHandler.copyFileFromExistingProjectWithProject
  92. .withArgs(
  93. sinon.match.any,
  94. sinon.match.any,
  95. sinon.match.any,
  96. sinon.match.any,
  97. 'BROKEN-FILE',
  98. sinon.match.any,
  99. sinon.match.any
  100. )
  101. .callsArgWith(6, new Error('failed'))
  102. this.ProjectEntityUpdateHandler.copyFileFromExistingProjectWithProject
  103. .withArgs(
  104. sinon.match.any,
  105. sinon.match.any,
  106. sinon.match.any,
  107. sinon.match.any,
  108. sinon.match.object,
  109. sinon.match.any
  110. )
  111. .callsArg(6)
  112. this.ProjectEntityUpdateHandler.copyFileFromExistingProjectWithProject
  113. .withArgs(
  114. sinon.match.any,
  115. sinon.match.any,
  116. sinon.match.any,
  117. sinon.match.any,
  118. null,
  119. sinon.match.any
  120. )
  121. .callsArg(6)
  122. this.DocumentUpdaterHandler = {
  123. flushProjectToMongo: sinon.stub().callsArg(1)
  124. }
  125. this.Project = {
  126. findById: sinon.stub().callsArgWith(1, null, this.project)
  127. }
  128. this.ProjectGetter = { getProject: sinon.stub() }
  129. this.ProjectGetter.getProject
  130. .withArgs(this.old_project_id, sinon.match.any)
  131. .callsArgWith(2, null, this.project)
  132. this.ProjectGetter.getProject
  133. .withArgs(this.new_project_id, sinon.match.any)
  134. .callsArgWith(2, null, this.stubbedNewProject)
  135. this.ProjectDeleter = { deleteProject: sinon.stub().callsArgWith(1, null) }
  136. return (this.duplicator = SandboxedModule.require(modulePath, {
  137. globals: {
  138. console: console
  139. },
  140. requires: {
  141. '../../models/Project': { Project: this.Project },
  142. '../DocumentUpdater/DocumentUpdaterHandler': this
  143. .DocumentUpdaterHandler,
  144. './ProjectCreationHandler': this.creationHandler,
  145. './ProjectEntityUpdateHandler': this.ProjectEntityUpdateHandler,
  146. './ProjectLocator': this.locator,
  147. './ProjectDeleter': this.ProjectDeleter,
  148. './ProjectOptionsHandler': this.projectOptionsHandler,
  149. '../Docstore/DocstoreManager': this.DocstoreManager,
  150. './ProjectGetter': this.ProjectGetter,
  151. 'logger-sharelatex': {
  152. log() {},
  153. warn() {},
  154. err() {}
  155. }
  156. }
  157. }))
  158. })
  159. describe('when the copy succeeds', function() {
  160. it('should look up the original project', function(done) {
  161. const newProjectName = 'someProj'
  162. return this.duplicator.duplicate(
  163. this.owner,
  164. this.old_project_id,
  165. newProjectName,
  166. (err, newProject) => {
  167. this.ProjectGetter.getProject
  168. .calledWith(this.old_project_id)
  169. .should.equal(true)
  170. return done()
  171. }
  172. )
  173. })
  174. it('should flush the original project to mongo', function(done) {
  175. const newProjectName = 'someProj'
  176. return this.duplicator.duplicate(
  177. this.owner,
  178. this.old_project_id,
  179. newProjectName,
  180. (err, newProject) => {
  181. this.DocumentUpdaterHandler.flushProjectToMongo
  182. .calledWith(this.old_project_id)
  183. .should.equal(true)
  184. return done()
  185. }
  186. )
  187. })
  188. it('should create a blank project', function(done) {
  189. const newProjectName = 'someProj'
  190. return this.duplicator.duplicate(
  191. this.owner,
  192. this.old_project_id,
  193. newProjectName,
  194. (err, newProject) => {
  195. newProject._id.should.equal(this.stubbedNewProject._id)
  196. this.creationHandler.createBlankProject
  197. .calledWith(this.owner._id, newProjectName)
  198. .should.equal(true)
  199. return done()
  200. }
  201. )
  202. })
  203. it('should use the same compiler', function(done) {
  204. this.ProjectEntityUpdateHandler.addDoc.callsArgWith(
  205. 5,
  206. null,
  207. this.rootFolder.docs[0],
  208. this.owner._id
  209. )
  210. return this.duplicator.duplicate(
  211. this.owner,
  212. this.old_project_id,
  213. '',
  214. (err, newProject) => {
  215. this.projectOptionsHandler.setCompiler
  216. .calledWith(this.stubbedNewProject._id, this.project.compiler)
  217. .should.equal(true)
  218. return done()
  219. }
  220. )
  221. })
  222. it('should use the same root doc', function(done) {
  223. this.ProjectEntityUpdateHandler.addDoc.callsArgWith(
  224. 5,
  225. null,
  226. this.rootFolder.docs[0],
  227. this.owner._id
  228. )
  229. return this.duplicator.duplicate(
  230. this.owner,
  231. this.old_project_id,
  232. '',
  233. (err, newProject) => {
  234. this.ProjectEntityUpdateHandler.setRootDoc
  235. .calledWith(this.stubbedNewProject._id, this.rootFolder.docs[0]._id)
  236. .should.equal(true)
  237. return done()
  238. }
  239. )
  240. })
  241. it('should not copy the collaberators or read only refs', function(done) {
  242. return this.duplicator.duplicate(
  243. this.owner,
  244. this.old_project_id,
  245. '',
  246. (err, newProject) => {
  247. newProject.collaberator_refs.length.should.equal(0)
  248. newProject.readOnly_refs.length.should.equal(0)
  249. return done()
  250. }
  251. )
  252. })
  253. it('should copy all the folders', function(done) {
  254. return this.duplicator.duplicate(
  255. this.owner,
  256. this.old_project_id,
  257. '',
  258. (err, newProject) => {
  259. this.ProjectEntityUpdateHandler.addFolder
  260. .calledWith(
  261. this.new_project_id,
  262. this.stubbedNewProject.rootFolder[0]._id,
  263. this.level1folder.name
  264. )
  265. .should.equal(true)
  266. this.ProjectEntityUpdateHandler.addFolder
  267. .calledWith(
  268. this.new_project_id,
  269. this.newFolder._id,
  270. this.level2folder.name
  271. )
  272. .should.equal(true)
  273. this.ProjectEntityUpdateHandler.addFolder.callCount.should.equal(2)
  274. return done()
  275. }
  276. )
  277. })
  278. it('should copy all the docs', function(done) {
  279. return this.duplicator.duplicate(
  280. this.owner,
  281. this.old_project_id,
  282. '',
  283. (err, newProject) => {
  284. this.DocstoreManager.getAllDocs
  285. .calledWith(this.old_project_id)
  286. .should.equal(true)
  287. this.ProjectEntityUpdateHandler.addDoc
  288. .calledWith(
  289. this.new_project_id,
  290. this.stubbedNewProject.rootFolder[0]._id,
  291. this.doc0.name,
  292. this.doc0_lines,
  293. this.owner._id
  294. )
  295. .should.equal(true)
  296. this.ProjectEntityUpdateHandler.addDoc
  297. .calledWith(
  298. this.new_project_id,
  299. this.newFolder._id,
  300. this.doc1.name,
  301. this.doc1_lines,
  302. this.owner._id
  303. )
  304. .should.equal(true)
  305. this.ProjectEntityUpdateHandler.addDoc
  306. .calledWith(
  307. this.new_project_id,
  308. this.newFolder._id,
  309. this.doc2.name,
  310. this.doc2_lines,
  311. this.owner._id
  312. )
  313. .should.equal(true)
  314. return done()
  315. }
  316. )
  317. })
  318. it('should copy all the files', function(done) {
  319. return this.duplicator.duplicate(
  320. this.owner,
  321. this.old_project_id,
  322. '',
  323. (err, newProject) => {
  324. this.ProjectEntityUpdateHandler.copyFileFromExistingProjectWithProject
  325. .calledWith(
  326. this.stubbedNewProject._id,
  327. this.stubbedNewProject,
  328. this.stubbedNewProject.rootFolder[0]._id,
  329. this.project._id,
  330. this.rootFolder.fileRefs[0],
  331. this.owner._id
  332. )
  333. .should.equal(true)
  334. this.ProjectEntityUpdateHandler.copyFileFromExistingProjectWithProject
  335. .calledWith(
  336. this.stubbedNewProject._id,
  337. this.stubbedNewProject,
  338. this.newFolder._id,
  339. this.project._id,
  340. this.level1folder.fileRefs[0],
  341. this.owner._id
  342. )
  343. .should.equal(true)
  344. this.ProjectEntityUpdateHandler.copyFileFromExistingProjectWithProject
  345. .calledWith(
  346. this.stubbedNewProject._id,
  347. this.stubbedNewProject,
  348. this.newFolder._id,
  349. this.project._id,
  350. this.level2folder.fileRefs[0],
  351. this.owner._id
  352. )
  353. .should.equal(true)
  354. return done()
  355. }
  356. )
  357. })
  358. })
  359. describe('when there is an error', function() {
  360. beforeEach(function() {
  361. return (this.rootFolder.fileRefs = [
  362. { name: 'file0', _id: 'file0' },
  363. 'BROKEN-FILE',
  364. { name: 'file1', _id: 'file1' },
  365. { name: 'file2', _id: 'file2' }
  366. ])
  367. })
  368. it('should delete the broken cloned project', function(done) {
  369. return this.duplicator.duplicate(
  370. this.owner,
  371. this.old_project_id,
  372. '',
  373. (err, newProject) => {
  374. this.ProjectDeleter.deleteProject
  375. .calledWith(this.stubbedNewProject._id)
  376. .should.equal(true)
  377. return done()
  378. }
  379. )
  380. })
  381. it('should not delete the original project', function(done) {
  382. return this.duplicator.duplicate(
  383. this.owner,
  384. this.old_project_id,
  385. '',
  386. (err, newProject) => {
  387. this.ProjectDeleter.deleteProject
  388. .calledWith(this.old_project_id)
  389. .should.equal(false)
  390. return done()
  391. }
  392. )
  393. })
  394. it('should return an error', function(done) {
  395. return this.duplicator.duplicate(
  396. this.owner,
  397. this.old_project_id,
  398. '',
  399. (err, newProject) => {
  400. err.should.not.equal(null)
  401. return done()
  402. }
  403. )
  404. })
  405. })
  406. })