FileControllerTests.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /* eslint-disable
  2. no-return-assign,
  3. no-unused-vars,
  4. */
  5. // TODO: This file was created by bulk-decaffeinate.
  6. // Fix any style issues and re-enable lint.
  7. /*
  8. * decaffeinate suggestions:
  9. * DS102: Remove unnecessary code created because of implicit returns
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. const { assert } = require('chai')
  13. const sinon = require('sinon')
  14. const chai = require('chai')
  15. const should = chai.should()
  16. const { expect } = chai
  17. const modulePath = '../../../app/js/FileController.js'
  18. const SandboxedModule = require('sandboxed-module')
  19. describe('FileController', function() {
  20. beforeEach(function() {
  21. this.PersistorManager = {
  22. sendStream: sinon.stub(),
  23. copyFile: sinon.stub(),
  24. deleteFile: sinon.stub()
  25. }
  26. this.settings = {
  27. s3: {
  28. buckets: {
  29. user_files: 'user_files'
  30. }
  31. }
  32. }
  33. this.FileHandler = {
  34. getFile: sinon.stub(),
  35. getFileSize: sinon.stub(),
  36. deleteFile: sinon.stub(),
  37. insertFile: sinon.stub(),
  38. getDirectorySize: sinon.stub()
  39. }
  40. this.LocalFileWriter = {}
  41. this.controller = SandboxedModule.require(modulePath, {
  42. requires: {
  43. './LocalFileWriter': this.LocalFileWriter,
  44. './FileHandler': this.FileHandler,
  45. './PersistorManager': this.PersistorManager,
  46. './Errors': (this.Errors = { NotFoundError: sinon.stub() }),
  47. 'settings-sharelatex': this.settings,
  48. 'metrics-sharelatex': {
  49. inc() {}
  50. },
  51. 'logger-sharelatex': {
  52. log() {},
  53. err() {}
  54. }
  55. }
  56. })
  57. this.project_id = 'project_id'
  58. this.file_id = 'file_id'
  59. this.bucket = 'user_files'
  60. this.key = `${this.project_id}/${this.file_id}`
  61. this.req = {
  62. key: this.key,
  63. bucket: this.bucket,
  64. query: {},
  65. params: {
  66. project_id: this.project_id,
  67. file_id: this.file_id
  68. },
  69. headers: {}
  70. }
  71. this.res = {
  72. set: sinon.stub().returnsThis(),
  73. status: sinon.stub().returnsThis()
  74. }
  75. return (this.fileStream = {})
  76. })
  77. describe('getFile', function() {
  78. it('should pipe the stream', function(done) {
  79. this.FileHandler.getFile.callsArgWith(3, null, this.fileStream)
  80. this.fileStream.pipe = res => {
  81. res.should.equal(this.res)
  82. return done()
  83. }
  84. return this.controller.getFile(this.req, this.res)
  85. })
  86. it('should send a 200 if the cacheWarm param is true', function(done) {
  87. this.req.query.cacheWarm = true
  88. this.FileHandler.getFile.callsArgWith(3, null, this.fileStream)
  89. this.res.send = statusCode => {
  90. statusCode.should.equal(200)
  91. return done()
  92. }
  93. return this.controller.getFile(this.req, this.res)
  94. })
  95. it('should send a 500 if there is a problem', function(done) {
  96. this.FileHandler.getFile.callsArgWith(3, 'error')
  97. this.res.send = code => {
  98. code.should.equal(500)
  99. return done()
  100. }
  101. return this.controller.getFile(this.req, this.res)
  102. })
  103. return describe("with a 'Range' header set", function() {
  104. beforeEach(function() {
  105. return (this.req.headers.range = 'bytes=0-8')
  106. })
  107. return it("should pass 'start' and 'end' options to FileHandler", function(done) {
  108. this.FileHandler.getFile.callsArgWith(3, null, this.fileStream)
  109. this.fileStream.pipe = res => {
  110. expect(this.FileHandler.getFile.lastCall.args[2].start).to.equal(0)
  111. expect(this.FileHandler.getFile.lastCall.args[2].end).to.equal(8)
  112. return done()
  113. }
  114. return this.controller.getFile(this.req, this.res)
  115. })
  116. })
  117. })
  118. describe('getFileHead', function() {
  119. it('should return the file size in a Content-Length header', function(done) {
  120. const expectedFileSize = 84921
  121. this.FileHandler.getFileSize.yields(
  122. new Error('FileHandler.getFileSize: unexpected arguments')
  123. )
  124. this.FileHandler.getFileSize
  125. .withArgs(this.bucket, this.key)
  126. .yields(null, expectedFileSize)
  127. this.res.end = () => {
  128. expect(this.res.status.lastCall.args[0]).to.equal(200)
  129. expect(
  130. this.res.set.calledWith('Content-Length', expectedFileSize)
  131. ).to.equal(true)
  132. return done()
  133. }
  134. return this.controller.getFileHead(this.req, this.res)
  135. })
  136. it('should return a 404 is the file is not found', function(done) {
  137. this.FileHandler.getFileSize.yields(new this.Errors.NotFoundError())
  138. this.res.end = () => {
  139. expect(this.res.status.lastCall.args[0]).to.equal(404)
  140. return done()
  141. }
  142. return this.controller.getFileHead(this.req, this.res)
  143. })
  144. return it('should return a 500 on internal errors', function(done) {
  145. this.FileHandler.getFileSize.yields(new Error())
  146. this.res.end = () => {
  147. expect(this.res.status.lastCall.args[0]).to.equal(500)
  148. return done()
  149. }
  150. return this.controller.getFileHead(this.req, this.res)
  151. })
  152. })
  153. describe('insertFile', () =>
  154. it('should send bucket name key and res to PersistorManager', function(done) {
  155. this.FileHandler.insertFile.callsArgWith(3)
  156. this.res.send = () => {
  157. this.FileHandler.insertFile
  158. .calledWith(this.bucket, this.key, this.req)
  159. .should.equal(true)
  160. return done()
  161. }
  162. return this.controller.insertFile(this.req, this.res)
  163. }))
  164. describe('copyFile', function() {
  165. beforeEach(function() {
  166. this.oldFile_id = 'old_file_id'
  167. this.oldProject_id = 'old_project_id'
  168. return (this.req.body = {
  169. source: {
  170. project_id: this.oldProject_id,
  171. file_id: this.oldFile_id
  172. }
  173. })
  174. })
  175. it('should send bucket name and both keys to PersistorManager', function(done) {
  176. this.PersistorManager.copyFile.callsArgWith(3)
  177. this.res.send = code => {
  178. code.should.equal(200)
  179. this.PersistorManager.copyFile
  180. .calledWith(
  181. this.bucket,
  182. `${this.oldProject_id}/${this.oldFile_id}`,
  183. this.key
  184. )
  185. .should.equal(true)
  186. return done()
  187. }
  188. return this.controller.copyFile(this.req, this.res)
  189. })
  190. it('should send a 404 if the original file was not found', function(done) {
  191. this.PersistorManager.copyFile.callsArgWith(
  192. 3,
  193. new this.Errors.NotFoundError()
  194. )
  195. this.res.send = code => {
  196. code.should.equal(404)
  197. return done()
  198. }
  199. return this.controller.copyFile(this.req, this.res)
  200. })
  201. return it('should send a 500 if there was an error', function(done) {
  202. this.PersistorManager.copyFile.callsArgWith(3, 'error')
  203. this.res.send = code => {
  204. code.should.equal(500)
  205. return done()
  206. }
  207. return this.controller.copyFile(this.req, this.res)
  208. })
  209. })
  210. describe('delete file', function() {
  211. it('should tell the file handler', function(done) {
  212. this.FileHandler.deleteFile.callsArgWith(2)
  213. this.res.send = code => {
  214. code.should.equal(204)
  215. this.FileHandler.deleteFile
  216. .calledWith(this.bucket, this.key)
  217. .should.equal(true)
  218. return done()
  219. }
  220. return this.controller.deleteFile(this.req, this.res)
  221. })
  222. return it('should send a 500 if there was an error', function(done) {
  223. this.FileHandler.deleteFile.callsArgWith(2, 'error')
  224. this.res.send = function(code) {
  225. code.should.equal(500)
  226. return done()
  227. }
  228. return this.controller.deleteFile(this.req, this.res)
  229. })
  230. })
  231. describe('_get_range', function() {
  232. it('should parse a valid Range header', function(done) {
  233. const result = this.controller._get_range('bytes=0-200')
  234. expect(result).to.not.equal(null)
  235. expect(result.start).to.equal(0)
  236. expect(result.end).to.equal(200)
  237. return done()
  238. })
  239. it('should return null for an invalid Range header', function(done) {
  240. const result = this.controller._get_range('wat')
  241. expect(result).to.equal(null)
  242. return done()
  243. })
  244. return it("should return null for any type other than 'bytes'", function(done) {
  245. const result = this.controller._get_range('carrots=0-200')
  246. expect(result).to.equal(null)
  247. return done()
  248. })
  249. })
  250. return describe('directorySize', function() {
  251. it('should return total directory size bytes', function(done) {
  252. this.FileHandler.getDirectorySize.callsArgWith(2, null, 1024)
  253. return this.controller.directorySize(this.req, {
  254. json: result => {
  255. expect(result['total bytes']).to.equal(1024)
  256. return done()
  257. }
  258. })
  259. })
  260. return it('should send a 500 if there was an error', function(done) {
  261. this.FileHandler.getDirectorySize.callsArgWith(2, 'error')
  262. this.res.send = function(code) {
  263. code.should.equal(500)
  264. return done()
  265. }
  266. return this.controller.directorySize(this.req, this.res)
  267. })
  268. })
  269. })