Merge pull request #151 from overleaf/jpa-bulk-dependency-upgrades

[misc] bulk dependency upgrades
This commit is contained in:
Jakob Ackermann 2021-07-15 15:42:54 +02:00 committed by GitHub
commit 9d790f4eda
33 changed files with 1475 additions and 1568 deletions

View file

@ -3,9 +3,9 @@
// https://github.com/sharelatex/sharelatex-dev-environment // https://github.com/sharelatex/sharelatex-dev-environment
{ {
"extends": [ "extends": [
"eslint:recommended",
"standard", "standard",
"prettier", "prettier"
"prettier/standard"
], ],
"parserOptions": { "parserOptions": {
"ecmaVersion": 2018 "ecmaVersion": 2018
@ -20,6 +20,19 @@
"mocha": true "mocha": true
}, },
"rules": { "rules": {
// TODO(das7pad): remove overrides after fixing all the violations manually (https://github.com/overleaf/issues/issues/3882#issuecomment-878999671)
// START of temporary overrides
"array-callback-return": "off",
"no-dupe-else-if": "off",
"no-var": "off",
"no-empty": "off",
"node/handle-callback-err": "off",
"no-loss-of-precision": "off",
"node/no-callback-literal": "off",
"node/no-path-concat": "off",
"prefer-regex-literals": "off",
// END of temporary overrides
// Swap the no-unused-expressions rule with a more chai-friendly one // Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0, "no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error", "chai-friendly/no-unused-expressions": "error",

View file

@ -20,4 +20,4 @@ updates:
# future if we reorganise teams # future if we reorganise teams
labels: labels:
- "dependencies" - "dependencies"
- "Team-Magma" - "type:maintenance"

View file

@ -1 +1 @@
12.20.1 12.22.3

View file

@ -2,6 +2,10 @@
# Instead run bin/update_build_scripts from # Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment # https://github.com/sharelatex/sharelatex-dev-environment
{ {
"arrowParens": "avoid",
"semi": false, "semi": false,
"singleQuote": true "singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
} }

View file

@ -2,7 +2,7 @@
# Instead run bin/update_build_scripts from # Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment # https://github.com/sharelatex/sharelatex-dev-environment
FROM node:12.20.1 as base FROM node:12.22.3 as base
WORKDIR /app WORKDIR /app
COPY install_deps.sh /app COPY install_deps.sh /app

View file

@ -4,7 +4,7 @@ Metrics.initialize(process.env.METRICS_APP_NAME || 'filestore')
const logger = require('logger-sharelatex') const logger = require('logger-sharelatex')
logger.initialize(process.env.METRICS_APP_NAME || 'filestore') logger.initialize(process.env.METRICS_APP_NAME || 'filestore')
const settings = require('settings-sharelatex') const settings = require('@overleaf/settings')
const express = require('express') const express = require('express')
const bodyParser = require('body-parser') const bodyParser = require('body-parser')
@ -140,7 +140,7 @@ const host = '0.0.0.0'
if (!module.parent) { if (!module.parent) {
// Called directly // Called directly
app.listen(port, host, (error) => { app.listen(port, host, error => {
if (error) { if (error) {
logger.error('Error starting Filestore', error) logger.error('Error starting Filestore', error)
throw error throw error
@ -153,7 +153,7 @@ process
.on('unhandledRejection', (reason, p) => { .on('unhandledRejection', (reason, p) => {
logger.err(reason, 'Unhandled Rejection at Promise', p) logger.err(reason, 'Unhandled Rejection at Promise', p)
}) })
.on('uncaughtException', (err) => { .on('uncaughtException', err => {
logger.err(err, 'Uncaught Exception thrown') logger.err(err, 'Uncaught Exception thrown')
process.exit(1) process.exit(1)
}) })

View file

@ -11,7 +11,7 @@ class FailedCommandError extends OError {
constructor(command, code, stdout, stderr) { constructor(command, code, stdout, stderr) {
super('command failed with error exit code', { super('command failed with error exit code', {
command, command,
code code,
}) })
this.stdout = stdout this.stdout = stdout
this.stderr = stderr this.stderr = stderr
@ -26,5 +26,5 @@ module.exports = {
HealthCheckError, HealthCheckError,
TimeoutError, TimeoutError,
InvalidParametersError, InvalidParametersError,
...Errors ...Errors,
} }

View file

@ -14,7 +14,7 @@ module.exports = {
copyFile, copyFile,
deleteFile, deleteFile,
deleteProject, deleteProject,
directorySize directorySize,
} }
function getFile(req, res, next) { function getFile(req, res, next) {
@ -24,7 +24,7 @@ function getFile(req, res, next) {
key, key,
bucket, bucket,
format, format,
style style,
} }
metrics.inc('getFile') metrics.inc('getFile')
@ -34,7 +34,7 @@ function getFile(req, res, next) {
bucket, bucket,
format, format,
style, style,
cacheWarm: req.query.cacheWarm cacheWarm: req.query.cacheWarm,
}) })
if (req.headers.range) { if (req.headers.range) {
@ -70,7 +70,7 @@ function getFile(req, res, next) {
return res.sendStatus(200).end() return res.sendStatus(200).end()
} }
pipeline(fileStream, res, (err) => { pipeline(fileStream, res, err => {
if (err && err.code === 'ERR_STREAM_PREMATURE_CLOSE') { if (err && err.code === 'ERR_STREAM_PREMATURE_CLOSE') {
res.end() res.end()
} else if (err) { } else if (err) {
@ -134,13 +134,13 @@ function copyFile(req, res, next) {
key, key,
bucket, bucket,
oldProject_id: oldProjectId, oldProject_id: oldProjectId,
oldFile_id: oldFileId oldFile_id: oldFileId,
}) })
req.requestLogger.setMessage('copying file') req.requestLogger.setMessage('copying file')
PersistorManager.copyObject(bucket, `${oldProjectId}/${oldFileId}`, key) PersistorManager.copyObject(bucket, `${oldProjectId}/${oldFileId}`, key)
.then(() => res.sendStatus(200)) .then(() => res.sendStatus(200))
.catch((err) => { .catch(err => {
if (err) { if (err) {
if (err instanceof Errors.NotFoundError) { if (err instanceof Errors.NotFoundError) {
res.sendStatus(404) res.sendStatus(404)

View file

@ -1,5 +1,5 @@
const metrics = require('@overleaf/metrics') const metrics = require('@overleaf/metrics')
const Settings = require('settings-sharelatex') const Settings = require('@overleaf/settings')
const { callbackify } = require('util') const { callbackify } = require('util')
const safeExec = require('./SafeExec').promises const safeExec = require('./SafeExec').promises
@ -16,8 +16,8 @@ module.exports = {
promises: { promises: {
convert, convert,
thumbnail, thumbnail,
preview preview,
} },
} }
async function convert(sourcePath, requestedFormat) { async function convert(sourcePath, requestedFormat) {
@ -29,7 +29,7 @@ async function convert(sourcePath, requestedFormat) {
'-flatten', '-flatten',
'-density', '-density',
'300', '300',
`${sourcePath}[0]` `${sourcePath}[0]`,
]) ])
} }
@ -46,7 +46,7 @@ async function thumbnail(sourcePath) {
`pdf:fit-page=${width}`, `pdf:fit-page=${width}`,
`${sourcePath}[0]`, `${sourcePath}[0]`,
'-resize', '-resize',
width width,
]) ])
} }
@ -63,14 +63,14 @@ async function preview(sourcePath) {
`pdf:fit-page=${width}`, `pdf:fit-page=${width}`,
`${sourcePath}[0]`, `${sourcePath}[0]`,
'-resize', '-resize',
width width,
]) ])
} }
async function _convert(sourcePath, requestedFormat, command) { async function _convert(sourcePath, requestedFormat, command) {
if (!APPROVED_FORMATS.includes(requestedFormat)) { if (!APPROVED_FORMATS.includes(requestedFormat)) {
throw new ConversionError('invalid format requested', { throw new ConversionError('invalid format requested', {
format: requestedFormat format: requestedFormat,
}) })
} }
@ -83,7 +83,7 @@ async function _convert(sourcePath, requestedFormat, command) {
try { try {
await safeExec(command, { await safeExec(command, {
killSignal: KILL_SIGNAL, killSignal: KILL_SIGNAL,
timeout: FOURTY_SECONDS timeout: FOURTY_SECONDS,
}) })
} catch (err) { } catch (err) {
throw new ConversionError( throw new ConversionError(

View file

@ -1,4 +1,4 @@
const Settings = require('settings-sharelatex') const Settings = require('@overleaf/settings')
const { callbackify } = require('util') const { callbackify } = require('util')
const fs = require('fs') const fs = require('fs')
const PersistorManager = require('./PersistorManager') const PersistorManager = require('./PersistorManager')
@ -23,8 +23,8 @@ module.exports = {
deleteFile, deleteFile,
deleteProject, deleteProject,
getFileSize, getFileSize,
getDirectorySize getDirectorySize,
} },
} }
async function insertFile(bucket, key, stream) { async function insertFile(bucket, key, stream) {
@ -33,7 +33,7 @@ async function insertFile(bucket, key, stream) {
throw new InvalidParametersError('key does not match validation regex', { throw new InvalidParametersError('key does not match validation regex', {
bucket, bucket,
key, key,
convertedKey convertedKey,
}) })
} }
if (Settings.enableConversions) { if (Settings.enableConversions) {
@ -48,7 +48,7 @@ async function deleteFile(bucket, key) {
throw new InvalidParametersError('key does not match validation regex', { throw new InvalidParametersError('key does not match validation regex', {
bucket, bucket,
key, key,
convertedKey convertedKey,
}) })
} }
const jobs = [PersistorManager.deleteObject(bucket, key)] const jobs = [PersistorManager.deleteObject(bucket, key)]
@ -62,7 +62,7 @@ async function deleteProject(bucket, key) {
if (!key.match(/^[0-9a-f]{24}\//i)) { if (!key.match(/^[0-9a-f]{24}\//i)) {
throw new InvalidParametersError('key does not match validation regex', { throw new InvalidParametersError('key does not match validation regex', {
bucket, bucket,
key key,
}) })
} }
await PersistorManager.deleteDirectory(bucket, key) await PersistorManager.deleteDirectory(bucket, key)
@ -172,7 +172,7 @@ async function _convertFile(bucket, originalKey, opts) {
throw new ConversionError('invalid file conversion options', { throw new ConversionError('invalid file conversion options', {
bucket, bucket,
originalKey, originalKey,
opts opts,
}) })
} }
let destPath let destPath

View file

@ -1,6 +1,6 @@
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const Settings = require('settings-sharelatex') const Settings = require('@overleaf/settings')
const streamBuffers = require('stream-buffers') const streamBuffers = require('stream-buffers')
const { promisify } = require('util') const { promisify } = require('util')
const Stream = require('stream') const Stream = require('stream')
@ -24,7 +24,7 @@ async function checkCanGetFiles() {
const bucket = Settings.filestore.stores.user_files const bucket = Settings.filestore.stores.user_files
const buffer = new streamBuffers.WritableStreamBuffer({ const buffer = new streamBuffers.WritableStreamBuffer({
initialSize: 100 initialSize: 100,
}) })
const sourceStream = await FileHandler.getFile(bucket, key, {}) const sourceStream = await FileHandler.getFile(bucket, key, {})
@ -62,8 +62,8 @@ module.exports = {
check(req, res, next) { check(req, res, next) {
Promise.all([checkCanGetFiles(), checkFileConvert()]) Promise.all([checkCanGetFiles(), checkFileConvert()])
.then(() => res.sendStatus(200)) .then(() => res.sendStatus(200))
.catch((err) => { .catch(err => {
next(err) next(err)
}) })
} },
} }

View file

@ -6,8 +6,8 @@ const safeExec = require('./SafeExec').promises
module.exports = { module.exports = {
compressPng: callbackify(compressPng), compressPng: callbackify(compressPng),
promises: { promises: {
compressPng compressPng,
} },
} }
async function compressPng(localPath, callback) { async function compressPng(localPath, callback) {
@ -15,7 +15,7 @@ async function compressPng(localPath, callback) {
const args = ['optipng', localPath] const args = ['optipng', localPath]
const opts = { const opts = {
timeout: 30 * 1000, timeout: 30 * 1000,
killSignal: 'SIGKILL' killSignal: 'SIGKILL',
} }
try { try {

View file

@ -1,4 +1,4 @@
const settings = require('settings-sharelatex') const settings = require('@overleaf/settings')
module.exports = { module.exports = {
getConvertedFolderKey, getConvertedFolderKey,
@ -8,7 +8,7 @@ module.exports = {
publicFileKeyMiddleware, publicFileKeyMiddleware,
publicProjectKeyMiddleware, publicProjectKeyMiddleware,
bucketFileKeyMiddleware, bucketFileKeyMiddleware,
templateFileKeyMiddleware templateFileKeyMiddleware,
} }
function getConvertedFolderKey(key) { function getConvertedFolderKey(key) {
@ -68,7 +68,7 @@ function templateFileKeyMiddleware(req, res, next) {
template_id: templateId, template_id: templateId,
format, format,
version, version,
sub_type: subType sub_type: subType,
} = req.params } = req.params
req.key = `${templateId}/v/${version}/${format}` req.key = `${templateId}/v/${version}/${format}`

View file

@ -4,16 +4,16 @@ const path = require('path')
const Stream = require('stream') const Stream = require('stream')
const { callbackify, promisify } = require('util') const { callbackify, promisify } = require('util')
const metrics = require('@overleaf/metrics') const metrics = require('@overleaf/metrics')
const Settings = require('settings-sharelatex') const Settings = require('@overleaf/settings')
const { WriteError } = require('./Errors') const { WriteError } = require('./Errors')
module.exports = { module.exports = {
promises: { promises: {
writeStream, writeStream,
deleteFile deleteFile,
}, },
writeStream: callbackify(writeStream), writeStream: callbackify(writeStream),
deleteFile: callbackify(deleteFile) deleteFile: callbackify(deleteFile),
} }
const pipeline = promisify(Stream.pipeline) const pipeline = promisify(Stream.pipeline)

View file

@ -1,4 +1,4 @@
const settings = require('settings-sharelatex') const settings = require('@overleaf/settings')
const persistorSettings = settings.filestore const persistorSettings = settings.filestore
persistorSettings.Metrics = require('@overleaf/metrics') persistorSettings.Metrics = require('@overleaf/metrics')

View file

@ -38,7 +38,7 @@ class RequestLogger {
metrics.timing('http_request', responseTime, null, { metrics.timing('http_request', responseTime, null, {
method: req.method, method: req.method,
status_code: res.statusCode, status_code: res.statusCode,
path: routePath.replace(/\//g, '_').replace(/:/g, '').slice(1) path: routePath.replace(/\//g, '_').replace(/:/g, '').slice(1),
}) })
} }
@ -57,14 +57,14 @@ class RequestLogger {
req.socket.socket && req.socket.socket &&
req.socket.socket.remoteAddress), req.socket.socket.remoteAddress),
'user-agent': req.headers['user-agent'], 'user-agent': req.headers['user-agent'],
'content-length': req.headers['content-length'] 'content-length': req.headers['content-length'],
}, },
res: { res: {
'content-length': res._headers['content-length'], 'content-length': res._headers['content-length'],
statusCode: res.statusCode, statusCode: res.statusCode,
'response-time': responseTime 'response-time': responseTime,
}, },
info: req.requestLogger._logInfo info: req.requestLogger._logInfo,
}, },
req.requestLogger._logMessage req.requestLogger._logMessage
) )

View file

@ -1,6 +1,6 @@
const lodashOnce = require('lodash.once') const lodashOnce = require('lodash.once')
const childProcess = require('child_process') const childProcess = require('child_process')
const Settings = require('settings-sharelatex') const Settings = require('@overleaf/settings')
const { ConversionsDisabledError, FailedCommandError } = require('./Errors') const { ConversionsDisabledError, FailedCommandError } = require('./Errors')
// execute a command in the same way as 'exec' but with a timeout that // execute a command in the same way as 'exec' but with a timeout that
@ -45,7 +45,7 @@ function safeExec(command, options, callback) {
new FailedCommandError('failed to kill process after timeout', { new FailedCommandError('failed to kill process after timeout', {
command, command,
options, options,
pid: child.pid pid: child.pid,
}) })
) )
} }
@ -62,13 +62,13 @@ function safeExec(command, options, callback) {
cleanup() cleanup()
}) })
child.on('error', (err) => { child.on('error', err => {
cleanup(err) cleanup(err)
}) })
child.stdout.on('data', (chunk) => { child.stdout.on('data', chunk => {
stdout += chunk stdout += chunk
}) })
child.stderr.on('data', (chunk) => { child.stderr.on('data', chunk => {
stderr += chunk stderr += chunk
}) })
} }

View file

@ -4,6 +4,6 @@ filestore
--docker-repos=gcr.io/overleaf-ops --docker-repos=gcr.io/overleaf-ops
--env-add=ENABLE_CONVERSIONS="true",USE_PROM_METRICS="true",AWS_S3_USER_FILES_BUCKET_NAME=fake_user_files,AWS_S3_TEMPLATE_FILES_BUCKET_NAME=fake_template_files,AWS_S3_PUBLIC_FILES_BUCKET_NAME=fake_public_files,GCS_USER_FILES_BUCKET_NAME=fake_userfiles,GCS_TEMPLATE_FILES_BUCKET_NAME=fake_templatefiles,GCS_PUBLIC_FILES_BUCKET_NAME=fake_publicfiles --env-add=ENABLE_CONVERSIONS="true",USE_PROM_METRICS="true",AWS_S3_USER_FILES_BUCKET_NAME=fake_user_files,AWS_S3_TEMPLATE_FILES_BUCKET_NAME=fake_template_files,AWS_S3_PUBLIC_FILES_BUCKET_NAME=fake_public_files,GCS_USER_FILES_BUCKET_NAME=fake_userfiles,GCS_TEMPLATE_FILES_BUCKET_NAME=fake_templatefiles,GCS_PUBLIC_FILES_BUCKET_NAME=fake_publicfiles
--env-pass-through= --env-pass-through=
--node-version=12.20.1 --node-version=12.22.3
--public-repo=True --public-repo=True
--script-version=3.8.0 --script-version=3.11.0

View file

@ -40,8 +40,8 @@ const settings = {
internal: { internal: {
filestore: { filestore: {
port: 3009, port: 3009,
host: process.env.LISTEN_ADDRESS || 'localhost' host: process.env.LISTEN_ADDRESS || 'localhost',
} },
}, },
filestore: { filestore: {
@ -57,13 +57,13 @@ const settings = {
? { ? {
apiEndpoint: process.env.GCS_API_ENDPOINT, apiEndpoint: process.env.GCS_API_ENDPOINT,
apiScheme: process.env.GCS_API_SCHEME, apiScheme: process.env.GCS_API_SCHEME,
projectId: process.env.GCS_PROJECT_ID projectId: process.env.GCS_PROJECT_ID,
} }
: undefined, : undefined,
unlockBeforeDelete: process.env.GCS_UNLOCK_BEFORE_DELETE === 'true', // unlock an event-based hold before deleting. default false unlockBeforeDelete: process.env.GCS_UNLOCK_BEFORE_DELETE === 'true', // unlock an event-based hold before deleting. default false
deletedBucketSuffix: process.env.GCS_DELETED_BUCKET_SUFFIX, // if present, copy file to another bucket on delete. default null deletedBucketSuffix: process.env.GCS_DELETED_BUCKET_SUFFIX, // if present, copy file to another bucket on delete. default null
deleteConcurrency: parseInt(process.env.GCS_DELETE_CONCURRENCY) || 50, deleteConcurrency: parseInt(process.env.GCS_DELETE_CONCURRENCY) || 50,
signedUrlExpiryInMs: parseInt(process.env.LINK_EXPIRY_TIMEOUT || 60000) signedUrlExpiryInMs: parseInt(process.env.LINK_EXPIRY_TIMEOUT || 60000),
}, },
s3: s3:
@ -76,7 +76,7 @@ const settings = {
partSize: process.env.AWS_S3_PARTSIZE || 100 * 1024 * 1024, partSize: process.env.AWS_S3_PARTSIZE || 100 * 1024 * 1024,
bucketCreds: process.env.S3_BUCKET_CREDENTIALS bucketCreds: process.env.S3_BUCKET_CREDENTIALS
? JSON.parse(process.env.S3_BUCKET_CREDENTIALS) ? JSON.parse(process.env.S3_BUCKET_CREDENTIALS)
: undefined : undefined,
} }
: undefined, : undefined,
@ -86,7 +86,7 @@ const settings = {
stores: { stores: {
user_files: process.env.USER_FILES_BUCKET_NAME, user_files: process.env.USER_FILES_BUCKET_NAME,
template_files: process.env.TEMPLATE_FILES_BUCKET_NAME, template_files: process.env.TEMPLATE_FILES_BUCKET_NAME,
public_files: process.env.PUBLIC_FILES_BUCKET_NAME public_files: process.env.PUBLIC_FILES_BUCKET_NAME,
}, },
fallback: process.env.FALLBACK_BACKEND fallback: process.env.FALLBACK_BACKEND
@ -95,28 +95,28 @@ const settings = {
// mapping of bucket names on the fallback, to bucket names on the primary. // mapping of bucket names on the fallback, to bucket names on the primary.
// e.g. { myS3UserFilesBucketName: 'myGoogleUserFilesBucketName' } // e.g. { myS3UserFilesBucketName: 'myGoogleUserFilesBucketName' }
buckets: JSON.parse(process.env.FALLBACK_BUCKET_MAPPING || '{}'), buckets: JSON.parse(process.env.FALLBACK_BUCKET_MAPPING || '{}'),
copyOnMiss: process.env.COPY_ON_MISS === 'true' copyOnMiss: process.env.COPY_ON_MISS === 'true',
} }
: undefined, : undefined,
allowRedirects: process.env.ALLOW_REDIRECTS === 'true' allowRedirects: process.env.ALLOW_REDIRECTS === 'true',
}, },
path: { path: {
// eslint-disable-next-line no-path-concat // eslint-disable-next-line no-path-concat
uploadFolder: Path.resolve(__dirname + '/../uploads') uploadFolder: Path.resolve(__dirname + '/../uploads'),
}, },
commands: { commands: {
// Any commands to wrap the convert utility in, for example ["nice"], or ["firejail", "--profile=/etc/firejail/convert.profile"] // Any commands to wrap the convert utility in, for example ["nice"], or ["firejail", "--profile=/etc/firejail/convert.profile"]
convertCommandPrefix: [] convertCommandPrefix: [],
}, },
enableConversions: process.env.ENABLE_CONVERSIONS === 'true', enableConversions: process.env.ENABLE_CONVERSIONS === 'true',
sentry: { sentry: {
dsn: process.env.SENTRY_DSN dsn: process.env.SENTRY_DSN,
} },
} }
// Filestore health check // Filestore health check
@ -125,7 +125,7 @@ const settings = {
if (process.env.HEALTH_CHECK_PROJECT_ID && process.env.HEALTH_CHECK_FILE_ID) { if (process.env.HEALTH_CHECK_PROJECT_ID && process.env.HEALTH_CHECK_FILE_ID) {
settings.health_check = { settings.health_check = {
project_id: process.env.HEALTH_CHECK_PROJECT_ID, project_id: process.env.HEALTH_CHECK_PROJECT_ID,
file_id: process.env.HEALTH_CHECK_FILE_ID file_id: process.env.HEALTH_CHECK_FILE_ID,
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -13,17 +13,20 @@
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP", "test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
"start": "node $NODE_APP_OPTIONS app.js", "start": "node $NODE_APP_OPTIONS app.js",
"nodemon": "nodemon --config nodemon.json", "nodemon": "nodemon --config nodemon.json",
"lint": "node_modules/.bin/eslint --max-warnings 0 .", "lint": "eslint --max-warnings 0 --format unix .",
"format": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --list-different", "format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --write", "format:fix": "prettier --write $PWD/'**/*.js'",
"test:acceptance:_run": "mocha --recursive --reporter spec --timeout 15000 --exit $@ test/acceptance/js", "test:acceptance:_run": "mocha --recursive --reporter spec --timeout 15000 --exit $@ test/acceptance/js",
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js" "test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"lint:fix": "eslint --fix ."
}, },
"dependencies": { "dependencies": {
"@overleaf/metrics": "^3.5.1", "@overleaf/metrics": "^3.5.1",
"@overleaf/o-error": "^3.0.0", "@overleaf/o-error": "^3.0.0",
"@overleaf/object-persistor": "https://github.com/overleaf/object-persistor/archive/8fbc9ed03206bfb54368578d22b7ac4f285baa25.tar.gz", "@overleaf/object-persistor": "https://github.com/overleaf/object-persistor/archive/8fbc9ed03206bfb54368578d22b7ac4f285baa25.tar.gz",
"@overleaf/settings": "^2.1.1",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"bunyan": "^1.8.15",
"express": "^4.17.1", "express": "^4.17.1",
"fast-crc32c": "^2.0.0", "fast-crc32c": "^2.0.0",
"glob": "^7.1.6", "glob": "^7.1.6",
@ -33,34 +36,29 @@
"range-parser": "^1.2.1", "range-parser": "^1.2.1",
"request": "^2.88.2", "request": "^2.88.2",
"request-promise-native": "^1.0.8", "request-promise-native": "^1.0.8",
"settings-sharelatex": "^1.1.0",
"stream-buffers": "~0.2.6", "stream-buffers": "~0.2.6",
"tiny-async-pool": "^1.1.0" "tiny-async-pool": "^1.1.0"
}, },
"devDependencies": { "devDependencies": {
"@google-cloud/storage": "^5.1.2", "@google-cloud/storage": "^5.1.2",
"aws-sdk": "^2.718.0", "aws-sdk": "^2.718.0",
"babel-eslint": "^10.1.0", "chai": "^4.2.0",
"bunyan": "^1.8.14",
"chai": "4.2.0",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"disrequire": "^1.1.0", "disrequire": "^1.1.0",
"eslint": "^6.8.0", "eslint": "^7.21.0",
"eslint-config-prettier": "^6.10.0", "eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^14.1.0", "eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.1.0", "eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.5.0", "eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.20.1", "eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^6.3.0", "eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.0.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2", "eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1", "mocha": "^8.3.2",
"mocha": "7.2.0",
"mongodb": "^3.5.9", "mongodb": "^3.5.9",
"prettier": "^2.0.0", "prettier": "^2.2.1",
"prettier-eslint": "^9.0.2", "prettier-eslint": "^9.0.2",
"prettier-eslint-cli": "^5.0.0",
"sandboxed-module": "2.0.4", "sandboxed-module": "2.0.4",
"sinon": "9.0.2", "sinon": "9.0.2",
"sinon-chai": "^3.5.0", "sinon-chai": "^3.5.0",

View file

@ -1,5 +1,5 @@
const logger = require('logger-sharelatex') const logger = require('logger-sharelatex')
const Settings = require('settings-sharelatex') const Settings = require('@overleaf/settings')
const fs = require('fs') const fs = require('fs')
const Path = require('path') const Path = require('path')
const { promisify } = require('util') const { promisify } = require('util')
@ -33,7 +33,7 @@ class FilestoreApp {
this.server = this.app.listen( this.server = this.app.listen(
Settings.internal.filestore.port, Settings.internal.filestore.port,
'localhost', 'localhost',
(err) => { err => {
if (err) { if (err) {
return reject(err) return reject(err)
} }
@ -82,7 +82,7 @@ class FilestoreApp {
secretAccessKey: Settings.filestore.s3.secret, secretAccessKey: Settings.filestore.s3.secret,
endpoint: Settings.filestore.s3.endpoint, endpoint: Settings.filestore.s3.endpoint,
s3ForcePathStyle: true, s3ForcePathStyle: true,
signatureVersion: 'v4' signatureVersion: 'v4',
}) })
while (true) { while (true) {
@ -91,7 +91,7 @@ class FilestoreApp {
.putObject({ .putObject({
Key: 'startup', Key: 'startup',
Body: '42', Body: '42',
Bucket: Settings.filestore.stores.user_files Bucket: Settings.filestore.stores.user_files,
}) })
.promise() .promise()
} catch (err) { } catch (err) {
@ -110,7 +110,7 @@ class FilestoreApp {
// unload the app, as we may be doing this on multiple runs with // unload the app, as we may be doing this on multiple runs with
// different settings, which affect startup in some cases // different settings, which affect startup in some cases
const files = await fsReaddir(Path.resolve(__dirname, '../../../app/js')) const files = await fsReaddir(Path.resolve(__dirname, '../../../app/js'))
files.forEach((file) => { files.forEach(file => {
disrequire(Path.resolve(__dirname, '../../../app/js', file)) disrequire(Path.resolve(__dirname, '../../../app/js', file))
}) })
disrequire(Path.resolve(__dirname, '../../../app')) disrequire(Path.resolve(__dirname, '../../../app'))

View file

@ -1,12 +1,12 @@
const chai = require('chai') const chai = require('chai')
const { expect } = chai const { expect } = chai
const fs = require('fs') const fs = require('fs')
const Settings = require('settings-sharelatex') const Settings = require('@overleaf/settings')
const Path = require('path') const Path = require('path')
const FilestoreApp = require('./FilestoreApp') const FilestoreApp = require('./FilestoreApp')
const TestHelper = require('./TestHelper') const TestHelper = require('./TestHelper')
const rp = require('request-promise-native').defaults({ const rp = require('request-promise-native').defaults({
resolveWithFullResponse: true resolveWithFullResponse: true,
}) })
const S3 = require('aws-sdk/clients/s3') const S3 = require('aws-sdk/clients/s3')
const Stream = require('stream') const Stream = require('stream')
@ -29,7 +29,7 @@ if (!process.env.AWS_ACCESS_KEY_ID) {
throw new Error('please provide credentials for the AWS S3 test server') throw new Error('please provide credentials for the AWS S3 test server')
} }
process.on('unhandledRejection', (e) => { process.on('unhandledRejection', e => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('** Unhandled Promise Rejection **\n', e) console.log('** Unhandled Promise Rejection **\n', e)
throw e throw e
@ -51,7 +51,7 @@ describe('Filestore', function () {
const badSockets = [] const badSockets = []
for (const socket of stdout.split('\n')) { for (const socket of stdout.split('\n')) {
const fields = socket.split(' ').filter((part) => part !== '') const fields = socket.split(' ').filter(part => part !== '')
if ( if (
fields.length > 2 && fields.length > 2 &&
parseInt(fields[1]) && parseInt(fields[1]) &&
@ -79,7 +79,7 @@ describe('Filestore', function () {
} }
// redefine the test suite for every available backend // redefine the test suite for every available backend
Object.keys(BackendSettings).forEach((backend) => { Object.keys(BackendSettings).forEach(backend => {
describe(backend, function () { describe(backend, function () {
let app, previousEgress, previousIngress, metricPrefix, projectId let app, previousEgress, previousIngress, metricPrefix, projectId
@ -150,7 +150,7 @@ describe('Filestore', function () {
constantFileContent = [ constantFileContent = [
'hello world', 'hello world',
`line 2 goes here ${Math.random()}`, `line 2 goes here ${Math.random()}`,
'there are 3 lines in all' 'there are 3 lines in all',
].join('\n') ].join('\n')
await fsWriteFile(localFileReadPath, constantFileContent) await fsWriteFile(localFileReadPath, constantFileContent)
@ -204,8 +204,8 @@ describe('Filestore', function () {
const options = { const options = {
uri: fileUrl, uri: fileUrl,
headers: { headers: {
Range: 'bytes=0-8' Range: 'bytes=0-8',
} },
} }
const res = await rp.get(options) const res = await rp.get(options)
expect(res.body).to.equal('hello wor') expect(res.body).to.equal('hello wor')
@ -215,8 +215,8 @@ describe('Filestore', function () {
const options = { const options = {
uri: fileUrl, uri: fileUrl,
headers: { headers: {
Range: 'bytes=4-10' Range: 'bytes=4-10',
} },
} }
const res = await rp.get(options) const res = await rp.get(options)
expect(res.body).to.equal('o world') expect(res.body).to.equal('o world')
@ -240,9 +240,9 @@ describe('Filestore', function () {
json: { json: {
source: { source: {
project_id: projectId, project_id: projectId,
file_id: fileId file_id: fileId,
} },
} },
} }
let response = await rp(opts) let response = await rp(opts)
expect(response.statusCode).to.equal(200) expect(response.statusCode).to.equal(200)
@ -288,8 +288,8 @@ describe('Filestore', function () {
const options = { const options = {
uri: fileUrl, uri: fileUrl,
headers: { headers: {
Range: 'bytes=0-8' Range: 'bytes=0-8',
} },
} }
await rp.get(options) await rp.get(options)
const metric = await TestHelper.getMetric( const metric = await TestHelper.getMetric(
@ -305,25 +305,25 @@ describe('Filestore', function () {
let fileIds, fileUrls, projectUrl let fileIds, fileUrls, projectUrl
const localFileReadPaths = [ const localFileReadPaths = [
'/tmp/filestore_acceptance_tests_file_read_1.txt', '/tmp/filestore_acceptance_tests_file_read_1.txt',
'/tmp/filestore_acceptance_tests_file_read_2.txt' '/tmp/filestore_acceptance_tests_file_read_2.txt',
] ]
const constantFileContents = [ const constantFileContents = [
[ [
'hello world', 'hello world',
`line 2 goes here ${Math.random()}`, `line 2 goes here ${Math.random()}`,
'there are 3 lines in all' 'there are 3 lines in all',
].join('\n'), ].join('\n'),
[ [
`for reference: ${Math.random()}`, `for reference: ${Math.random()}`,
'cats are the best animals', 'cats are the best animals',
'wombats are a close second' 'wombats are a close second',
].join('\n') ].join('\n'),
] ]
before(async function () { before(async function () {
return Promise.all([ return Promise.all([
fsWriteFile(localFileReadPaths[0], constantFileContents[0]), fsWriteFile(localFileReadPaths[0], constantFileContents[0]),
fsWriteFile(localFileReadPaths[1], constantFileContents[1]) fsWriteFile(localFileReadPaths[1], constantFileContents[1]),
]) ])
}) })
@ -332,25 +332,25 @@ describe('Filestore', function () {
fileIds = [ObjectId().toString(), ObjectId().toString()] fileIds = [ObjectId().toString(), ObjectId().toString()]
fileUrls = [ fileUrls = [
`${projectUrl}/file/${fileIds[0]}`, `${projectUrl}/file/${fileIds[0]}`,
`${projectUrl}/file/${fileIds[1]}` `${projectUrl}/file/${fileIds[1]}`,
] ]
const writeStreams = [ const writeStreams = [
request.post(fileUrls[0]), request.post(fileUrls[0]),
request.post(fileUrls[1]) request.post(fileUrls[1]),
] ]
const readStreams = [ const readStreams = [
fs.createReadStream(localFileReadPaths[0]), fs.createReadStream(localFileReadPaths[0]),
fs.createReadStream(localFileReadPaths[1]) fs.createReadStream(localFileReadPaths[1]),
] ]
// hack to consume the result to ensure the http request has been fully processed // hack to consume the result to ensure the http request has been fully processed
const resultStreams = [ const resultStreams = [
fs.createWriteStream('/dev/null'), fs.createWriteStream('/dev/null'),
fs.createWriteStream('/dev/null') fs.createWriteStream('/dev/null'),
] ]
return Promise.all([ return Promise.all([
pipeline(readStreams[0], writeStreams[0], resultStreams[0]), pipeline(readStreams[0], writeStreams[0], resultStreams[0]),
pipeline(readStreams[1], writeStreams[1], resultStreams[1]) pipeline(readStreams[1], writeStreams[1], resultStreams[1]),
]) ])
}) })
@ -433,7 +433,7 @@ describe('Filestore', function () {
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
// test is not 100% reliable, so repeat // test is not 100% reliable, so repeat
// create a new connection and have it time out before reading any data // create a new connection and have it time out before reading any data
await new Promise((resolve) => { await new Promise(resolve => {
const streamThatHangs = new Stream.PassThrough() const streamThatHangs = new Stream.PassThrough()
const stream = request({ url: fileUrl, timeout: 1000 }) const stream = request({ url: fileUrl, timeout: 1000 })
stream.pipe(streamThatHangs) stream.pipe(streamThatHangs)
@ -461,24 +461,24 @@ describe('Filestore', function () {
const s3ClientSettings = { const s3ClientSettings = {
credentials: { credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID, accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
}, },
endpoint: process.env.AWS_S3_ENDPOINT, endpoint: process.env.AWS_S3_ENDPOINT,
sslEnabled: false, sslEnabled: false,
s3ForcePathStyle: true s3ForcePathStyle: true,
} }
const s3 = new S3(s3ClientSettings) const s3 = new S3(s3ClientSettings)
await s3 await s3
.createBucket({ .createBucket({
Bucket: bucketName Bucket: bucketName,
}) })
.promise() .promise()
await s3 await s3
.upload({ .upload({
Bucket: bucketName, Bucket: bucketName,
Key: fileId, Key: fileId,
Body: constantFileContent Body: constantFileContent,
}) })
.promise() .promise()
}) })
@ -648,9 +648,9 @@ describe('Filestore', function () {
json: { json: {
source: { source: {
project_id: projectId, project_id: projectId,
file_id: fileId file_id: fileId,
} },
} },
} }
}) })
@ -752,9 +752,8 @@ describe('Filestore', function () {
describe('when sending a file', function () { describe('when sending a file', function () {
beforeEach(async function () { beforeEach(async function () {
const writeStream = request.post(fileUrl) const writeStream = request.post(fileUrl)
const readStream = streamifier.createReadStream( const readStream =
constantFileContent streamifier.createReadStream(constantFileContent)
)
// hack to consume the result to ensure the http request has been fully processed // hack to consume the result to ensure the http request has been fully processed
const resultStream = fs.createWriteStream('/dev/null') const resultStream = fs.createWriteStream('/dev/null')
await pipeline(readStream, writeStream, resultStream) await pipeline(readStream, writeStream, resultStream)

View file

@ -7,7 +7,7 @@ function s3Config() {
secret: process.env.AWS_SECRET_ACCESS_KEY, secret: process.env.AWS_SECRET_ACCESS_KEY,
endpoint: process.env.AWS_S3_ENDPOINT, endpoint: process.env.AWS_S3_ENDPOINT,
pathStyle: true, pathStyle: true,
partSize: 100 * 1024 * 1024 partSize: 100 * 1024 * 1024,
} }
} }
@ -15,7 +15,7 @@ function s3Stores() {
return { return {
user_files: process.env.AWS_S3_USER_FILES_BUCKET_NAME, user_files: process.env.AWS_S3_USER_FILES_BUCKET_NAME,
template_files: process.env.AWS_S3_TEMPLATE_FILES_BUCKET_NAME, template_files: process.env.AWS_S3_TEMPLATE_FILES_BUCKET_NAME,
public_files: process.env.AWS_S3_PUBLIC_FILES_BUCKET_NAME public_files: process.env.AWS_S3_PUBLIC_FILES_BUCKET_NAME,
} }
} }
@ -24,11 +24,11 @@ function gcsConfig() {
endpoint: { endpoint: {
apiEndpoint: process.env.GCS_API_ENDPOINT, apiEndpoint: process.env.GCS_API_ENDPOINT,
apiScheme: process.env.GCS_API_SCHEME, apiScheme: process.env.GCS_API_SCHEME,
projectId: 'fake' projectId: 'fake',
}, },
directoryKeyRegex: new RegExp('^[0-9a-fA-F]{24}/[0-9a-fA-F]{24}'), directoryKeyRegex: new RegExp('^[0-9a-fA-F]{24}/[0-9a-fA-F]{24}'),
unlockBeforeDelete: false, // fake-gcs does not support this unlockBeforeDelete: false, // fake-gcs does not support this
deletedBucketSuffix: '-deleted' deletedBucketSuffix: '-deleted',
} }
} }
@ -36,7 +36,7 @@ function gcsStores() {
return { return {
user_files: process.env.GCS_USER_FILES_BUCKET_NAME, user_files: process.env.GCS_USER_FILES_BUCKET_NAME,
template_files: process.env.GCS_TEMPLATE_FILES_BUCKET_NAME, template_files: process.env.GCS_TEMPLATE_FILES_BUCKET_NAME,
public_files: process.env.GCS_PUBLIC_FILES_BUCKET_NAME public_files: process.env.GCS_PUBLIC_FILES_BUCKET_NAME,
} }
} }
@ -44,7 +44,7 @@ function fsStores() {
return { return {
user_files: Path.resolve(__dirname, '../../../user_files'), user_files: Path.resolve(__dirname, '../../../user_files'),
public_files: Path.resolve(__dirname, '../../../public_files'), public_files: Path.resolve(__dirname, '../../../public_files'),
template_files: Path.resolve(__dirname, '../../../template_files') template_files: Path.resolve(__dirname, '../../../template_files'),
} }
} }
@ -52,24 +52,24 @@ function fallbackStores(primaryConfig, fallbackConfig) {
return { return {
[primaryConfig.user_files]: fallbackConfig.user_files, [primaryConfig.user_files]: fallbackConfig.user_files,
[primaryConfig.public_files]: fallbackConfig.public_files, [primaryConfig.public_files]: fallbackConfig.public_files,
[primaryConfig.template_files]: fallbackConfig.template_files [primaryConfig.template_files]: fallbackConfig.template_files,
} }
} }
module.exports = { module.exports = {
FSPersistor: { FSPersistor: {
backend: 'fs', backend: 'fs',
stores: fsStores() stores: fsStores(),
}, },
S3Persistor: { S3Persistor: {
backend: 's3', backend: 's3',
s3: s3Config(), s3: s3Config(),
stores: s3Stores() stores: s3Stores(),
}, },
GcsPersistor: { GcsPersistor: {
backend: 'gcs', backend: 'gcs',
gcs: gcsConfig(), gcs: gcsConfig(),
stores: gcsStores() stores: gcsStores(),
}, },
FallbackS3ToFSPersistor: { FallbackS3ToFSPersistor: {
backend: 's3', backend: 's3',
@ -77,8 +77,8 @@ module.exports = {
stores: s3Stores(), stores: s3Stores(),
fallback: { fallback: {
backend: 'fs', backend: 'fs',
buckets: fallbackStores(s3Stores(), fsStores()) buckets: fallbackStores(s3Stores(), fsStores()),
} },
}, },
FallbackFSToS3Persistor: { FallbackFSToS3Persistor: {
backend: 'fs', backend: 'fs',
@ -86,8 +86,8 @@ module.exports = {
stores: fsStores(), stores: fsStores(),
fallback: { fallback: {
backend: 's3', backend: 's3',
buckets: fallbackStores(fsStores(), s3Stores()) buckets: fallbackStores(fsStores(), s3Stores()),
} },
}, },
FallbackGcsToS3Persistor: { FallbackGcsToS3Persistor: {
backend: 'gcs', backend: 'gcs',
@ -96,8 +96,8 @@ module.exports = {
s3: s3Config(), s3: s3Config(),
fallback: { fallback: {
backend: 's3', backend: 's3',
buckets: fallbackStores(gcsStores(), s3Stores()) buckets: fallbackStores(gcsStores(), s3Stores()),
} },
}, },
FallbackS3ToGcsPersistor: { FallbackS3ToGcsPersistor: {
backend: 's3', backend: 's3',
@ -107,7 +107,7 @@ module.exports = {
gcs: gcsConfig(), gcs: gcsConfig(),
fallback: { fallback: {
backend: 'gcs', backend: 'gcs',
buckets: fallbackStores(s3Stores(), gcsStores()) buckets: fallbackStores(s3Stores(), gcsStores()),
} },
} },
} }

View file

@ -1,6 +1,6 @@
const streamifier = require('streamifier') const streamifier = require('streamifier')
const rp = require('request-promise-native').defaults({ const rp = require('request-promise-native').defaults({
resolveWithFullResponse: true resolveWithFullResponse: true,
}) })
const { expect } = require('chai') const { expect } = require('chai')
@ -11,7 +11,7 @@ module.exports = {
expectPersistorToHaveFile, expectPersistorToHaveFile,
expectPersistorNotToHaveFile, expectPersistorNotToHaveFile,
streamToString, streamToString,
getMetric getMetric,
} }
async function getMetric(filestoreUrl, metric) { async function getMetric(filestoreUrl, metric) {
@ -25,7 +25,7 @@ async function getMetric(filestoreUrl, metric) {
function streamToString(stream) { function streamToString(stream) {
const chunks = [] const chunks = []
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(chunk)) stream.on('data', chunk => chunks.push(chunk))
stream.on('error', reject) stream.on('error', reject)
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))) stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
stream.resume() stream.resume()

View file

@ -17,9 +17,9 @@ describe('FileController', function () {
const settings = { const settings = {
s3: { s3: {
buckets: { buckets: {
user_files: 'user_files' user_files: 'user_files',
} },
} },
} }
const fileSize = 1234 const fileSize = 1234
const fileStream = 'fileStream' const fileStream = 'fileStream'
@ -33,7 +33,7 @@ describe('FileController', function () {
PersistorManager = { PersistorManager = {
sendStream: sinon.stub().yields(), sendStream: sinon.stub().yields(),
copyObject: sinon.stub().resolves(), copyObject: sinon.stub().resolves(),
deleteObject: sinon.stub().yields() deleteObject: sinon.stub().yields(),
} }
FileHandler = { FileHandler = {
@ -43,12 +43,12 @@ describe('FileController', function () {
deleteProject: sinon.stub().yields(), deleteProject: sinon.stub().yields(),
insertFile: sinon.stub().yields(), insertFile: sinon.stub().yields(),
getDirectorySize: sinon.stub().yields(null, fileSize), getDirectorySize: sinon.stub().yields(null, fileSize),
getRedirectUrl: sinon.stub().yields(null, null) getRedirectUrl: sinon.stub().yields(null, null),
} }
LocalFileWriter = {} LocalFileWriter = {}
stream = { stream = {
pipeline: sinon.stub() pipeline: sinon.stub(),
} }
FileController = SandboxedModule.require(modulePath, { FileController = SandboxedModule.require(modulePath, {
@ -58,12 +58,12 @@ describe('FileController', function () {
'./PersistorManager': PersistorManager, './PersistorManager': PersistorManager,
'./Errors': Errors, './Errors': Errors,
stream: stream, stream: stream,
'settings-sharelatex': settings, '@overleaf/settings': settings,
'@overleaf/metrics': { '@overleaf/metrics': {
inc() {} inc() {},
}
}, },
globals: { console } },
globals: { console },
}) })
req = { req = {
@ -73,19 +73,19 @@ describe('FileController', function () {
query: {}, query: {},
params: { params: {
project_id: projectId, project_id: projectId,
file_id: fileId file_id: fileId,
}, },
headers: {}, headers: {},
requestLogger: { requestLogger: {
setMessage: sinon.stub(), setMessage: sinon.stub(),
addFields: sinon.stub() addFields: sinon.stub(),
} },
} }
res = { res = {
set: sinon.stub().returnsThis(), set: sinon.stub().returnsThis(),
sendStatus: sinon.stub().returnsThis(), sendStatus: sinon.stub().returnsThis(),
status: sinon.stub().returnsThis() status: sinon.stub().returnsThis(),
} }
next = sinon.stub() next = sinon.stub()
@ -104,7 +104,7 @@ describe('FileController', function () {
it('should send a 200 if the cacheWarm param is true', function (done) { it('should send a 200 if the cacheWarm param is true', function (done) {
req.query.cacheWarm = true req.query.cacheWarm = true
res.sendStatus = (statusCode) => { res.sendStatus = statusCode => {
statusCode.should.equal(200) statusCode.should.equal(200)
done() done()
} }
@ -165,7 +165,7 @@ describe('FileController', function () {
bucket, bucket,
key, key,
format: undefined, format: undefined,
style: undefined style: undefined,
} }
}) })
@ -220,7 +220,7 @@ describe('FileController', function () {
new Errors.NotFoundError({ message: 'not found', info: {} }) new Errors.NotFoundError({ message: 'not found', info: {} })
) )
res.sendStatus = (code) => { res.sendStatus = code => {
expect(code).to.equal(404) expect(code).to.equal(404)
done() done()
} }
@ -238,7 +238,7 @@ describe('FileController', function () {
describe('insertFile', function () { describe('insertFile', function () {
it('should send bucket name key and res to PersistorManager', function (done) { it('should send bucket name key and res to PersistorManager', function (done) {
res.sendStatus = (code) => { res.sendStatus = code => {
expect(FileHandler.insertFile).to.have.been.calledWith(bucket, key, req) expect(FileHandler.insertFile).to.have.been.calledWith(bucket, key, req)
expect(code).to.equal(200) expect(code).to.equal(200)
done() done()
@ -256,13 +256,13 @@ describe('FileController', function () {
req.body = { req.body = {
source: { source: {
project_id: oldProjectId, project_id: oldProjectId,
file_id: oldFileId file_id: oldFileId,
} },
} }
}) })
it('should send bucket name and both keys to PersistorManager', function (done) { it('should send bucket name and both keys to PersistorManager', function (done) {
res.sendStatus = (code) => { res.sendStatus = code => {
code.should.equal(200) code.should.equal(200)
expect(PersistorManager.copyObject).to.have.been.calledWith( expect(PersistorManager.copyObject).to.have.been.calledWith(
bucket, bucket,
@ -278,7 +278,7 @@ describe('FileController', function () {
PersistorManager.copyObject.rejects( PersistorManager.copyObject.rejects(
new Errors.NotFoundError({ message: 'not found', info: {} }) new Errors.NotFoundError({ message: 'not found', info: {} })
) )
res.sendStatus = (code) => { res.sendStatus = code => {
code.should.equal(404) code.should.equal(404)
done() done()
} }
@ -287,7 +287,7 @@ describe('FileController', function () {
it('should send an error if there was an error', function (done) { it('should send an error if there was an error', function (done) {
PersistorManager.copyObject.rejects(error) PersistorManager.copyObject.rejects(error)
FileController.copyFile(req, res, (err) => { FileController.copyFile(req, res, err => {
expect(err).to.equal(error) expect(err).to.equal(error)
done() done()
}) })
@ -296,7 +296,7 @@ describe('FileController', function () {
describe('delete file', function () { describe('delete file', function () {
it('should tell the file handler', function (done) { it('should tell the file handler', function (done) {
res.sendStatus = (code) => { res.sendStatus = code => {
code.should.equal(204) code.should.equal(204)
expect(FileHandler.deleteFile).to.have.been.calledWith(bucket, key) expect(FileHandler.deleteFile).to.have.been.calledWith(bucket, key)
done() done()
@ -313,7 +313,7 @@ describe('FileController', function () {
describe('delete project', function () { describe('delete project', function () {
it('should tell the file handler', function (done) { it('should tell the file handler', function (done) {
res.sendStatus = (code) => { res.sendStatus = code => {
code.should.equal(204) code.should.equal(204)
expect(FileHandler.deleteProject).to.have.been.calledWith(bucket, key) expect(FileHandler.deleteProject).to.have.been.calledWith(bucket, key)
done() done()
@ -331,10 +331,10 @@ describe('FileController', function () {
describe('directorySize', function () { describe('directorySize', function () {
it('should return total directory size bytes', function (done) { it('should return total directory size bytes', function (done) {
FileController.directorySize(req, { FileController.directorySize(req, {
json: (result) => { json: result => {
expect(result['total bytes']).to.equal(fileSize) expect(result['total bytes']).to.equal(fileSize)
done() done()
} },
}) })
}) })

View file

@ -14,13 +14,13 @@ describe('FileConverter', function () {
const errorMessage = 'guru meditation error' const errorMessage = 'guru meditation error'
const Settings = { const Settings = {
commands: { commands: {
convertCommandPrefix: [] convertCommandPrefix: [],
} },
} }
beforeEach(function () { beforeEach(function () {
SafeExec = { SafeExec = {
promises: sinon.stub().resolves(destPath) promises: sinon.stub().resolves(destPath),
} }
const ObjectPersistor = { Errors } const ObjectPersistor = { Errors }
@ -30,11 +30,11 @@ describe('FileConverter', function () {
'./SafeExec': SafeExec, './SafeExec': SafeExec,
'@overleaf/metrics': { '@overleaf/metrics': {
inc: sinon.stub(), inc: sinon.stub(),
Timer: sinon.stub().returns({ done: sinon.stub() }) Timer: sinon.stub().returns({ done: sinon.stub() }),
},
'@overleaf/settings': Settings,
'@overleaf/object-persistor': ObjectPersistor,
}, },
'settings-sharelatex': Settings,
'@overleaf/object-persistor': ObjectPersistor
}
}) })
}) })

View file

@ -28,7 +28,7 @@ describe('FileHandler', function () {
const redirectUrl = 'https://wombat.potato/giraffe' const redirectUrl = 'https://wombat.potato/giraffe'
const readStream = { const readStream = {
stream: 'readStream', stream: 'readStream',
on: sinon.stub() on: sinon.stub(),
} }
beforeEach(function () { beforeEach(function () {
@ -41,35 +41,35 @@ describe('FileHandler', function () {
sendStream: sinon.stub().resolves(), sendStream: sinon.stub().resolves(),
insertFile: sinon.stub().resolves(), insertFile: sinon.stub().resolves(),
sendFile: sinon.stub().resolves(), sendFile: sinon.stub().resolves(),
directorySize: sinon.stub().resolves() directorySize: sinon.stub().resolves(),
} }
LocalFileWriter = { LocalFileWriter = {
// the callback style is used for detached cleanup calls // the callback style is used for detached cleanup calls
deleteFile: sinon.stub().yields(), deleteFile: sinon.stub().yields(),
promises: { promises: {
writeStream: sinon.stub().resolves(), writeStream: sinon.stub().resolves(),
deleteFile: sinon.stub().resolves() deleteFile: sinon.stub().resolves(),
} },
} }
FileConverter = { FileConverter = {
promises: { promises: {
convert: sinon.stub().resolves(), convert: sinon.stub().resolves(),
thumbnail: sinon.stub().resolves(), thumbnail: sinon.stub().resolves(),
preview: sinon.stub().resolves() preview: sinon.stub().resolves(),
} },
} }
KeyBuilder = { KeyBuilder = {
addCachingToKey: sinon.stub().returns(convertedKey), addCachingToKey: sinon.stub().returns(convertedKey),
getConvertedFolderKey: sinon.stub().returns(convertedFolderKey) getConvertedFolderKey: sinon.stub().returns(convertedFolderKey),
} }
ImageOptimiser = { ImageOptimiser = {
promises: { promises: {
compressPng: sinon.stub().resolves() compressPng: sinon.stub().resolves(),
} },
} }
Settings = {} Settings = {}
fs = { fs = {
createReadStream: sinon.stub().returns(readStream) createReadStream: sinon.stub().returns(readStream),
} }
const ObjectPersistor = { Errors } const ObjectPersistor = { Errors }
@ -81,11 +81,11 @@ describe('FileHandler', function () {
'./FileConverter': FileConverter, './FileConverter': FileConverter,
'./KeyBuilder': KeyBuilder, './KeyBuilder': KeyBuilder,
'./ImageOptimiser': ImageOptimiser, './ImageOptimiser': ImageOptimiser,
'settings-sharelatex': Settings, '@overleaf/settings': Settings,
'@overleaf/object-persistor': ObjectPersistor, '@overleaf/object-persistor': ObjectPersistor,
fs: fs fs: fs,
}, },
globals: { console } globals: { console },
}) })
}) })
@ -93,7 +93,7 @@ describe('FileHandler', function () {
const stream = 'stream' const stream = 'stream'
it('should send file to the filestore', function (done) { it('should send file to the filestore', function (done) {
FileHandler.insertFile(bucket, key, stream, (err) => { FileHandler.insertFile(bucket, key, stream, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.sendStream).to.have.been.calledWith( expect(PersistorManager.sendStream).to.have.been.calledWith(
bucket, bucket,
@ -105,7 +105,7 @@ describe('FileHandler', function () {
}) })
it('should not make a delete request for the convertedKey folder', function (done) { it('should not make a delete request for the convertedKey folder', function (done) {
FileHandler.insertFile(bucket, key, stream, (err) => { FileHandler.insertFile(bucket, key, stream, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.deleteDirectory).not.to.have.been.called expect(PersistorManager.deleteDirectory).not.to.have.been.called
done() done()
@ -116,7 +116,7 @@ describe('FileHandler', function () {
KeyBuilder.getConvertedFolderKey.returns( KeyBuilder.getConvertedFolderKey.returns(
'5ecba29f1a294e007d0bccb4/v/0/pdf' '5ecba29f1a294e007d0bccb4/v/0/pdf'
) )
FileHandler.insertFile(bucket, key, stream, (err) => { FileHandler.insertFile(bucket, key, stream, err => {
expect(err).not.to.exist expect(err).not.to.exist
done() done()
}) })
@ -124,7 +124,7 @@ describe('FileHandler', function () {
it('should throw an error when the key is in the wrong format', function (done) { it('should throw an error when the key is in the wrong format', function (done) {
KeyBuilder.getConvertedFolderKey.returns('wombat') KeyBuilder.getConvertedFolderKey.returns('wombat')
FileHandler.insertFile(bucket, key, stream, (err) => { FileHandler.insertFile(bucket, key, stream, err => {
expect(err).to.exist expect(err).to.exist
done() done()
}) })
@ -136,7 +136,7 @@ describe('FileHandler', function () {
}) })
it('should delete the convertedKey folder', function (done) { it('should delete the convertedKey folder', function (done) {
FileHandler.insertFile(bucket, key, stream, (err) => { FileHandler.insertFile(bucket, key, stream, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.deleteDirectory).to.have.been.calledWith( expect(PersistorManager.deleteDirectory).to.have.been.calledWith(
bucket, bucket,
@ -150,7 +150,7 @@ describe('FileHandler', function () {
describe('deleteFile', function () { describe('deleteFile', function () {
it('should tell the filestore manager to delete the file', function (done) { it('should tell the filestore manager to delete the file', function (done) {
FileHandler.deleteFile(bucket, key, (err) => { FileHandler.deleteFile(bucket, key, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.deleteObject).to.have.been.calledWith( expect(PersistorManager.deleteObject).to.have.been.calledWith(
bucket, bucket,
@ -161,7 +161,7 @@ describe('FileHandler', function () {
}) })
it('should not tell the filestore manager to delete the cached folder', function (done) { it('should not tell the filestore manager to delete the cached folder', function (done) {
FileHandler.deleteFile(bucket, key, (err) => { FileHandler.deleteFile(bucket, key, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.deleteDirectory).not.to.have.been.called expect(PersistorManager.deleteDirectory).not.to.have.been.called
done() done()
@ -172,7 +172,7 @@ describe('FileHandler', function () {
KeyBuilder.getConvertedFolderKey.returns( KeyBuilder.getConvertedFolderKey.returns(
'5ecba29f1a294e007d0bccb4/v/0/pdf' '5ecba29f1a294e007d0bccb4/v/0/pdf'
) )
FileHandler.deleteFile(bucket, key, (err) => { FileHandler.deleteFile(bucket, key, err => {
expect(err).not.to.exist expect(err).not.to.exist
done() done()
}) })
@ -180,7 +180,7 @@ describe('FileHandler', function () {
it('should throw an error when the key is in the wrong format', function (done) { it('should throw an error when the key is in the wrong format', function (done) {
KeyBuilder.getConvertedFolderKey.returns('wombat') KeyBuilder.getConvertedFolderKey.returns('wombat')
FileHandler.deleteFile(bucket, key, (err) => { FileHandler.deleteFile(bucket, key, err => {
expect(err).to.exist expect(err).to.exist
done() done()
}) })
@ -192,7 +192,7 @@ describe('FileHandler', function () {
}) })
it('should delete the convertedKey folder', function (done) { it('should delete the convertedKey folder', function (done) {
FileHandler.deleteFile(bucket, key, (err) => { FileHandler.deleteFile(bucket, key, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.deleteDirectory).to.have.been.calledWith( expect(PersistorManager.deleteDirectory).to.have.been.calledWith(
bucket, bucket,
@ -206,7 +206,7 @@ describe('FileHandler', function () {
describe('deleteProject', function () { describe('deleteProject', function () {
it('should tell the filestore manager to delete the folder', function (done) { it('should tell the filestore manager to delete the folder', function (done) {
FileHandler.deleteProject(bucket, projectKey, (err) => { FileHandler.deleteProject(bucket, projectKey, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.deleteDirectory).to.have.been.calledWith( expect(PersistorManager.deleteDirectory).to.have.been.calledWith(
bucket, bucket,
@ -217,7 +217,7 @@ describe('FileHandler', function () {
}) })
it('should throw an error when the key is in the wrong format', function (done) { it('should throw an error when the key is in the wrong format', function (done) {
FileHandler.deleteProject(bucket, 'wombat', (err) => { FileHandler.deleteProject(bucket, 'wombat', err => {
expect(err).to.exist expect(err).to.exist
done() done()
}) })
@ -235,7 +235,7 @@ describe('FileHandler', function () {
it('should pass options through to PersistorManager', function (done) { it('should pass options through to PersistorManager', function (done) {
const options = { start: 0, end: 8 } const options = { start: 0, end: 8 }
FileHandler.getFile(bucket, key, options, (err) => { FileHandler.getFile(bucket, key, options, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.getObjectStream).to.have.been.calledWith( expect(PersistorManager.getObjectStream).to.have.been.calledWith(
bucket, bucket,
@ -305,7 +305,7 @@ describe('FileHandler', function () {
describe('when a style is defined', function () { describe('when a style is defined', function () {
it('generates a thumbnail when requested', function (done) { it('generates a thumbnail when requested', function (done) {
FileHandler.getFile(bucket, key, { style: 'thumbnail' }, (err) => { FileHandler.getFile(bucket, key, { style: 'thumbnail' }, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(FileConverter.promises.thumbnail).to.have.been.called expect(FileConverter.promises.thumbnail).to.have.been.called
expect(FileConverter.promises.preview).not.to.have.been.called expect(FileConverter.promises.preview).not.to.have.been.called
@ -314,7 +314,7 @@ describe('FileHandler', function () {
}) })
it('generates a preview when requested', function (done) { it('generates a preview when requested', function (done) {
FileHandler.getFile(bucket, key, { style: 'preview' }, (err) => { FileHandler.getFile(bucket, key, { style: 'preview' }, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(FileConverter.promises.thumbnail).not.to.have.been.called expect(FileConverter.promises.thumbnail).not.to.have.been.called
expect(FileConverter.promises.preview).to.have.been.called expect(FileConverter.promises.preview).to.have.been.called
@ -329,8 +329,8 @@ describe('FileHandler', function () {
Settings.filestore = { Settings.filestore = {
allowRedirects: true, allowRedirects: true,
stores: { stores: {
userFiles: bucket userFiles: bucket,
} },
} }
}) })
@ -385,7 +385,7 @@ describe('FileHandler', function () {
describe('getDirectorySize', function () { describe('getDirectorySize', function () {
it('should call the filestore manager to get directory size', function (done) { it('should call the filestore manager to get directory size', function (done) {
FileHandler.getDirectorySize(bucket, key, (err) => { FileHandler.getDirectorySize(bucket, key, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(PersistorManager.directorySize).to.have.been.calledWith( expect(PersistorManager.directorySize).to.have.been.calledWith(
bucket, bucket,

View file

@ -11,29 +11,29 @@ describe('ImageOptimiser', function () {
beforeEach(function () { beforeEach(function () {
SafeExec = { SafeExec = {
promises: sinon.stub().resolves() promises: sinon.stub().resolves(),
} }
logger = { logger = {
warn: sinon.stub() warn: sinon.stub(),
} }
ImageOptimiser = SandboxedModule.require(modulePath, { ImageOptimiser = SandboxedModule.require(modulePath, {
requires: { requires: {
'./SafeExec': SafeExec, './SafeExec': SafeExec,
'logger-sharelatex': logger, 'logger-sharelatex': logger,
'@overleaf/metrics': { '@overleaf/metrics': {
Timer: sinon.stub().returns({ done: sinon.stub() }) Timer: sinon.stub().returns({ done: sinon.stub() }),
} },
} },
}) })
}) })
describe('compressPng', function () { describe('compressPng', function () {
it('should convert the file', function (done) { it('should convert the file', function (done) {
ImageOptimiser.compressPng(sourcePath, (err) => { ImageOptimiser.compressPng(sourcePath, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(SafeExec.promises).to.have.been.calledWith([ expect(SafeExec.promises).to.have.been.calledWith([
'optipng', 'optipng',
sourcePath sourcePath,
]) ])
done() done()
}) })
@ -41,7 +41,7 @@ describe('ImageOptimiser', function () {
it('should return the error', function (done) { it('should return the error', function (done) {
SafeExec.promises.rejects('wombat herding failure') SafeExec.promises.rejects('wombat herding failure')
ImageOptimiser.compressPng(sourcePath, (err) => { ImageOptimiser.compressPng(sourcePath, err => {
expect(err.toString()).to.equal('wombat herding failure') expect(err.toString()).to.equal('wombat herding failure')
done() done()
}) })
@ -54,7 +54,7 @@ describe('ImageOptimiser', function () {
beforeEach(function (done) { beforeEach(function (done) {
SafeExec.promises.rejects(expectedError) SafeExec.promises.rejects(expectedError)
ImageOptimiser.compressPng(sourcePath, (err) => { ImageOptimiser.compressPng(sourcePath, err => {
error = err error = err
done() done()
}) })

View file

@ -8,7 +8,7 @@ describe('KeybuilderTests', function () {
beforeEach(function () { beforeEach(function () {
KeyBuilder = SandboxedModule.require(modulePath, { KeyBuilder = SandboxedModule.require(modulePath, {
requires: { 'settings-sharelatex': {} } requires: { '@overleaf/settings': {} },
}) })
}) })
@ -28,7 +28,7 @@ describe('KeybuilderTests', function () {
it('should add format first, then style', function () { it('should add format first, then style', function () {
const opts = { const opts = {
style: 'thumbnail', style: 'thumbnail',
format: 'png' format: 'png',
} }
const newKey = KeyBuilder.addCachingToKey(key, opts) const newKey = KeyBuilder.addCachingToKey(key, opts)
newKey.should.equal(`${key}-converted-cache/format-png-style-thumbnail`) newKey.should.equal(`${key}-converted-cache/format-png-style-thumbnail`)

View file

@ -17,10 +17,10 @@ describe('LocalFileWriter', function () {
beforeEach(function () { beforeEach(function () {
fs = { fs = {
createWriteStream: sinon.stub().returns(writeStream), createWriteStream: sinon.stub().returns(writeStream),
unlink: sinon.stub().yields() unlink: sinon.stub().yields(),
} }
stream = { stream = {
pipeline: sinon.stub().yields() pipeline: sinon.stub().yields(),
} }
const ObjectPersistor = { Errors } const ObjectPersistor = { Errors }
@ -29,13 +29,13 @@ describe('LocalFileWriter', function () {
requires: { requires: {
fs, fs,
stream, stream,
'settings-sharelatex': settings, '@overleaf/settings': settings,
'@overleaf/metrics': { '@overleaf/metrics': {
inc: sinon.stub(), inc: sinon.stub(),
Timer: sinon.stub().returns({ done: sinon.stub() }) Timer: sinon.stub().returns({ done: sinon.stub() }),
},
'@overleaf/object-persistor': ObjectPersistor,
}, },
'@overleaf/object-persistor': ObjectPersistor
}
}) })
}) })
@ -57,7 +57,7 @@ describe('LocalFileWriter', function () {
}) })
it('should wrap the error', function () { it('should wrap the error', function () {
LocalFileWriter.writeStream(readStream, filename, (err) => { LocalFileWriter.writeStream(readStream, filename, err => {
expect(err).to.exist expect(err).to.exist
expect(err.cause).to.equal(error) expect(err.cause).to.equal(error)
}) })
@ -73,7 +73,7 @@ describe('LocalFileWriter', function () {
describe('deleteFile', function () { describe('deleteFile', function () {
it('should unlink the file', function (done) { it('should unlink the file', function (done) {
LocalFileWriter.deleteFile(fsPath, (err) => { LocalFileWriter.deleteFile(fsPath, err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(fs.unlink).to.have.been.calledWith(fsPath) expect(fs.unlink).to.have.been.calledWith(fsPath)
done() done()
@ -81,7 +81,7 @@ describe('LocalFileWriter', function () {
}) })
it('should not call unlink with an empty path', function (done) { it('should not call unlink with an empty path', function (done) {
LocalFileWriter.deleteFile('', (err) => { LocalFileWriter.deleteFile('', err => {
expect(err).not.to.exist expect(err).not.to.exist
expect(fs.unlink).not.to.have.been.called expect(fs.unlink).not.to.have.been.called
done() done()
@ -92,7 +92,7 @@ describe('LocalFileWriter', function () {
const error = new Error('file not found') const error = new Error('file not found')
error.code = 'ENOENT' error.code = 'ENOENT'
fs.unlink = sinon.stub().yields(error) fs.unlink = sinon.stub().yields(error)
LocalFileWriter.deleteFile(fsPath, (err) => { LocalFileWriter.deleteFile(fsPath, err => {
expect(err).not.to.exist expect(err).not.to.exist
done() done()
}) })
@ -101,7 +101,7 @@ describe('LocalFileWriter', function () {
it('should wrap the error', function (done) { it('should wrap the error', function (done) {
const error = new Error('failed to reticulate splines') const error = new Error('failed to reticulate splines')
fs.unlink = sinon.stub().yields(error) fs.unlink = sinon.stub().yields(error)
LocalFileWriter.deleteFile(fsPath, (err) => { LocalFileWriter.deleteFile(fsPath, err => {
expect(err).to.exist expect(err).to.exist
expect(err.cause).to.equal(error) expect(err.cause).to.equal(error)
done() done()

View file

@ -17,9 +17,9 @@ describe('SafeExec', function () {
safeExec = SandboxedModule.require(modulePath, { safeExec = SandboxedModule.require(modulePath, {
globals: { process }, globals: { process },
requires: { requires: {
'settings-sharelatex': settings, '@overleaf/settings': settings,
'@overleaf/object-persistor': ObjectPersistor '@overleaf/object-persistor': ObjectPersistor,
} },
}) })
}) })
@ -35,14 +35,14 @@ describe('SafeExec', function () {
it('should error when conversions are disabled', function (done) { it('should error when conversions are disabled', function (done) {
settings.enableConversions = false settings.enableConversions = false
safeExec(['/bin/echo', 'hello'], options, (err) => { safeExec(['/bin/echo', 'hello'], options, err => {
expect(err).to.exist expect(err).to.exist
done() done()
}) })
}) })
it('should execute a command with non-zero exit status', function (done) { it('should execute a command with non-zero exit status', function (done) {
safeExec(['/usr/bin/env', 'false'], options, (err) => { safeExec(['/usr/bin/env', 'false'], options, err => {
expect(err).to.exist expect(err).to.exist
expect(err.name).to.equal('FailedCommandError') expect(err.name).to.equal('FailedCommandError')
expect(err.code).to.equal(1) expect(err.code).to.equal(1)
@ -53,7 +53,7 @@ describe('SafeExec', function () {
}) })
it('should handle an invalid command', function (done) { it('should handle an invalid command', function (done) {
safeExec(['/bin/foobar'], options, (err) => { safeExec(['/bin/foobar'], options, err => {
err.code.should.equal('ENOENT') err.code.should.equal('ENOENT')
done() done()
}) })
@ -63,7 +63,7 @@ describe('SafeExec', function () {
safeExec( safeExec(
['/bin/sleep', '10'], ['/bin/sleep', '10'],
{ timeout: 500, killSignal: 'SIGTERM' }, { timeout: 500, killSignal: 'SIGTERM' },
(err) => { err => {
expect(err).to.exist expect(err).to.exist
expect(err.name).to.equal('FailedCommandError') expect(err.name).to.equal('FailedCommandError')
expect(err.code).to.equal('SIGTERM') expect(err.code).to.equal('SIGTERM')

View file

@ -8,12 +8,12 @@ describe('Settings', function () {
const s3Settings = { const s3Settings = {
bucket1: { bucket1: {
auth_key: 'bucket1_key', auth_key: 'bucket1_key',
auth_secret: 'bucket1_secret' auth_secret: 'bucket1_secret',
} },
} }
process.env.S3_BUCKET_CREDENTIALS = JSON.stringify(s3Settings) process.env.S3_BUCKET_CREDENTIALS = JSON.stringify(s3Settings)
const settings = SandboxedModule.require('settings-sharelatex', { const settings = SandboxedModule.require('@overleaf/settings', {
globals: { console, process } globals: { console, process },
}) })
expect(settings.filestore.s3.bucketCreds).to.deep.equal(s3Settings) expect(settings.filestore.s3.bucketCreds).to.deep.equal(s3Settings)
}) })