ProjectUploadControllerTests.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. * DS102: Remove unnecessary code created because of implicit returns
  11. * DS206: Consider reworking classes to avoid initClass
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const sinon = require('sinon')
  15. const chai = require('chai')
  16. const should = chai.should()
  17. const { expect } = chai
  18. const modulePath =
  19. '../../../../app/src/Features/Uploads/ProjectUploadController.js'
  20. const SandboxedModule = require('sandboxed-module')
  21. const MockRequest = require('../helpers/MockRequest')
  22. const MockResponse = require('../helpers/MockResponse')
  23. const ArchiveErrors = require('../../../../app/src/Features/Uploads/ArchiveErrors')
  24. describe('ProjectUploadController', function() {
  25. beforeEach(function() {
  26. let Timer
  27. this.req = new MockRequest()
  28. this.res = new MockResponse()
  29. this.user_id = 'user-id-123'
  30. this.metrics = {
  31. Timer: (Timer = (function() {
  32. Timer = class Timer {
  33. static initClass() {
  34. this.prototype.done = sinon.stub()
  35. }
  36. }
  37. Timer.initClass()
  38. return Timer
  39. })())
  40. }
  41. this.AuthenticationController = {
  42. getLoggedInUserId: sinon.stub().returns(this.user_id)
  43. }
  44. return (this.ProjectUploadController = SandboxedModule.require(modulePath, {
  45. globals: {
  46. console: console
  47. },
  48. requires: {
  49. './ProjectUploadManager': (this.ProjectUploadManager = {}),
  50. './FileSystemImportManager': (this.FileSystemImportManager = {}),
  51. 'logger-sharelatex': (this.logger = {
  52. log: sinon.stub(),
  53. error: sinon.stub(),
  54. err() {}
  55. }),
  56. '@overleaf/metrics': this.metrics,
  57. '../Authentication/AuthenticationController': this
  58. .AuthenticationController,
  59. './ArchiveErrors': ArchiveErrors,
  60. fs: (this.fs = {})
  61. }
  62. }))
  63. })
  64. describe('uploadProject', function() {
  65. beforeEach(function() {
  66. this.path = '/path/to/file/on/disk.zip'
  67. this.name = 'filename.zip'
  68. this.req.file = {
  69. path: this.path,
  70. originalname: this.name
  71. }
  72. this.req.session = {
  73. user: {
  74. _id: this.user_id
  75. }
  76. }
  77. this.project = { _id: (this.project_id = 'project-id-123') }
  78. return (this.fs.unlink = sinon.stub())
  79. })
  80. describe('successfully', function() {
  81. beforeEach(function() {
  82. this.ProjectUploadManager.createProjectFromZipArchive = sinon
  83. .stub()
  84. .callsArgWith(3, null, this.project)
  85. return this.ProjectUploadController.uploadProject(this.req, this.res)
  86. })
  87. it('should create a project owned by the logged in user', function() {
  88. return this.ProjectUploadManager.createProjectFromZipArchive
  89. .calledWith(this.user_id)
  90. .should.equal(true)
  91. })
  92. it('should create a project with the same name as the zip archive', function() {
  93. return this.ProjectUploadManager.createProjectFromZipArchive
  94. .calledWith(sinon.match.any, 'filename', sinon.match.any)
  95. .should.equal(true)
  96. })
  97. it('should create a project from the zip archive', function() {
  98. return this.ProjectUploadManager.createProjectFromZipArchive
  99. .calledWith(sinon.match.any, sinon.match.any, this.path)
  100. .should.equal(true)
  101. })
  102. it('should return a successful response to the FileUploader client', function() {
  103. return expect(this.res.body).to.deep.equal({
  104. success: true,
  105. project_id: this.project_id
  106. })
  107. })
  108. it('should record the time taken to do the upload', function() {
  109. return this.metrics.Timer.prototype.done.called.should.equal(true)
  110. })
  111. it('should remove the uploaded file', function() {
  112. return this.fs.unlink.calledWith(this.path).should.equal(true)
  113. })
  114. })
  115. describe('when ProjectUploadManager.createProjectFromZipArchive fails', function() {
  116. beforeEach(function() {
  117. this.ProjectUploadManager.createProjectFromZipArchive = sinon
  118. .stub()
  119. .callsArgWith(3, new Error('Something went wrong'), this.project)
  120. return this.ProjectUploadController.uploadProject(this.req, this.res)
  121. })
  122. it('should return a failed response to the FileUploader client', function() {
  123. return expect(this.res.body).to.deep.equal(
  124. JSON.stringify({ success: false, error: 'upload_failed' })
  125. )
  126. })
  127. })
  128. describe('when ProjectUploadManager.createProjectFromZipArchive reports the file as invalid', function() {
  129. beforeEach(function() {
  130. this.ProjectUploadManager.createProjectFromZipArchive = sinon
  131. .stub()
  132. .callsArgWith(
  133. 3,
  134. new ArchiveErrors.ZipContentsTooLargeError(),
  135. this.project
  136. )
  137. return this.ProjectUploadController.uploadProject(this.req, this.res)
  138. })
  139. it('should return the reported error to the FileUploader client', function() {
  140. expect(JSON.parse(this.res.body)).to.deep.equal({
  141. success: false,
  142. error: 'zip_contents_too_large'
  143. })
  144. })
  145. it("should return an 'unprocessable entity' status code", function() {
  146. return expect(this.res.statusCode).to.equal(422)
  147. })
  148. })
  149. })
  150. describe('uploadFile', function() {
  151. beforeEach(function() {
  152. this.project_id = 'project-id-123'
  153. this.folder_id = 'folder-id-123'
  154. this.path = '/path/to/file/on/disk.png'
  155. this.name = 'filename.png'
  156. this.req.file = {
  157. path: this.path,
  158. originalname: this.name
  159. }
  160. this.req.session = {
  161. user: {
  162. _id: this.user_id
  163. }
  164. }
  165. this.req.params = { Project_id: this.project_id }
  166. this.req.query = { folder_id: this.folder_id }
  167. return (this.fs.unlink = sinon.stub())
  168. })
  169. describe('successfully', function() {
  170. beforeEach(function() {
  171. this.entity = {
  172. _id: '1234',
  173. type: 'file'
  174. }
  175. this.FileSystemImportManager.addEntity = sinon
  176. .stub()
  177. .callsArgWith(6, null, this.entity)
  178. return this.ProjectUploadController.uploadFile(this.req, this.res)
  179. })
  180. it('should insert the file', function() {
  181. return this.FileSystemImportManager.addEntity
  182. .calledWith(
  183. this.user_id,
  184. this.project_id,
  185. this.folder_id,
  186. this.name,
  187. this.path
  188. )
  189. .should.equal(true)
  190. })
  191. it('should return a successful response to the FileUploader client', function() {
  192. return expect(this.res.body).to.deep.equal({
  193. success: true,
  194. entity_id: this.entity._id,
  195. entity_type: 'file'
  196. })
  197. })
  198. it('should time the request', function() {
  199. return this.metrics.Timer.prototype.done.called.should.equal(true)
  200. })
  201. it('should remove the uploaded file', function() {
  202. return this.fs.unlink.calledWith(this.path).should.equal(true)
  203. })
  204. })
  205. describe('when FileSystemImportManager.addEntity returns a generic error', function() {
  206. beforeEach(function() {
  207. this.FileSystemImportManager.addEntity = sinon
  208. .stub()
  209. .callsArgWith(6, new Error('Sorry something went wrong'))
  210. return this.ProjectUploadController.uploadFile(this.req, this.res)
  211. })
  212. it('should return an unsuccessful response to the FileUploader client', function() {
  213. return expect(this.res.body).to.deep.equal({
  214. success: false
  215. })
  216. })
  217. })
  218. describe('when FileSystemImportManager.addEntity returns a too many files error', function() {
  219. beforeEach(function() {
  220. this.FileSystemImportManager.addEntity = sinon
  221. .stub()
  222. .callsArgWith(6, new Error('project_has_too_many_files'))
  223. return this.ProjectUploadController.uploadFile(this.req, this.res)
  224. })
  225. it('should return an unsuccessful response to the FileUploader client', function() {
  226. return expect(this.res.body).to.deep.equal({
  227. success: false,
  228. error: 'project_has_too_many_files'
  229. })
  230. })
  231. })
  232. describe('with a bad request', function() {
  233. beforeEach(function() {
  234. this.req.file.originalname = ''
  235. return this.ProjectUploadController.uploadFile(this.req, this.res)
  236. })
  237. it('should return a a non success response', function() {
  238. return expect(this.res.body).to.deep.equal({
  239. success: false
  240. })
  241. })
  242. })
  243. })
  244. })