LocalFileWriterTests.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. const sinon = require('sinon')
  2. const chai = require('chai')
  3. const { expect } = chai
  4. const modulePath = '../../../app/js/LocalFileWriter.js'
  5. const SandboxedModule = require('sandboxed-module')
  6. const { Errors } = require('@overleaf/object-persistor')
  7. chai.use(require('sinon-chai'))
  8. describe('LocalFileWriter', function () {
  9. const writeStream = 'writeStream'
  10. const readStream = 'readStream'
  11. const settings = { path: { uploadFolder: '/uploads' } }
  12. const fsPath = '/uploads/wombat'
  13. const filename = 'wombat'
  14. let stream, fs, LocalFileWriter
  15. beforeEach(function () {
  16. fs = {
  17. createWriteStream: sinon.stub().returns(writeStream),
  18. unlink: sinon.stub().yields(),
  19. }
  20. stream = {
  21. pipeline: sinon.stub().yields(),
  22. }
  23. const ObjectPersistor = { Errors }
  24. LocalFileWriter = SandboxedModule.require(modulePath, {
  25. requires: {
  26. fs,
  27. stream,
  28. '@overleaf/settings': settings,
  29. '@overleaf/metrics': {
  30. inc: sinon.stub(),
  31. Timer: sinon.stub().returns({ done: sinon.stub() }),
  32. },
  33. '@overleaf/object-persistor': ObjectPersistor,
  34. },
  35. })
  36. })
  37. describe('writeStream', function () {
  38. it('writes the stream to the upload folder', function (done) {
  39. LocalFileWriter.writeStream(readStream, filename, (err, path) => {
  40. expect(err).not.to.exist
  41. expect(fs.createWriteStream).to.have.been.calledWith(fsPath)
  42. expect(stream.pipeline).to.have.been.calledWith(readStream, writeStream)
  43. expect(path).to.equal(fsPath)
  44. done()
  45. })
  46. })
  47. describe('when there is an error', function () {
  48. const error = new Error('not enough ketchup')
  49. beforeEach(function () {
  50. stream.pipeline.yields(error)
  51. })
  52. it('should wrap the error', function () {
  53. LocalFileWriter.writeStream(readStream, filename, err => {
  54. expect(err).to.exist
  55. expect(err.cause).to.equal(error)
  56. })
  57. })
  58. it('should delete the temporary file', function () {
  59. LocalFileWriter.writeStream(readStream, filename, () => {
  60. expect(fs.unlink).to.have.been.calledWith(fsPath)
  61. })
  62. })
  63. })
  64. })
  65. describe('deleteFile', function () {
  66. it('should unlink the file', function (done) {
  67. LocalFileWriter.deleteFile(fsPath, err => {
  68. expect(err).not.to.exist
  69. expect(fs.unlink).to.have.been.calledWith(fsPath)
  70. done()
  71. })
  72. })
  73. it('should not call unlink with an empty path', function (done) {
  74. LocalFileWriter.deleteFile('', err => {
  75. expect(err).not.to.exist
  76. expect(fs.unlink).not.to.have.been.called
  77. done()
  78. })
  79. })
  80. it('should not throw a error if the file does not exist', function (done) {
  81. const error = new Error('file not found')
  82. error.code = 'ENOENT'
  83. fs.unlink = sinon.stub().yields(error)
  84. LocalFileWriter.deleteFile(fsPath, err => {
  85. expect(err).not.to.exist
  86. done()
  87. })
  88. })
  89. it('should wrap the error', function (done) {
  90. const error = new Error('failed to reticulate splines')
  91. fs.unlink = sinon.stub().yields(error)
  92. LocalFileWriter.deleteFile(fsPath, err => {
  93. expect(err).to.exist
  94. expect(err.cause).to.equal(error)
  95. done()
  96. })
  97. })
  98. })
  99. })