mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
[filestore] convert to ES modules GitOrigin-RevId: 404905973548bb6e437fff66b368e87be8249b73
258 lines
6.7 KiB
JavaScript
258 lines
6.7 KiB
JavaScript
import sinon from 'sinon'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import Errors from '../../../app/js/Errors.js'
|
|
|
|
const modulePath = '../../../app/js/FileController.js'
|
|
|
|
describe('FileController', () => {
|
|
let FileHandler, LocalFileWriter, FileController, req, res, next, stream
|
|
const settings = {
|
|
s3: {
|
|
buckets: {
|
|
template_files: 'template_files',
|
|
},
|
|
},
|
|
}
|
|
const fileSize = 1234
|
|
const fileStream = {
|
|
destroy() {},
|
|
}
|
|
const projectId = 'projectId'
|
|
const fileId = 'file_id'
|
|
const bucket = 'template_files'
|
|
const key = `${projectId}/${fileId}`
|
|
const error = new Error('incorrect utensil')
|
|
|
|
beforeEach(async () => {
|
|
FileHandler = {
|
|
getFile: sinon.stub().yields(null, fileStream),
|
|
getFileSize: sinon.stub().yields(null, fileSize),
|
|
insertFile: sinon.stub().yields(),
|
|
getRedirectUrl: sinon.stub().yields(null, null),
|
|
}
|
|
|
|
LocalFileWriter = {}
|
|
stream = {
|
|
pipeline: sinon.stub(),
|
|
}
|
|
|
|
vi.doMock('../../../app/js/LocalFileWriter', () => ({
|
|
default: LocalFileWriter,
|
|
}))
|
|
|
|
vi.doMock('../../../app/js/FileHandler', () => ({
|
|
default: FileHandler,
|
|
}))
|
|
|
|
vi.doMock('../../../app/js/Errors', () => ({
|
|
default: Errors,
|
|
}))
|
|
|
|
vi.doMock('stream', () => stream)
|
|
|
|
vi.doMock('@overleaf/settings', () => ({
|
|
default: settings,
|
|
}))
|
|
|
|
vi.doMock('@overleaf/metrics', () => ({
|
|
default: {
|
|
inc() {},
|
|
},
|
|
}))
|
|
|
|
FileController = (await import(modulePath)).default
|
|
|
|
req = {
|
|
key,
|
|
bucket,
|
|
project_id: projectId,
|
|
query: {},
|
|
params: {
|
|
project_id: projectId,
|
|
file_id: fileId,
|
|
},
|
|
headers: {},
|
|
requestLogger: {
|
|
setMessage: sinon.stub(),
|
|
addFields: sinon.stub(),
|
|
},
|
|
}
|
|
|
|
res = {
|
|
set: sinon.stub().returnsThis(),
|
|
sendStatus: sinon.stub().returnsThis(),
|
|
status: sinon.stub().returnsThis(),
|
|
}
|
|
|
|
next = sinon.stub()
|
|
})
|
|
|
|
describe('getFile', () => {
|
|
it('should try and get a redirect url first', () => {
|
|
FileController.getFile(req, res, next)
|
|
expect(FileHandler.getRedirectUrl).to.have.been.calledWith(bucket, key)
|
|
})
|
|
|
|
it('should pipe the stream', () => {
|
|
FileController.getFile(req, res, next)
|
|
expect(stream.pipeline).to.have.been.calledWith(fileStream, res)
|
|
})
|
|
|
|
it('should send a 200 if the cacheWarm param is true', async () => {
|
|
req.query.cacheWarm = true
|
|
await new Promise(resolve => {
|
|
res.sendStatus = statusCode => {
|
|
expect(statusCode).to.equal(200)
|
|
resolve()
|
|
}
|
|
FileController.getFile(req, res, next)
|
|
})
|
|
})
|
|
|
|
it('should send an error if there is a problem', () => {
|
|
FileHandler.getFile.yields(error)
|
|
FileController.getFile(req, res, next)
|
|
expect(next).to.have.been.calledWith(error)
|
|
})
|
|
|
|
describe('with a redirect url', () => {
|
|
const redirectUrl = 'https://wombat.potato/giraffe'
|
|
|
|
beforeEach(() => {
|
|
FileHandler.getRedirectUrl.yields(null, redirectUrl)
|
|
res.redirect = sinon.stub()
|
|
})
|
|
|
|
it('should redirect', () => {
|
|
FileController.getFile(req, res, next)
|
|
expect(res.redirect).to.have.been.calledWith(redirectUrl)
|
|
})
|
|
|
|
it('should not get a file stream', () => {
|
|
FileController.getFile(req, res, next)
|
|
expect(FileHandler.getFile).not.to.have.been.called
|
|
})
|
|
|
|
describe('when there is an error getting the redirect url', () => {
|
|
beforeEach(() => {
|
|
FileHandler.getRedirectUrl.yields(new Error('wombat herding error'))
|
|
})
|
|
|
|
it('should not redirect', () => {
|
|
FileController.getFile(req, res, next)
|
|
expect(res.redirect).not.to.have.been.called
|
|
})
|
|
|
|
it('should not return an error', () => {
|
|
FileController.getFile(req, res, next)
|
|
expect(next).not.to.have.been.called
|
|
})
|
|
|
|
it('should proxy the file', () => {
|
|
FileController.getFile(req, res, next)
|
|
expect(FileHandler.getFile).to.have.been.calledWith(bucket, key)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('with a range header', () => {
|
|
let expectedOptions
|
|
|
|
beforeEach(() => {
|
|
expectedOptions = {
|
|
bucket,
|
|
key,
|
|
format: undefined,
|
|
style: undefined,
|
|
}
|
|
})
|
|
|
|
it('should pass range options to FileHandler', () => {
|
|
req.headers.range = 'bytes=0-8'
|
|
expectedOptions.start = 0
|
|
expectedOptions.end = 8
|
|
|
|
FileController.getFile(req, res, next)
|
|
expect(FileHandler.getFile).to.have.been.calledWith(
|
|
bucket,
|
|
key,
|
|
expectedOptions
|
|
)
|
|
})
|
|
|
|
it('should ignore an invalid range header', () => {
|
|
req.headers.range = 'potato'
|
|
FileController.getFile(req, res, next)
|
|
expect(FileHandler.getFile).to.have.been.calledWith(
|
|
bucket,
|
|
key,
|
|
expectedOptions
|
|
)
|
|
})
|
|
|
|
it("should ignore any type other than 'bytes'", () => {
|
|
req.headers.range = 'wombats=0-8'
|
|
FileController.getFile(req, res, next)
|
|
expect(FileHandler.getFile).to.have.been.calledWith(
|
|
bucket,
|
|
key,
|
|
expectedOptions
|
|
)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('getFileHead', () => {
|
|
it('should return the file size in a Content-Length header', async () => {
|
|
await new Promise(resolve => {
|
|
res.end = () => {
|
|
expect(res.status).to.have.been.calledWith(200)
|
|
expect(res.set).to.have.been.calledWith('Content-Length', fileSize)
|
|
resolve()
|
|
}
|
|
|
|
FileController.getFileHead(req, res, next)
|
|
})
|
|
})
|
|
|
|
it('should return a 404 is the file is not found', async () => {
|
|
await new Promise(resolve => {
|
|
FileHandler.getFileSize.yields(
|
|
new Errors.NotFoundError({ message: 'not found', info: {} })
|
|
)
|
|
|
|
res.sendStatus = code => {
|
|
expect(code).to.equal(404)
|
|
resolve()
|
|
}
|
|
|
|
FileController.getFileHead(req, res, next)
|
|
})
|
|
})
|
|
|
|
it('should send an error on internal errors', () => {
|
|
FileHandler.getFileSize.yields(error)
|
|
|
|
FileController.getFileHead(req, res, next)
|
|
expect(next).to.have.been.calledWith(error)
|
|
})
|
|
})
|
|
|
|
describe('insertFile', () => {
|
|
it('should send bucket name key and res to FileHandler', async () => {
|
|
await new Promise(resolve => {
|
|
res.sendStatus = code => {
|
|
expect(FileHandler.insertFile).to.have.been.calledWith(
|
|
bucket,
|
|
key,
|
|
req
|
|
)
|
|
expect(code).to.equal(200)
|
|
resolve()
|
|
}
|
|
FileController.insertFile(req, res, next)
|
|
})
|
|
})
|
|
})
|
|
})
|