FileStoreHandlerTests.coffee 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. assert = require("chai").assert
  2. sinon = require('sinon')
  3. chai = require('chai')
  4. should = chai.should()
  5. expect = chai.expect
  6. modulePath = "../../../../app/js/Features/FileStore/FileStoreHandler.js"
  7. SandboxedModule = require('sandboxed-module')
  8. describe "FileStoreHandler", ->
  9. beforeEach ->
  10. @fs =
  11. createReadStream : sinon.stub()
  12. lstat: sinon.stub().callsArgWith(1, null, {
  13. isFile:=> true
  14. isDirectory:-> return false
  15. })
  16. @writeStream =
  17. my:"writeStream"
  18. on: (type, cb)->
  19. if type == "response"
  20. cb({statusCode: 200})
  21. @readStream = {my:"readStream", on: sinon.stub()}
  22. @request = sinon.stub()
  23. @settings = apis:{filestore:{url:"http//filestore.sharelatex.test"}}
  24. @handler = SandboxedModule.require modulePath, requires:
  25. "settings-sharelatex":@settings
  26. "request":@request
  27. "logger-sharelatex" : @logger = {log:sinon.stub(), err:sinon.stub()}
  28. "fs" : @fs
  29. @file_id = "file_id_here"
  30. @project_id = "1312312312"
  31. @fsPath = "uploads/myfile.eps"
  32. @handler._buildUrl = sinon.stub().returns("http://filestore.stubbedBuilder.com")
  33. describe "uploadFileFromDisk", ->
  34. beforeEach ->
  35. @request.returns(@writeStream)
  36. it "should create read stream", (done)->
  37. @fs.createReadStream.returns
  38. pipe:->
  39. on: (type, cb)->
  40. if type == "open"
  41. cb()
  42. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
  43. @fs.createReadStream.calledWith(@fsPath).should.equal true
  44. done()
  45. it "should pipe the read stream to request", (done)->
  46. @request.returns(@writeStream)
  47. @fs.createReadStream.returns
  48. on: (type, cb)->
  49. if type == "open"
  50. cb()
  51. pipe:(o)=>
  52. @writeStream.should.equal o
  53. done()
  54. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
  55. it "should pass the correct options to request", (done)->
  56. @fs.createReadStream.returns
  57. pipe:->
  58. on: (type, cb)->
  59. if type == "open"
  60. cb()
  61. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
  62. @request.args[0][0].method.should.equal "post"
  63. @request.args[0][0].uri.should.equal @handler._buildUrl()
  64. done()
  65. it "builds the correct url", (done)->
  66. @fs.createReadStream.returns
  67. pipe:->
  68. on: (type, cb)->
  69. if type == "open"
  70. cb()
  71. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
  72. @handler._buildUrl.calledWith(@project_id, @file_id).should.equal true
  73. done()
  74. it 'should callback with the url', (done) ->
  75. @fs.createReadStream.returns
  76. pipe:->
  77. on: (type, cb)->
  78. if type == "open"
  79. cb()
  80. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, (err, url) =>
  81. expect(err).to.not.exist
  82. expect(url).to.equal(@handler._buildUrl())
  83. done()
  84. describe "symlink", ->
  85. beforeEach ->
  86. @fs.lstat = sinon.stub().callsArgWith(1, null, {
  87. isFile:=> false
  88. isDirectory:-> return false
  89. })
  90. it "should not read file if it is symlink", (done)->
  91. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
  92. @fs.createReadStream.called.should.equal false
  93. done()
  94. describe "symlink", ->
  95. it "should not read file stat returns nothing", (done)->
  96. @fs.lstat = sinon.stub().callsArgWith(1, null, null)
  97. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, =>
  98. @fs.createReadStream.called.should.equal false
  99. done()
  100. describe "when upload fails", ->
  101. beforeEach ->
  102. @writeStream.on = (type, cb) ->
  103. if type == "response"
  104. cb({statusCode: 500})
  105. it 'should callback with an error', (done) ->
  106. @fs.createReadStream.callCount = 0
  107. @fs.createReadStream.returns
  108. pipe:->
  109. on: (type, cb)->
  110. if type == "open"
  111. cb()
  112. @handler.uploadFileFromDisk @project_id, @file_id, @fsPath, (err) =>
  113. expect(err).to.exist
  114. expect(err).to.be.instanceof Error
  115. expect(@fs.createReadStream.callCount).to.equal @handler.RETRY_ATTEMPTS
  116. done()
  117. describe "deleteFile", ->
  118. it "should send a delete request to filestore api", (done)->
  119. @request.callsArgWith(1, null)
  120. @handler.deleteFile @project_id, @file_id, (err)=>
  121. assert.equal err, undefined
  122. @request.args[0][0].method.should.equal "delete"
  123. @request.args[0][0].uri.should.equal @handler._buildUrl()
  124. done()
  125. it "should return the error if there is one", (done)->
  126. error = "my error"
  127. @request.callsArgWith(1, error)
  128. @handler.deleteFile @project_id, @file_id, (err)=>
  129. assert.equal err, error
  130. done()
  131. it "builds the correct url", (done)->
  132. @request.callsArgWith(1, null)
  133. @handler.deleteFile @project_id, @file_id, (err)=>
  134. @handler._buildUrl.calledWith(@project_id, @file_id).should.equal true
  135. done()
  136. describe "getFileStream", ->
  137. beforeEach ->
  138. @query = {}
  139. @request.returns(@readStream)
  140. it "should get the stream with the correct params", (done)->
  141. @handler.getFileStream @project_id, @file_id, @query, (err, stream)=>
  142. @request.args[0][0].method.should.equal "get"
  143. @request.args[0][0].uri.should.equal @handler._buildUrl()
  144. done()
  145. it "should get stream from request", (done)->
  146. @handler.getFileStream @project_id, @file_id, @query, (err, stream)=>
  147. stream.should.equal @readStream
  148. done()
  149. it "builds the correct url", (done)->
  150. @handler.getFileStream @project_id, @file_id, @query, (err, stream)=>
  151. @handler._buildUrl.calledWith(@project_id, @file_id).should.equal true
  152. done()
  153. it "should add an error handler", (done) ->
  154. @handler.getFileStream @project_id, @file_id, @query, (err, stream)=>
  155. stream.on.calledWith("error").should.equal true
  156. done()
  157. describe 'when range is specified in query', ->
  158. beforeEach ->
  159. @query = {'range': '0-10'}
  160. it 'should add a range header', (done) ->
  161. @handler.getFileStream @project_id, @file_id, @query, (err, stream)=>
  162. @request.callCount.should.equal 1
  163. headers = @request.firstCall.args[0].headers
  164. expect(headers).to.have.keys('range')
  165. expect(headers['range']).to.equal 'bytes=0-10'
  166. done()
  167. describe 'when range is invalid', ->
  168. ['0-', '-100', 'one-two', 'nonsense'].forEach (r) =>
  169. beforeEach ->
  170. @query = {'range': "#{r}"}
  171. it "should not add a range header for '#{r}'", (done) ->
  172. @handler.getFileStream @project_id, @file_id, @query, (err, stream)=>
  173. @request.callCount.should.equal 1
  174. headers = @request.firstCall.args[0].headers
  175. expect(headers).to.not.have.keys('range')
  176. done()
  177. describe "copyFile", ->
  178. beforeEach ->
  179. @newProject_id = "new project"
  180. @newFile_id = "new file id"
  181. it "should post json", (done)->
  182. @request.callsArgWith(1, null)
  183. @handler.copyFile @project_id, @file_id, @newProject_id, @newFile_id, =>
  184. @request.args[0][0].method.should.equal "put"
  185. @request.args[0][0].uri.should.equal @handler._buildUrl()
  186. @request.args[0][0].json.source.project_id.should.equal @project_id
  187. @request.args[0][0].json.source.file_id.should.equal @file_id
  188. done()
  189. it "builds the correct url", (done)->
  190. @request.callsArgWith(1, null)
  191. @handler.copyFile @project_id, @file_id, @newProject_id, @newFile_id, =>
  192. @handler._buildUrl.calledWith(@newProject_id, @newFile_id).should.equal true
  193. done()
  194. it "returns the url", (done)->
  195. @request.callsArgWith(1, null)
  196. @handler.copyFile @project_id, @file_id, @newProject_id, @newFile_id, (err, url) =>
  197. url.should.equal "http://filestore.stubbedBuilder.com"
  198. done()
  199. it "should return the err", (done)->
  200. error = "errrror"
  201. @request.callsArgWith(1, error)
  202. @handler.copyFile @project_id, @file_id, @newProject_id, @newFile_id, (err)=>
  203. err.should.equal error
  204. done()