2019-12-16 06:20:25 -05:00
|
|
|
/* eslint-disable
|
|
|
|
handle-callback-err,
|
|
|
|
no-return-assign,
|
|
|
|
no-unused-vars,
|
|
|
|
*/
|
|
|
|
// TODO: This file was created by bulk-decaffeinate.
|
|
|
|
// Fix any style issues and re-enable lint.
|
2019-12-16 06:20:22 -05:00
|
|
|
/*
|
|
|
|
* decaffeinate suggestions:
|
|
|
|
* DS102: Remove unnecessary code created because of implicit returns
|
|
|
|
* DS207: Consider shorter variations of null checks
|
|
|
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
|
|
*/
|
2019-12-16 06:20:29 -05:00
|
|
|
const { assert } = require('chai')
|
|
|
|
const sinon = require('sinon')
|
|
|
|
const chai = require('chai')
|
|
|
|
const { should } = chai
|
|
|
|
const { expect } = chai
|
|
|
|
const modulePath = '../../../app/js/FSPersistorManager.js'
|
|
|
|
const SandboxedModule = require('sandboxed-module')
|
|
|
|
const fs = require('fs')
|
|
|
|
const response = require('response')
|
|
|
|
|
|
|
|
describe('FSPersistorManagerTests', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
|
|
|
this.Fs = {
|
2019-12-16 06:20:29 -05:00
|
|
|
rename: sinon.stub(),
|
|
|
|
createReadStream: sinon.stub(),
|
|
|
|
createWriteStream: sinon.stub(),
|
|
|
|
unlink: sinon.stub(),
|
|
|
|
rmdir: sinon.stub(),
|
|
|
|
exists: sinon.stub(),
|
|
|
|
readdir: sinon.stub(),
|
|
|
|
open: sinon.stub(),
|
|
|
|
openSync: sinon.stub(),
|
|
|
|
fstatSync: sinon.stub(),
|
|
|
|
closeSync: sinon.stub(),
|
|
|
|
stat: sinon.stub()
|
|
|
|
}
|
|
|
|
this.Rimraf = sinon.stub()
|
2019-12-16 06:20:22 -05:00
|
|
|
this.LocalFileWriter = {
|
|
|
|
writeStream: sinon.stub(),
|
2018-11-07 11:51:06 -05:00
|
|
|
deleteFile: sinon.stub()
|
2019-12-16 06:20:29 -05:00
|
|
|
}
|
2019-12-16 06:20:22 -05:00
|
|
|
this.requires = {
|
2019-12-16 06:20:29 -05:00
|
|
|
'./LocalFileWriter': this.LocalFileWriter,
|
|
|
|
fs: this.Fs,
|
|
|
|
'logger-sharelatex': {
|
2019-12-16 06:20:22 -05:00
|
|
|
log() {},
|
|
|
|
err() {}
|
|
|
|
},
|
2019-12-16 06:20:29 -05:00
|
|
|
response: response,
|
|
|
|
rimraf: this.Rimraf,
|
|
|
|
'./Errors': (this.Errors = { NotFoundError: sinon.stub() })
|
|
|
|
}
|
|
|
|
this.location = '/tmp'
|
|
|
|
this.name1 = '530f2407e7ef165704000007/530f838b46d9a9e859000008'
|
|
|
|
this.name1Filtered = '530f2407e7ef165704000007_530f838b46d9a9e859000008'
|
|
|
|
this.name2 = 'second_file'
|
|
|
|
this.error = 'error_message'
|
|
|
|
return (this.FSPersistorManager = SandboxedModule.require(modulePath, {
|
|
|
|
requires: this.requires
|
|
|
|
}))
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('sendFile', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
2019-12-16 06:20:29 -05:00
|
|
|
return (this.Fs.createReadStream = sinon.stub().returns({
|
2019-12-16 06:20:22 -05:00
|
|
|
on() {},
|
|
|
|
pipe() {}
|
2019-12-16 06:20:29 -05:00
|
|
|
}))
|
|
|
|
})
|
2019-12-16 06:20:22 -05:00
|
|
|
|
2019-12-16 06:20:29 -05:00
|
|
|
it('should copy the file', function(done) {
|
|
|
|
this.Fs.createWriteStream = sinon.stub().returns({
|
2019-12-16 06:20:22 -05:00
|
|
|
on(event, handler) {
|
2019-12-16 06:20:29 -05:00
|
|
|
if (event === 'finish') {
|
|
|
|
return process.nextTick(handler)
|
|
|
|
}
|
2019-12-16 06:20:22 -05:00
|
|
|
}
|
2019-12-16 06:20:29 -05:00
|
|
|
})
|
|
|
|
return this.FSPersistorManager.sendFile(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.name2,
|
|
|
|
err => {
|
|
|
|
this.Fs.createReadStream.calledWith(this.name2).should.equal(true)
|
|
|
|
this.Fs.createWriteStream
|
|
|
|
.calledWith(`${this.location}/${this.name1Filtered}`)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
2019-12-16 06:20:22 -05:00
|
|
|
}
|
2019-12-16 06:20:29 -05:00
|
|
|
)
|
|
|
|
})
|
2019-12-16 06:20:22 -05:00
|
|
|
|
2019-12-16 06:20:29 -05:00
|
|
|
return it('should return an error if the file cannot be stored', function(done) {
|
|
|
|
this.Fs.createWriteStream = sinon.stub().returns({
|
|
|
|
on: (event, handler) => {
|
|
|
|
if (event === 'error') {
|
|
|
|
return process.nextTick(() => {
|
|
|
|
return handler(this.error)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return this.FSPersistorManager.sendFile(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.name2,
|
|
|
|
err => {
|
|
|
|
this.Fs.createReadStream.calledWith(this.name2).should.equal(true)
|
|
|
|
this.Fs.createWriteStream
|
|
|
|
.calledWith(`${this.location}/${this.name1Filtered}`)
|
|
|
|
.should.equal(true)
|
|
|
|
err.should.equal(this.error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
2019-12-16 06:20:22 -05:00
|
|
|
|
2019-12-16 06:20:29 -05:00
|
|
|
describe('sendStream', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
this.FSPersistorManager.sendFile = sinon.stub().callsArgWith(3)
|
|
|
|
this.LocalFileWriter.writeStream.callsArgWith(2, null, this.name1)
|
|
|
|
this.LocalFileWriter.deleteFile.callsArg(1)
|
|
|
|
return (this.SourceStream = { on() {} })
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should sent stream to LocalFileWriter', function(done) {
|
|
|
|
return this.FSPersistorManager.sendStream(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.SourceStream,
|
|
|
|
() => {
|
|
|
|
this.LocalFileWriter.writeStream
|
|
|
|
.calledWith(this.SourceStream)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return the error from LocalFileWriter', function(done) {
|
|
|
|
this.LocalFileWriter.writeStream.callsArgWith(2, this.error)
|
|
|
|
return this.FSPersistorManager.sendStream(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.SourceStream,
|
|
|
|
err => {
|
|
|
|
err.should.equal(this.error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should send the file to the filestore', function(done) {
|
|
|
|
this.LocalFileWriter.writeStream.callsArgWith(2)
|
|
|
|
return this.FSPersistorManager.sendStream(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.SourceStream,
|
|
|
|
err => {
|
|
|
|
this.FSPersistorManager.sendFile.called.should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
2019-12-16 06:20:22 -05:00
|
|
|
|
2019-12-16 06:20:29 -05:00
|
|
|
describe('getFileStream', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
return (this.opts = {})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should use correct file location', function(done) {
|
|
|
|
this.FSPersistorManager.getFileStream(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.opts,
|
|
|
|
(err, res) => {}
|
|
|
|
)
|
|
|
|
this.Fs.open
|
|
|
|
.calledWith(`${this.location}/${this.name1Filtered}`)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('with start and end options', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
2019-12-16 06:20:29 -05:00
|
|
|
this.fd = 2019
|
|
|
|
this.opts_in = { start: 0, end: 8 }
|
|
|
|
this.opts = { start: 0, end: 8, fd: this.fd }
|
|
|
|
return this.Fs.open.callsArgWith(2, null, this.fd)
|
|
|
|
})
|
2019-12-16 06:20:22 -05:00
|
|
|
|
|
|
|
return it('should pass the options to createReadStream', function(done) {
|
2019-12-16 06:20:29 -05:00
|
|
|
this.FSPersistorManager.getFileStream(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.opts_in,
|
|
|
|
(err, res) => {}
|
|
|
|
)
|
|
|
|
this.Fs.createReadStream.calledWith(null, this.opts).should.equal(true)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return describe('error conditions', function() {
|
|
|
|
describe('when the file does not exist', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
2019-12-16 06:20:29 -05:00
|
|
|
this.fakeCode = 'ENOENT'
|
|
|
|
const err = new Error()
|
|
|
|
err.code = this.fakeCode
|
|
|
|
return this.Fs.open.callsArgWith(2, err, null)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should give a NotFoundError', function(done) {
|
|
|
|
return this.FSPersistorManager.getFileStream(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.opts,
|
|
|
|
(err, res) => {
|
|
|
|
expect(res).to.equal(null)
|
|
|
|
expect(err).to.not.equal(null)
|
|
|
|
expect(err instanceof this.Errors.NotFoundError).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return describe('when some other error happens', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
2019-12-16 06:20:29 -05:00
|
|
|
this.fakeCode = 'SOMETHINGHORRIBLE'
|
|
|
|
const err = new Error()
|
|
|
|
err.code = this.fakeCode
|
|
|
|
return this.Fs.open.callsArgWith(2, err, null)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should give an Error', function(done) {
|
|
|
|
return this.FSPersistorManager.getFileStream(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.opts,
|
|
|
|
(err, res) => {
|
|
|
|
expect(res).to.equal(null)
|
|
|
|
expect(err).to.not.equal(null)
|
|
|
|
expect(err instanceof Error).to.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('getFileSize', function() {
|
|
|
|
it('should return the file size', function(done) {
|
|
|
|
const expectedFileSize = 75382
|
|
|
|
this.Fs.stat.yields(new Error('fs.stat got unexpected arguments'))
|
|
|
|
this.Fs.stat
|
|
|
|
.withArgs(`${this.location}/${this.name1Filtered}`)
|
|
|
|
.yields(null, { size: expectedFileSize })
|
|
|
|
|
|
|
|
return this.FSPersistorManager.getFileSize(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, fileSize) => {
|
|
|
|
if (err != null) {
|
|
|
|
return done(err)
|
|
|
|
}
|
|
|
|
expect(fileSize).to.equal(expectedFileSize)
|
|
|
|
return done()
|
2019-12-16 06:20:22 -05:00
|
|
|
}
|
2019-12-16 06:20:29 -05:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should throw a NotFoundError if the file does not exist', function(done) {
|
|
|
|
const error = new Error()
|
|
|
|
error.code = 'ENOENT'
|
|
|
|
this.Fs.stat.yields(error)
|
|
|
|
|
|
|
|
return this.FSPersistorManager.getFileSize(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, fileSize) => {
|
|
|
|
expect(err).to.be.instanceof(this.Errors.NotFoundError)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should rethrow any other error', function(done) {
|
|
|
|
const error = new Error()
|
|
|
|
this.Fs.stat.yields(error)
|
|
|
|
|
|
|
|
return this.FSPersistorManager.getFileSize(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, fileSize) => {
|
|
|
|
expect(err).to.equal(error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('copyFile', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
2019-12-16 06:20:29 -05:00
|
|
|
this.ReadStream = {
|
2019-12-16 06:20:22 -05:00
|
|
|
on() {},
|
2019-12-16 06:20:29 -05:00
|
|
|
pipe: sinon.stub()
|
|
|
|
}
|
|
|
|
this.WriteStream = { on() {} }
|
|
|
|
this.Fs.createReadStream.returns(this.ReadStream)
|
|
|
|
return this.Fs.createWriteStream.returns(this.WriteStream)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should open the source for reading', function(done) {
|
|
|
|
this.FSPersistorManager.copyFile(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.name2,
|
|
|
|
function() {}
|
|
|
|
)
|
|
|
|
this.Fs.createReadStream
|
|
|
|
.calledWith(`${this.location}/${this.name1Filtered}`)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should open the target for writing', function(done) {
|
|
|
|
this.FSPersistorManager.copyFile(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.name2,
|
|
|
|
function() {}
|
|
|
|
)
|
|
|
|
this.Fs.createWriteStream
|
|
|
|
.calledWith(`${this.location}/${this.name2}`)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('Should pipe the source to the target', function(done) {
|
|
|
|
this.FSPersistorManager.copyFile(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
this.name2,
|
|
|
|
function() {}
|
|
|
|
)
|
|
|
|
this.ReadStream.pipe.calledWith(this.WriteStream).should.equal(true)
|
|
|
|
return done()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('deleteFile', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
2019-12-16 06:20:29 -05:00
|
|
|
return this.Fs.unlink.callsArgWith(1, this.error)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should call unlink with correct options', function(done) {
|
|
|
|
return this.FSPersistorManager.deleteFile(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
err => {
|
|
|
|
this.Fs.unlink
|
|
|
|
.calledWith(`${this.location}/${this.name1Filtered}`)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('Should propogate the error', function(done) {
|
|
|
|
return this.FSPersistorManager.deleteFile(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
err => {
|
|
|
|
err.should.equal(this.error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('deleteDirectory', function() {
|
2019-12-16 06:20:22 -05:00
|
|
|
beforeEach(function() {
|
2019-12-16 06:20:29 -05:00
|
|
|
return this.Rimraf.callsArgWith(1, this.error)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should call rmdir(rimraf) with correct options', function(done) {
|
|
|
|
return this.FSPersistorManager.deleteDirectory(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
err => {
|
|
|
|
this.Rimraf.calledWith(
|
|
|
|
`${this.location}/${this.name1Filtered}`
|
|
|
|
).should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('Should propogate the error', function(done) {
|
|
|
|
return this.FSPersistorManager.deleteDirectory(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
err => {
|
|
|
|
err.should.equal(this.error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
2019-12-16 06:20:22 -05:00
|
|
|
|
2019-12-16 06:20:29 -05:00
|
|
|
describe('checkIfFileExists', function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
return this.Fs.exists.callsArgWith(1, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should call exists with correct options', function(done) {
|
|
|
|
return this.FSPersistorManager.checkIfFileExists(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
exists => {
|
|
|
|
this.Fs.exists
|
|
|
|
.calledWith(`${this.location}/${this.name1Filtered}`)
|
|
|
|
.should.equal(true)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
2019-12-16 06:20:22 -05:00
|
|
|
|
|
|
|
// fs.exists simply returns false on any error, so...
|
2019-12-16 06:20:29 -05:00
|
|
|
it('should not return an error', function(done) {
|
|
|
|
return this.FSPersistorManager.checkIfFileExists(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, exists) => {
|
|
|
|
expect(err).to.be.null
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('Should return true for existing files', function(done) {
|
|
|
|
this.Fs.exists.callsArgWith(1, true)
|
|
|
|
return this.FSPersistorManager.checkIfFileExists(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, exists) => {
|
|
|
|
exists.should.be.true
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('Should return false for non-existing files', function(done) {
|
|
|
|
this.Fs.exists.callsArgWith(1, false)
|
|
|
|
return this.FSPersistorManager.checkIfFileExists(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, exists) => {
|
|
|
|
exists.should.be.false
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return describe('directorySize', function() {
|
|
|
|
it('should propogate the error', function(done) {
|
|
|
|
this.Fs.readdir.callsArgWith(1, this.error)
|
|
|
|
return this.FSPersistorManager.directorySize(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, totalsize) => {
|
|
|
|
err.should.equal(this.error)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should sum directory files size', function(done) {
|
|
|
|
this.Fs.readdir.callsArgWith(1, null, [
|
|
|
|
{ file1: 'file1' },
|
|
|
|
{ file2: 'file2' }
|
|
|
|
])
|
|
|
|
this.Fs.fstatSync.returns({ size: 1024 })
|
|
|
|
return this.FSPersistorManager.directorySize(
|
|
|
|
this.location,
|
|
|
|
this.name1,
|
|
|
|
(err, totalsize) => {
|
|
|
|
expect(totalsize).to.equal(2048)
|
|
|
|
return done()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|