FileControllerTests.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. const sinon = require('sinon')
  2. const chai = require('chai')
  3. const { expect } = chai
  4. const SandboxedModule = require('sandboxed-module')
  5. const Errors = require('../../../app/js/Errors')
  6. const modulePath = '../../../app/js/FileController.js'
  7. describe('FileController', function() {
  8. let PersistorManager,
  9. FileHandler,
  10. LocalFileWriter,
  11. FileController,
  12. req,
  13. res,
  14. next,
  15. stream
  16. const settings = {
  17. s3: {
  18. buckets: {
  19. user_files: 'user_files'
  20. }
  21. }
  22. }
  23. const fileSize = 1234
  24. const fileStream = 'fileStream'
  25. const projectId = 'projectId'
  26. const fileId = 'file_id'
  27. const bucket = 'user_files'
  28. const key = `${projectId}/${fileId}`
  29. const error = new Error('incorrect utensil')
  30. beforeEach(function() {
  31. PersistorManager = {
  32. sendStream: sinon.stub().yields(),
  33. copyFile: sinon.stub().yields(),
  34. deleteFile: sinon.stub().yields()
  35. }
  36. FileHandler = {
  37. getFile: sinon.stub().yields(null, fileStream),
  38. getFileSize: sinon.stub().yields(null, fileSize),
  39. deleteFile: sinon.stub().yields(),
  40. insertFile: sinon.stub().yields(),
  41. getDirectorySize: sinon.stub().yields(null, fileSize)
  42. }
  43. LocalFileWriter = {}
  44. stream = {
  45. pipeline: sinon.stub()
  46. }
  47. FileController = SandboxedModule.require(modulePath, {
  48. requires: {
  49. './LocalFileWriter': LocalFileWriter,
  50. './FileHandler': FileHandler,
  51. './PersistorManager': PersistorManager,
  52. './Errors': Errors,
  53. stream: stream,
  54. 'settings-sharelatex': settings,
  55. 'metrics-sharelatex': {
  56. inc() {}
  57. }
  58. },
  59. globals: { console }
  60. })
  61. req = {
  62. key: key,
  63. bucket: bucket,
  64. query: {},
  65. params: {
  66. project_id: projectId,
  67. file_id: fileId
  68. },
  69. headers: {},
  70. setLogMessage: sinon.stub(),
  71. addLogField: sinon.stub(),
  72. addLogFields: sinon.stub()
  73. }
  74. res = {
  75. set: sinon.stub().returnsThis(),
  76. sendStatus: sinon.stub().returnsThis(),
  77. status: sinon.stub().returnsThis()
  78. }
  79. next = sinon.stub()
  80. })
  81. describe('getFile', function() {
  82. it('should pipe the stream', function() {
  83. FileController.getFile(req, res, next)
  84. expect(stream.pipeline).to.have.been.calledWith(fileStream, res)
  85. })
  86. it('should send a 200 if the cacheWarm param is true', function(done) {
  87. req.query.cacheWarm = true
  88. res.sendStatus = statusCode => {
  89. statusCode.should.equal(200)
  90. done()
  91. }
  92. FileController.getFile(req, res, next)
  93. })
  94. it('should send an error if there is a problem', function() {
  95. FileHandler.getFile.yields(error)
  96. FileController.getFile(req, res, next)
  97. expect(next).to.have.been.calledWith(error)
  98. })
  99. describe('with a range header', function() {
  100. let expectedOptions
  101. beforeEach(function() {
  102. expectedOptions = {
  103. bucket,
  104. key,
  105. format: undefined,
  106. style: undefined
  107. }
  108. })
  109. it('should pass range options to FileHandler', function() {
  110. req.headers.range = 'bytes=0-8'
  111. expectedOptions.start = 0
  112. expectedOptions.end = 8
  113. FileController.getFile(req, res, next)
  114. expect(FileHandler.getFile).to.have.been.calledWith(
  115. bucket,
  116. key,
  117. expectedOptions
  118. )
  119. })
  120. it('should ignore an invalid range header', function() {
  121. req.headers.range = 'potato'
  122. FileController.getFile(req, res, next)
  123. expect(FileHandler.getFile).to.have.been.calledWith(
  124. bucket,
  125. key,
  126. expectedOptions
  127. )
  128. })
  129. it("should ignore any type other than 'bytes'", function() {
  130. req.headers.range = 'wombats=0-8'
  131. FileController.getFile(req, res, next)
  132. expect(FileHandler.getFile).to.have.been.calledWith(
  133. bucket,
  134. key,
  135. expectedOptions
  136. )
  137. })
  138. })
  139. })
  140. describe('getFileHead', function() {
  141. it('should return the file size in a Content-Length header', function(done) {
  142. res.end = () => {
  143. expect(res.status).to.have.been.calledWith(200)
  144. expect(res.set).to.have.been.calledWith('Content-Length', fileSize)
  145. done()
  146. }
  147. FileController.getFileHead(req, res, next)
  148. })
  149. it('should return a 404 is the file is not found', function(done) {
  150. FileHandler.getFileSize.yields(new Errors.NotFoundError())
  151. res.sendStatus = code => {
  152. expect(code).to.equal(404)
  153. done()
  154. }
  155. FileController.getFileHead(req, res, next)
  156. })
  157. it('should send an error on internal errors', function() {
  158. FileHandler.getFileSize.yields(error)
  159. FileController.getFileHead(req, res, next)
  160. expect(next).to.have.been.calledWith(error)
  161. })
  162. })
  163. describe('insertFile', function() {
  164. it('should send bucket name key and res to PersistorManager', function(done) {
  165. res.sendStatus = code => {
  166. expect(FileHandler.insertFile).to.have.been.calledWith(bucket, key, req)
  167. expect(code).to.equal(200)
  168. done()
  169. }
  170. FileController.insertFile(req, res, next)
  171. })
  172. })
  173. describe('copyFile', function() {
  174. const oldFileId = 'oldFileId'
  175. const oldProjectId = 'oldProjectid'
  176. const oldKey = `${oldProjectId}/${oldFileId}`
  177. beforeEach(function() {
  178. req.body = {
  179. source: {
  180. project_id: oldProjectId,
  181. file_id: oldFileId
  182. }
  183. }
  184. })
  185. it('should send bucket name and both keys to PersistorManager', function(done) {
  186. res.sendStatus = code => {
  187. code.should.equal(200)
  188. expect(PersistorManager.copyFile).to.have.been.calledWith(
  189. bucket,
  190. oldKey,
  191. key
  192. )
  193. done()
  194. }
  195. FileController.copyFile(req, res, next)
  196. })
  197. it('should send a 404 if the original file was not found', function(done) {
  198. PersistorManager.copyFile.yields(new Errors.NotFoundError())
  199. res.sendStatus = code => {
  200. code.should.equal(404)
  201. done()
  202. }
  203. FileController.copyFile(req, res, next)
  204. })
  205. it('should send an error if there was an error', function() {
  206. PersistorManager.copyFile.yields(error)
  207. FileController.copyFile(req, res, next)
  208. expect(next).to.have.been.calledWith(error)
  209. })
  210. })
  211. describe('delete file', function() {
  212. it('should tell the file handler', function(done) {
  213. res.sendStatus = code => {
  214. code.should.equal(204)
  215. expect(FileHandler.deleteFile).to.have.been.calledWith(bucket, key)
  216. done()
  217. }
  218. FileController.deleteFile(req, res, next)
  219. })
  220. it('should send a 500 if there was an error', function() {
  221. FileHandler.deleteFile.yields(error)
  222. FileController.deleteFile(req, res, next)
  223. expect(next).to.have.been.calledWith(error)
  224. })
  225. })
  226. describe('directorySize', function() {
  227. it('should return total directory size bytes', function(done) {
  228. FileController.directorySize(req, {
  229. json: result => {
  230. expect(result['total bytes']).to.equal(fileSize)
  231. done()
  232. }
  233. })
  234. })
  235. it('should send a 500 if there was an error', function() {
  236. FileHandler.getDirectorySize.yields(error)
  237. FileController.directorySize(req, res, next)
  238. expect(next).to.have.been.calledWith(error)
  239. })
  240. })
  241. })