[misc] bump the dev-env to 3.3.2

This commit is contained in:
Jakob Ackermann 2020-08-10 17:01:11 +01:00
parent 5846ebb367
commit 1d1b9ebebc
66 changed files with 1371 additions and 1458 deletions

View file

@ -8,7 +8,7 @@
"prettier/standard" "prettier/standard"
], ],
"parserOptions": { "parserOptions": {
"ecmaVersion": 2017 "ecmaVersion": 2018
}, },
"plugins": [ "plugins": [
"mocha", "mocha",

17
services/clsi/.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,17 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
pull-request-branch-name:
# Separate sections of the branch name with a hyphen
# Docker images use the branch name and do not support slashes in tags
# https://github.com/overleaf/google-ops/issues/822
# https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#pull-request-branch-nameseparator
separator: "-"
# Block informal upgrades -- security upgrades use a separate queue.
# https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#open-pull-requests-limit
open-pull-requests-limit: 0

View file

@ -11,3 +11,6 @@ db.sqlite-wal
db.sqlite-shm db.sqlite-shm
config/* config/*
npm-debug.log npm-debug.log
# managed by dev-environment$ bin/update_build_scripts
.npmrc

View file

@ -15,12 +15,10 @@ FROM base as app
#wildcard as some files may not be in all repos #wildcard as some files may not be in all repos
COPY package*.json npm-shrink*.json /app/ COPY package*.json npm-shrink*.json /app/
RUN npm install --quiet RUN npm ci --quiet
COPY . /app COPY . /app
FROM base FROM base
COPY --from=app /app /app COPY --from=app /app /app

View file

@ -1,131 +0,0 @@
String cron_string = BRANCH_NAME == "master" ? "@daily" : ""
pipeline {
agent any
environment {
GIT_PROJECT = "clsi"
JENKINS_WORKFLOW = "clsi-sharelatex"
TARGET_URL = "${env.JENKINS_URL}blue/organizations/jenkins/${JENKINS_WORKFLOW}/detail/$BRANCH_NAME/$BUILD_NUMBER/pipeline"
GIT_API_URL = "https://api.github.com/repos/overleaf/${GIT_PROJECT}/statuses/$GIT_COMMIT"
}
triggers {
pollSCM('* * * * *')
cron(cron_string)
}
stages {
stage('Install') {
steps {
withCredentials([usernamePassword(credentialsId: 'GITHUB_INTEGRATION', usernameVariable: 'GH_AUTH_USERNAME', passwordVariable: 'GH_AUTH_PASSWORD')]) {
sh "curl $GIT_API_URL \
--data '{ \
\"state\" : \"pending\", \
\"target_url\": \"$TARGET_URL\", \
\"description\": \"Your build is underway\", \
\"context\": \"ci/jenkins\" }' \
-u $GH_AUTH_USERNAME:$GH_AUTH_PASSWORD"
}
}
}
stage('Build') {
steps {
sh 'make build'
}
}
stage('Linting') {
steps {
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make format'
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make lint'
}
}
stage('Unit Tests') {
steps {
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make test_unit'
}
}
stage('Acceptance Tests') {
steps {
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make test_acceptance'
}
}
stage('Package and docker push') {
steps {
sh 'echo ${BUILD_NUMBER} > build_number.txt'
sh 'touch build.tar.gz' // Avoid tar warning about files changing during read
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make tar'
withCredentials([file(credentialsId: 'gcr.io_overleaf-ops', variable: 'DOCKER_REPO_KEY_PATH')]) {
sh 'docker login -u _json_key --password-stdin https://gcr.io/overleaf-ops < ${DOCKER_REPO_KEY_PATH}'
}
sh 'DOCKER_REPO=gcr.io/overleaf-ops make publish'
sh 'docker logout https://gcr.io/overleaf-ops'
}
}
stage('Publish to s3') {
steps {
sh 'echo ${BRANCH_NAME}-${BUILD_NUMBER} > build_number.txt'
withAWS(credentials:'S3_CI_BUILDS_AWS_KEYS', region:"${S3_REGION_BUILD_ARTEFACTS}") {
s3Upload(file:'build.tar.gz', bucket:"${S3_BUCKET_BUILD_ARTEFACTS}", path:"${JOB_NAME}/${BUILD_NUMBER}.tar.gz")
}
withAWS(credentials:'S3_CI_BUILDS_AWS_KEYS', region:"${S3_REGION_BUILD_ARTEFACTS}") {
// The deployment process uses this file to figure out the latest build
s3Upload(file:'build_number.txt', bucket:"${S3_BUCKET_BUILD_ARTEFACTS}", path:"${JOB_NAME}/latest")
}
}
}
}
post {
always {
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make test_clean'
sh 'make clean'
}
success {
withCredentials([usernamePassword(credentialsId: 'GITHUB_INTEGRATION', usernameVariable: 'GH_AUTH_USERNAME', passwordVariable: 'GH_AUTH_PASSWORD')]) {
sh "curl $GIT_API_URL \
--data '{ \
\"state\" : \"success\", \
\"target_url\": \"$TARGET_URL\", \
\"description\": \"Your build succeeded!\", \
\"context\": \"ci/jenkins\" }' \
-u $GH_AUTH_USERNAME:$GH_AUTH_PASSWORD"
}
}
failure {
mail(from: "${EMAIL_ALERT_FROM}",
to: "${EMAIL_ALERT_TO}",
subject: "Jenkins build failed: ${JOB_NAME}:${BUILD_NUMBER}",
body: "Build: ${BUILD_URL}")
withCredentials([usernamePassword(credentialsId: 'GITHUB_INTEGRATION', usernameVariable: 'GH_AUTH_USERNAME', passwordVariable: 'GH_AUTH_PASSWORD')]) {
sh "curl $GIT_API_URL \
--data '{ \
\"state\" : \"failure\", \
\"target_url\": \"$TARGET_URL\", \
\"description\": \"Your build failed\", \
\"context\": \"ci/jenkins\" }' \
-u $GH_AUTH_USERNAME:$GH_AUTH_PASSWORD"
}
}
}
// The options directive is for configuration that applies to the whole job.
options {
// we'd like to make sure remove old builds, so we don't fill up our storage!
buildDiscarder(logRotator(numToKeepStr:'50'))
// And we'd really like to be sure that this build doesn't hang forever, so let's time it out after:
timeout(time: 30, unit: 'MINUTES')
}
}

View file

@ -25,13 +25,13 @@ clean:
docker rmi gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) docker rmi gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER)
format: format:
$(DOCKER_COMPOSE) run --rm test_unit npm run format $(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
format_fix: format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run format:fix $(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
lint: lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run lint $(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
test: format lint test_unit test_acceptance test: format lint test_unit test_acceptance

View file

@ -42,14 +42,14 @@ app.use(Metrics.http.monitor(logger))
// minutes (including file download time), so bump up the // minutes (including file download time), so bump up the
// timeout a bit. // timeout a bit.
const TIMEOUT = 10 * 60 * 1000 const TIMEOUT = 10 * 60 * 1000
app.use(function(req, res, next) { app.use(function (req, res, next) {
req.setTimeout(TIMEOUT) req.setTimeout(TIMEOUT)
res.setTimeout(TIMEOUT) res.setTimeout(TIMEOUT)
res.removeHeader('X-Powered-By') res.removeHeader('X-Powered-By')
return next() return next()
}) })
app.param('project_id', function(req, res, next, projectId) { app.param('project_id', function (req, res, next, projectId) {
if (projectId != null ? projectId.match(/^[a-zA-Z0-9_-]+$/) : undefined) { if (projectId != null ? projectId.match(/^[a-zA-Z0-9_-]+$/) : undefined) {
return next() return next()
} else { } else {
@ -57,7 +57,7 @@ app.param('project_id', function(req, res, next, projectId) {
} }
}) })
app.param('user_id', function(req, res, next, userId) { app.param('user_id', function (req, res, next, userId) {
if (userId != null ? userId.match(/^[0-9a-f]{24}$/) : undefined) { if (userId != null ? userId.match(/^[0-9a-f]{24}$/) : undefined) {
return next() return next()
} else { } else {
@ -65,7 +65,7 @@ app.param('user_id', function(req, res, next, userId) {
} }
}) })
app.param('build_id', function(req, res, next, buildId) { app.param('build_id', function (req, res, next, buildId) {
if ( if (
buildId != null ? buildId.match(OutputCacheManager.BUILD_REGEX) : undefined buildId != null ? buildId.match(OutputCacheManager.BUILD_REGEX) : undefined
) { ) {
@ -134,19 +134,18 @@ const staticServer = ForbidSymlinks(express.static, Settings.path.compilesDir, {
} }
}) })
app.get('/project/:project_id/user/:user_id/build/:build_id/output/*', function( app.get(
req, '/project/:project_id/user/:user_id/build/:build_id/output/*',
res, function (req, res, next) {
next // for specific build get the path from the OutputCacheManager (e.g. .clsi/buildId)
) { req.url =
// for specific build get the path from the OutputCacheManager (e.g. .clsi/buildId) `/${req.params.project_id}-${req.params.user_id}/` +
req.url = OutputCacheManager.path(req.params.build_id, `/${req.params[0]}`)
`/${req.params.project_id}-${req.params.user_id}/` + return staticServer(req, res, next)
OutputCacheManager.path(req.params.build_id, `/${req.params[0]}`) }
return staticServer(req, res, next) )
})
app.get('/project/:project_id/build/:build_id/output/*', function( app.get('/project/:project_id/build/:build_id/output/*', function (
req, req,
res, res,
next next
@ -158,7 +157,7 @@ app.get('/project/:project_id/build/:build_id/output/*', function(
return staticServer(req, res, next) return staticServer(req, res, next)
}) })
app.get('/project/:project_id/user/:user_id/output/*', function( app.get('/project/:project_id/user/:user_id/output/*', function (
req, req,
res, res,
next next
@ -168,7 +167,7 @@ app.get('/project/:project_id/user/:user_id/output/*', function(
return staticServer(req, res, next) return staticServer(req, res, next)
}) })
app.get('/project/:project_id/output/*', function(req, res, next) { app.get('/project/:project_id/output/*', function (req, res, next) {
if ( if (
(req.query != null ? req.query.build : undefined) != null && (req.query != null ? req.query.build : undefined) != null &&
req.query.build.match(OutputCacheManager.BUILD_REGEX) req.query.build.match(OutputCacheManager.BUILD_REGEX)
@ -183,7 +182,7 @@ app.get('/project/:project_id/output/*', function(req, res, next) {
return staticServer(req, res, next) return staticServer(req, res, next)
}) })
app.get('/oops', function(req, res, next) { app.get('/oops', function (req, res, next) {
logger.error({ err: 'hello' }, 'test error') logger.error({ err: 'hello' }, 'test error')
return res.send('error\n') return res.send('error\n')
}) })
@ -208,7 +207,7 @@ if (Settings.processLifespanLimitMs) {
function runSmokeTest() { function runSmokeTest() {
if (Settings.processTooOld) return if (Settings.processTooOld) return
logger.log('running smoke tests') logger.log('running smoke tests')
smokeTest.triggerRun(err => { smokeTest.triggerRun((err) => {
if (err) logger.error({ err }, 'smoke tests failed') if (err) logger.error({ err }, 'smoke tests failed')
setTimeout(runSmokeTest, 30 * 1000) setTimeout(runSmokeTest, 30 * 1000)
}) })
@ -217,7 +216,7 @@ if (Settings.smokeTest) {
runSmokeTest() runSmokeTest()
} }
app.get('/health_check', function(req, res) { app.get('/health_check', function (req, res) {
if (Settings.processTooOld) { if (Settings.processTooOld) {
return res.status(500).json({ processTooOld: true }) return res.status(500).json({ processTooOld: true })
} }
@ -226,7 +225,7 @@ app.get('/health_check', function(req, res) {
app.get('/smoke_test_force', (req, res) => smokeTest.sendNewResult(res)) app.get('/smoke_test_force', (req, res) => smokeTest.sendNewResult(res))
app.use(function(error, req, res, next) { app.use(function (error, req, res, next) {
if (error instanceof Errors.NotFoundError) { if (error instanceof Errors.NotFoundError) {
logger.log({ err: error, url: req.url }, 'not found error') logger.log({ err: error, url: req.url }, 'not found error')
return res.sendStatus(404) return res.sendStatus(404)
@ -244,8 +243,8 @@ const os = require('os')
let STATE = 'up' let STATE = 'up'
const loadTcpServer = net.createServer(function(socket) { const loadTcpServer = net.createServer(function (socket) {
socket.on('error', function(err) { socket.on('error', function (err) {
if (err.code === 'ECONNRESET') { if (err.code === 'ECONNRESET') {
// this always comes up, we don't know why // this always comes up, we don't know why
return return
@ -280,19 +279,19 @@ const loadTcpServer = net.createServer(function(socket) {
const loadHttpServer = express() const loadHttpServer = express()
loadHttpServer.post('/state/up', function(req, res, next) { loadHttpServer.post('/state/up', function (req, res, next) {
STATE = 'up' STATE = 'up'
logger.info('getting message to set server to down') logger.info('getting message to set server to down')
return res.sendStatus(204) return res.sendStatus(204)
}) })
loadHttpServer.post('/state/down', function(req, res, next) { loadHttpServer.post('/state/down', function (req, res, next) {
STATE = 'down' STATE = 'down'
logger.info('getting message to set server to down') logger.info('getting message to set server to down')
return res.sendStatus(204) return res.sendStatus(204)
}) })
loadHttpServer.post('/state/maint', function(req, res, next) { loadHttpServer.post('/state/maint', function (req, res, next) {
STATE = 'maint' STATE = 'maint'
logger.info('getting message to set server to maint') logger.info('getting message to set server to maint')
return res.sendStatus(204) return res.sendStatus(204)
@ -301,12 +300,12 @@ loadHttpServer.post('/state/maint', function(req, res, next) {
const port = const port =
__guard__( __guard__(
Settings.internal != null ? Settings.internal.clsi : undefined, Settings.internal != null ? Settings.internal.clsi : undefined,
x => x.port (x) => x.port
) || 3013 ) || 3013
const host = const host =
__guard__( __guard__(
Settings.internal != null ? Settings.internal.clsi : undefined, Settings.internal != null ? Settings.internal.clsi : undefined,
x1 => x1.host (x1) => x1.host
) || 'localhost' ) || 'localhost'
const loadTcpPort = Settings.internal.load_balancer_agent.load_port const loadTcpPort = Settings.internal.load_balancer_agent.load_port
@ -314,7 +313,7 @@ const loadHttpPort = Settings.internal.load_balancer_agent.local_port
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.fatal({ error }, `Error starting CLSI on ${host}:${port}`) logger.fatal({ error }, `Error starting CLSI on ${host}:${port}`)
} else { } else {
@ -322,14 +321,14 @@ if (!module.parent) {
} }
}) })
loadTcpServer.listen(loadTcpPort, host, function(error) { loadTcpServer.listen(loadTcpPort, host, function (error) {
if (error != null) { if (error != null) {
throw error throw error
} }
return logger.info(`Load tcp agent listening on load port ${loadTcpPort}`) return logger.info(`Load tcp agent listening on load port ${loadTcpPort}`)
}) })
loadHttpServer.listen(loadHttpPort, host, function(error) { loadHttpServer.listen(loadHttpPort, host, function (error) {
if (error != null) { if (error != null) {
throw error throw error
} }

View file

@ -24,10 +24,10 @@ const Errors = require('./Errors')
module.exports = CompileController = { module.exports = CompileController = {
compile(req, res, next) { compile(req, res, next) {
if (next == null) { if (next == null) {
next = function(error) {} next = function (error) {}
} }
const timer = new Metrics.Timer('compile-request') const timer = new Metrics.Timer('compile-request')
return RequestParser.parse(req.body, function(error, request) { return RequestParser.parse(req.body, function (error, request) {
if (error != null) { if (error != null) {
return next(error) return next(error)
} }
@ -37,11 +37,11 @@ module.exports = CompileController = {
} }
return ProjectPersistenceManager.markProjectAsJustAccessed( return ProjectPersistenceManager.markProjectAsJustAccessed(
request.project_id, request.project_id,
function(error) { function (error) {
if (error != null) { if (error != null) {
return next(error) return next(error)
} }
return CompileManager.doCompileWithLock(request, function( return CompileManager.doCompileWithLock(request, function (
error, error,
outputFiles outputFiles
) { ) {
@ -116,7 +116,7 @@ module.exports = CompileController = {
compile: { compile: {
status, status,
error: (error != null ? error.message : undefined) || error, error: (error != null ? error.message : undefined) || error,
outputFiles: outputFiles.map(file => ({ outputFiles: outputFiles.map((file) => ({
url: url:
`${Settings.apis.clsi.url}/project/${request.project_id}` + `${Settings.apis.clsi.url}/project/${request.project_id}` +
(request.user_id != null (request.user_id != null
@ -138,7 +138,7 @@ module.exports = CompileController = {
stopCompile(req, res, next) { stopCompile(req, res, next) {
const { project_id, user_id } = req.params const { project_id, user_id } = req.params
return CompileManager.stopCompile(project_id, user_id, function(error) { return CompileManager.stopCompile(project_id, user_id, function (error) {
if (error != null) { if (error != null) {
return next(error) return next(error)
} }
@ -148,12 +148,12 @@ module.exports = CompileController = {
clearCache(req, res, next) { clearCache(req, res, next) {
if (next == null) { if (next == null) {
next = function(error) {} next = function (error) {}
} }
return ProjectPersistenceManager.clearProject( return ProjectPersistenceManager.clearProject(
req.params.project_id, req.params.project_id,
req.params.user_id, req.params.user_id,
function(error) { function (error) {
if (error != null) { if (error != null) {
return next(error) return next(error)
} }
@ -164,7 +164,7 @@ module.exports = CompileController = {
syncFromCode(req, res, next) { syncFromCode(req, res, next) {
if (next == null) { if (next == null) {
next = function(error) {} next = function (error) {}
} }
const { file } = req.query const { file } = req.query
const line = parseInt(req.query.line, 10) const line = parseInt(req.query.line, 10)
@ -177,7 +177,7 @@ module.exports = CompileController = {
file, file,
line, line,
column, column,
function(error, pdfPositions) { function (error, pdfPositions) {
if (error != null) { if (error != null) {
return next(error) return next(error)
} }
@ -190,29 +190,33 @@ module.exports = CompileController = {
syncFromPdf(req, res, next) { syncFromPdf(req, res, next) {
if (next == null) { if (next == null) {
next = function(error) {} next = function (error) {}
} }
const page = parseInt(req.query.page, 10) const page = parseInt(req.query.page, 10)
const h = parseFloat(req.query.h) const h = parseFloat(req.query.h)
const v = parseFloat(req.query.v) const v = parseFloat(req.query.v)
const { project_id } = req.params const { project_id } = req.params
const { user_id } = req.params const { user_id } = req.params
return CompileManager.syncFromPdf(project_id, user_id, page, h, v, function( return CompileManager.syncFromPdf(
error, project_id,
codePositions user_id,
) { page,
if (error != null) { h,
return next(error) v,
function (error, codePositions) {
if (error != null) {
return next(error)
}
return res.json({
code: codePositions
})
} }
return res.json({ )
code: codePositions
})
})
}, },
wordcount(req, res, next) { wordcount(req, res, next) {
if (next == null) { if (next == null) {
next = function(error) {} next = function (error) {}
} }
const file = req.query.file || 'main.tex' const file = req.query.file || 'main.tex'
const { project_id } = req.params const { project_id } = req.params
@ -229,7 +233,7 @@ module.exports = CompileController = {
} }
logger.log({ image, file, project_id }, 'word count request') logger.log({ image, file, project_id }, 'word count request')
return CompileManager.wordcount(project_id, user_id, file, image, function( return CompileManager.wordcount(project_id, user_id, file, image, function (
error, error,
result result
) { ) {
@ -244,7 +248,7 @@ module.exports = CompileController = {
status(req, res, next) { status(req, res, next) {
if (next == null) { if (next == null) {
next = function(error) {} next = function (error) {}
} }
return res.send('OK') return res.send('OK')
} }

View file

@ -35,7 +35,7 @@ const async = require('async')
const Errors = require('./Errors') const Errors = require('./Errors')
const CommandRunner = require('./CommandRunner') const CommandRunner = require('./CommandRunner')
const getCompileName = function(project_id, user_id) { const getCompileName = function (project_id, user_id) {
if (user_id != null) { if (user_id != null) {
return `${project_id}-${user_id}` return `${project_id}-${user_id}`
} else { } else {
@ -49,19 +49,19 @@ const getCompileDir = (project_id, user_id) =>
module.exports = CompileManager = { module.exports = CompileManager = {
doCompileWithLock(request, callback) { doCompileWithLock(request, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, outputFiles) {} callback = function (error, outputFiles) {}
} }
const compileDir = getCompileDir(request.project_id, request.user_id) const compileDir = getCompileDir(request.project_id, request.user_id)
const lockFile = Path.join(compileDir, '.project-lock') const lockFile = Path.join(compileDir, '.project-lock')
// use a .project-lock file in the compile directory to prevent // use a .project-lock file in the compile directory to prevent
// simultaneous compiles // simultaneous compiles
return fse.ensureDir(compileDir, function(error) { return fse.ensureDir(compileDir, function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return LockManager.runWithLock( return LockManager.runWithLock(
lockFile, lockFile,
releaseLock => CompileManager.doCompile(request, releaseLock), (releaseLock) => CompileManager.doCompile(request, releaseLock),
callback callback
) )
}) })
@ -69,7 +69,7 @@ module.exports = CompileManager = {
doCompile(request, callback) { doCompile(request, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, outputFiles) {} callback = function (error, outputFiles) {}
} }
const compileDir = getCompileDir(request.project_id, request.user_id) const compileDir = getCompileDir(request.project_id, request.user_id)
let timer = new Metrics.Timer('write-to-disk') let timer = new Metrics.Timer('write-to-disk')
@ -77,7 +77,7 @@ module.exports = CompileManager = {
{ project_id: request.project_id, user_id: request.user_id }, { project_id: request.project_id, user_id: request.user_id },
'syncing resources to disk' 'syncing resources to disk'
) )
return ResourceWriter.syncResourcesToDisk(request, compileDir, function( return ResourceWriter.syncResourcesToDisk(request, compileDir, function (
error, error,
resourceList resourceList
) { ) {
@ -109,7 +109,7 @@ module.exports = CompileManager = {
) )
timer.done() timer.done()
const injectDraftModeIfRequired = function(callback) { const injectDraftModeIfRequired = function (callback) {
if (request.draft) { if (request.draft) {
return DraftModeManager.injectDraftMode( return DraftModeManager.injectDraftMode(
Path.join(compileDir, request.rootResourcePath), Path.join(compileDir, request.rootResourcePath),
@ -120,12 +120,12 @@ module.exports = CompileManager = {
} }
} }
const createTikzFileIfRequired = callback => const createTikzFileIfRequired = (callback) =>
TikzManager.checkMainFile( TikzManager.checkMainFile(
compileDir, compileDir,
request.rootResourcePath, request.rootResourcePath,
resourceList, resourceList,
function(error, needsMainFile) { function (error, needsMainFile) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -165,7 +165,7 @@ module.exports = CompileManager = {
// apply a series of file modifications/creations for draft mode and tikz // apply a series of file modifications/creations for draft mode and tikz
return async.series( return async.series(
[injectDraftModeIfRequired, createTikzFileIfRequired], [injectDraftModeIfRequired, createTikzFileIfRequired],
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -177,9 +177,9 @@ module.exports = CompileManager = {
request.imageName != null request.imageName != null
? request.imageName.match(/:(.*)/) ? request.imageName.match(/:(.*)/)
: undefined, : undefined,
x1 => x1[1] (x1) => x1[1]
), ),
x => x.replace(/\./g, '-') (x) => x.replace(/\./g, '-')
) || 'default' ) || 'default'
if (!request.project_id.match(/^[0-9a-f]{24}$/)) { if (!request.project_id.match(/^[0-9a-f]{24}$/)) {
tag = 'other' tag = 'other'
@ -202,13 +202,11 @@ module.exports = CompileManager = {
environment: env, environment: env,
compileGroup: request.compileGroup compileGroup: request.compileGroup
}, },
function(error, output, stats, timings) { function (error, output, stats, timings) {
// request was for validation only // request was for validation only
let metric_key, metric_value let metric_key, metric_value
if (request.check === 'validate') { if (request.check === 'validate') {
const result = (error != null const result = (error != null ? error.code : undefined)
? error.code
: undefined)
? 'fail' ? 'fail'
: 'pass' : 'pass'
error = new Error('validation') error = new Error('validation')
@ -231,7 +229,7 @@ module.exports = CompileManager = {
OutputFileFinder.findOutputFiles( OutputFileFinder.findOutputFiles(
resourceList, resourceList,
compileDir, compileDir,
function(err, outputFiles) { function (err, outputFiles) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
@ -289,7 +287,7 @@ module.exports = CompileManager = {
return OutputFileFinder.findOutputFiles( return OutputFileFinder.findOutputFiles(
resourceList, resourceList,
compileDir, compileDir,
function(error, outputFiles) { function (error, outputFiles) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -309,7 +307,7 @@ module.exports = CompileManager = {
stopCompile(project_id, user_id, callback) { stopCompile(project_id, user_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const compileName = getCompileName(project_id, user_id) const compileName = getCompileName(project_id, user_id)
return LatexRunner.killLatex(compileName, callback) return LatexRunner.killLatex(compileName, callback)
@ -317,16 +315,16 @@ module.exports = CompileManager = {
clearProject(project_id, user_id, _callback) { clearProject(project_id, user_id, _callback) {
if (_callback == null) { if (_callback == null) {
_callback = function(error) {} _callback = function (error) {}
} }
const callback = function(error) { const callback = function (error) {
_callback(error) _callback(error)
return (_callback = function() {}) return (_callback = function () {})
} }
const compileDir = getCompileDir(project_id, user_id) const compileDir = getCompileDir(project_id, user_id)
return CompileManager._checkDirectory(compileDir, function(err, exists) { return CompileManager._checkDirectory(compileDir, function (err, exists) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
@ -339,9 +337,9 @@ module.exports = CompileManager = {
proc.on('error', callback) proc.on('error', callback)
let stderr = '' let stderr = ''
proc.stderr.setEncoding('utf8').on('data', chunk => (stderr += chunk)) proc.stderr.setEncoding('utf8').on('data', (chunk) => (stderr += chunk))
return proc.on('close', function(code) { return proc.on('close', function (code) {
if (code === 0) { if (code === 0) {
return callback(null) return callback(null)
} else { } else {
@ -353,26 +351,26 @@ module.exports = CompileManager = {
_findAllDirs(callback) { _findAllDirs(callback) {
if (callback == null) { if (callback == null) {
callback = function(error, allDirs) {} callback = function (error, allDirs) {}
} }
const root = Settings.path.compilesDir const root = Settings.path.compilesDir
return fs.readdir(root, function(err, files) { return fs.readdir(root, function (err, files) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
const allDirs = Array.from(files).map(file => Path.join(root, file)) const allDirs = Array.from(files).map((file) => Path.join(root, file))
return callback(null, allDirs) return callback(null, allDirs)
}) })
}, },
clearExpiredProjects(max_cache_age_ms, callback) { clearExpiredProjects(max_cache_age_ms, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const now = Date.now() const now = Date.now()
// action for each directory // action for each directory
const expireIfNeeded = (checkDir, cb) => const expireIfNeeded = (checkDir, cb) =>
fs.stat(checkDir, function(err, stats) { fs.stat(checkDir, function (err, stats) {
if (err != null) { if (err != null) {
return cb() return cb()
} // ignore errors checking directory } // ignore errors checking directory
@ -385,7 +383,7 @@ module.exports = CompileManager = {
} }
}) })
// iterate over all project directories // iterate over all project directories
return CompileManager._findAllDirs(function(error, allDirs) { return CompileManager._findAllDirs(function (error, allDirs) {
if (error != null) { if (error != null) {
return callback() return callback()
} }
@ -395,9 +393,9 @@ module.exports = CompileManager = {
_checkDirectory(compileDir, callback) { _checkDirectory(compileDir, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, exists) {} callback = function (error, exists) {}
} }
return fs.lstat(compileDir, function(err, stats) { return fs.lstat(compileDir, function (err, stats) {
if ((err != null ? err.code : undefined) === 'ENOENT') { if ((err != null ? err.code : undefined) === 'ENOENT') {
return callback(null, false) // directory does not exist return callback(null, false) // directory does not exist
} else if (err != null) { } else if (err != null) {
@ -423,7 +421,7 @@ module.exports = CompileManager = {
// might not match the file path on the host. The .synctex.gz file however, will be accessed // might not match the file path on the host. The .synctex.gz file however, will be accessed
// wherever it is on the host. // wherever it is on the host.
if (callback == null) { if (callback == null) {
callback = function(error, pdfPositions) {} callback = function (error, pdfPositions) {}
} }
const compileName = getCompileName(project_id, user_id) const compileName = getCompileName(project_id, user_id)
const base_dir = Settings.path.synctexBaseDir(compileName) const base_dir = Settings.path.synctexBaseDir(compileName)
@ -431,7 +429,7 @@ module.exports = CompileManager = {
const compileDir = getCompileDir(project_id, user_id) const compileDir = getCompileDir(project_id, user_id)
const synctex_path = `${base_dir}/output.pdf` const synctex_path = `${base_dir}/output.pdf`
const command = ['code', synctex_path, file_path, line, column] const command = ['code', synctex_path, file_path, line, column]
CompileManager._runSynctex(project_id, user_id, command, function( CompileManager._runSynctex(project_id, user_id, command, function (
error, error,
stdout stdout
) { ) {
@ -448,14 +446,14 @@ module.exports = CompileManager = {
syncFromPdf(project_id, user_id, page, h, v, callback) { syncFromPdf(project_id, user_id, page, h, v, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, filePositions) {} callback = function (error, filePositions) {}
} }
const compileName = getCompileName(project_id, user_id) const compileName = getCompileName(project_id, user_id)
const compileDir = getCompileDir(project_id, user_id) const compileDir = getCompileDir(project_id, user_id)
const base_dir = Settings.path.synctexBaseDir(compileName) const base_dir = Settings.path.synctexBaseDir(compileName)
const synctex_path = `${base_dir}/output.pdf` const synctex_path = `${base_dir}/output.pdf`
const command = ['pdf', synctex_path, page, h, v] const command = ['pdf', synctex_path, page, h, v]
CompileManager._runSynctex(project_id, user_id, command, function( CompileManager._runSynctex(project_id, user_id, command, function (
error, error,
stdout stdout
) { ) {
@ -475,17 +473,17 @@ module.exports = CompileManager = {
_checkFileExists(dir, filename, callback) { _checkFileExists(dir, filename, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const file = Path.join(dir, filename) const file = Path.join(dir, filename)
return fs.stat(dir, function(error, stats) { return fs.stat(dir, function (error, stats) {
if ((error != null ? error.code : undefined) === 'ENOENT') { if ((error != null ? error.code : undefined) === 'ENOENT') {
return callback(new Errors.NotFoundError('no output directory')) return callback(new Errors.NotFoundError('no output directory'))
} }
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return fs.stat(file, function(error, stats) { return fs.stat(file, function (error, stats) {
if ((error != null ? error.code : undefined) === 'ENOENT') { if ((error != null ? error.code : undefined) === 'ENOENT') {
return callback(new Errors.NotFoundError('no output file')) return callback(new Errors.NotFoundError('no output file'))
} }
@ -502,7 +500,7 @@ module.exports = CompileManager = {
_runSynctex(project_id, user_id, command, callback) { _runSynctex(project_id, user_id, command, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, stdout) {} callback = function (error, stdout) {}
} }
const seconds = 1000 const seconds = 1000
@ -512,7 +510,7 @@ module.exports = CompileManager = {
const timeout = 60 * 1000 // increased to allow for large projects const timeout = 60 * 1000 // increased to allow for large projects
const compileName = getCompileName(project_id, user_id) const compileName = getCompileName(project_id, user_id)
const compileGroup = 'synctex' const compileGroup = 'synctex'
CompileManager._checkFileExists(directory, 'output.synctex.gz', error => { CompileManager._checkFileExists(directory, 'output.synctex.gz', (error) => {
if (error) { if (error) {
return callback(error) return callback(error)
} }
@ -526,7 +524,7 @@ module.exports = CompileManager = {
timeout, timeout,
{}, {},
compileGroup, compileGroup,
function(error, output) { function (error, output) {
if (error != null) { if (error != null) {
logger.err( logger.err(
{ err: error, command, project_id, user_id }, { err: error, command, project_id, user_id },
@ -576,7 +574,7 @@ module.exports = CompileManager = {
wordcount(project_id, user_id, file_name, image, callback) { wordcount(project_id, user_id, file_name, image, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, pdfPositions) {} callback = function (error, pdfPositions) {}
} }
logger.log({ project_id, user_id, file_name, image }, 'running wordcount') logger.log({ project_id, user_id, file_name, image }, 'running wordcount')
const file_path = `$COMPILE_DIR/${file_name}` const file_path = `$COMPILE_DIR/${file_name}`
@ -591,7 +589,7 @@ module.exports = CompileManager = {
const timeout = 60 * 1000 const timeout = 60 * 1000
const compileName = getCompileName(project_id, user_id) const compileName = getCompileName(project_id, user_id)
const compileGroup = 'wordcount' const compileGroup = 'wordcount'
return fse.ensureDir(compileDir, function(error) { return fse.ensureDir(compileDir, function (error) {
if (error != null) { if (error != null) {
logger.err( logger.err(
{ error, project_id, user_id, file_name }, { error, project_id, user_id, file_name },
@ -607,14 +605,14 @@ module.exports = CompileManager = {
timeout, timeout,
{}, {},
compileGroup, compileGroup,
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return fs.readFile( return fs.readFile(
compileDir + '/' + file_name + '.wc', compileDir + '/' + file_name + '.wc',
'utf-8', 'utf-8',
function(err, stdout) { function (err, stdout) {
if (err != null) { if (err != null) {
// call it node_err so sentry doesn't use random path error as unique id so it can't be ignored // call it node_err so sentry doesn't use random path error as unique id so it can't be ignored
logger.err( logger.err(

View file

@ -23,7 +23,7 @@ module.exports = LockManager = {
tryLock(key, callback) { tryLock(key, callback) {
let lockValue let lockValue
if (callback == null) { if (callback == null) {
callback = function(err, gotLock) {} callback = function (err, gotLock) {}
} }
const existingLock = LockState[key] const existingLock = LockState[key]
if (existingLock != null) { if (existingLock != null) {
@ -46,11 +46,11 @@ module.exports = LockManager = {
getLock(key, callback) { getLock(key, callback) {
let attempt let attempt
if (callback == null) { if (callback == null) {
callback = function(error, lockValue) {} callback = function (error, lockValue) {}
} }
const startTime = Date.now() const startTime = Date.now()
return (attempt = () => return (attempt = () =>
LockManager.tryLock(key, function(error, gotLock, lockValue) { LockManager.tryLock(key, function (error, gotLock, lockValue) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -68,7 +68,7 @@ module.exports = LockManager = {
releaseLock(key, lockValue, callback) { releaseLock(key, lockValue, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const existingLock = LockState[key] const existingLock = LockState[key]
if (existingLock === lockValue) { if (existingLock === lockValue) {
@ -93,14 +93,14 @@ module.exports = LockManager = {
runWithLock(key, runner, callback) { runWithLock(key, runner, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return LockManager.getLock(key, function(error, lockValue) { return LockManager.getLock(key, function (error, lockValue) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return runner((error1, ...args) => return runner((error1, ...args) =>
LockManager.releaseLock(key, lockValue, function(error2) { LockManager.releaseLock(key, lockValue, function (error2) {
error = error1 || error2 error = error1 || error2
if (error != null) { if (error != null) {
return callback(error) return callback(error)

View file

@ -32,7 +32,7 @@ logger.info('using docker runner')
const usingSiblingContainers = () => const usingSiblingContainers = () =>
__guard__( __guard__(
Settings != null ? Settings.path : undefined, Settings != null ? Settings.path : undefined,
x => x.sandboxedCompilesHostDir (x) => x.sandboxedCompilesHostDir
) != null ) != null
let containerMonitorTimeout let containerMonitorTimeout
@ -56,7 +56,7 @@ module.exports = DockerRunner = {
) { ) {
let name let name
if (callback == null) { if (callback == null) {
callback = function(error, output) {} callback = function (error, output) {}
} }
if (usingSiblingContainers()) { if (usingSiblingContainers()) {
const _newPath = Settings.path.sandboxedCompilesHostDir const _newPath = Settings.path.sandboxedCompilesHostDir
@ -77,8 +77,8 @@ module.exports = DockerRunner = {
const volumes = {} const volumes = {}
volumes[directory] = '/compile' volumes[directory] = '/compile'
command = Array.from(command).map(arg => command = Array.from(command).map((arg) =>
__guardMethod__(arg.toString(), 'replace', o => __guardMethod__(arg.toString(), 'replace', (o) =>
o.replace('$COMPILE_DIR', '/compile') o.replace('$COMPILE_DIR', '/compile')
) )
) )
@ -112,7 +112,7 @@ module.exports = DockerRunner = {
// logOptions = _.clone(options) // logOptions = _.clone(options)
// logOptions?.HostConfig?.SecurityOpt = "secomp used, removed in logging" // logOptions?.HostConfig?.SecurityOpt = "secomp used, removed in logging"
logger.log({ project_id }, 'running docker container') logger.log({ project_id }, 'running docker container')
DockerRunner._runAndWaitForContainer(options, volumes, timeout, function( DockerRunner._runAndWaitForContainer(options, volumes, timeout, function (
error, error,
output output
) { ) {
@ -121,7 +121,9 @@ module.exports = DockerRunner = {
{ err: error, project_id }, { err: error, project_id },
'error running container so destroying and retrying' 'error running container so destroying and retrying'
) )
return DockerRunner.destroyContainer(name, null, true, function(error) { return DockerRunner.destroyContainer(name, null, true, function (
error
) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -142,15 +144,17 @@ module.exports = DockerRunner = {
kill(container_id, callback) { kill(container_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
logger.log({ container_id }, 'sending kill signal to container') logger.log({ container_id }, 'sending kill signal to container')
const container = dockerode.getContainer(container_id) const container = dockerode.getContainer(container_id)
return container.kill(function(error) { return container.kill(function (error) {
if ( if (
error != null && error != null &&
__guardMethod__(error != null ? error.message : undefined, 'match', o => __guardMethod__(
o.match(/Cannot kill container .* is not running/) error != null ? error.message : undefined,
'match',
(o) => o.match(/Cannot kill container .* is not running/)
) )
) { ) {
logger.warn( logger.warn(
@ -170,12 +174,12 @@ module.exports = DockerRunner = {
_runAndWaitForContainer(options, volumes, timeout, _callback) { _runAndWaitForContainer(options, volumes, timeout, _callback) {
if (_callback == null) { if (_callback == null) {
_callback = function(error, output) {} _callback = function (error, output) {}
} }
const callback = function(...args) { const callback = function (...args) {
_callback(...Array.from(args || [])) _callback(...Array.from(args || []))
// Only call the callback once // Only call the callback once
return (_callback = function() {}) return (_callback = function () {})
} }
const { name } = options const { name } = options
@ -184,13 +188,13 @@ module.exports = DockerRunner = {
let containerReturned = false let containerReturned = false
let output = {} let output = {}
const callbackIfFinished = function() { const callbackIfFinished = function () {
if (streamEnded && containerReturned) { if (streamEnded && containerReturned) {
return callback(null, output) return callback(null, output)
} }
} }
const attachStreamHandler = function(error, _output) { const attachStreamHandler = function (error, _output) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -203,12 +207,12 @@ module.exports = DockerRunner = {
options, options,
volumes, volumes,
attachStreamHandler, attachStreamHandler,
function(error, containerId) { function (error, containerId) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return DockerRunner.waitForContainer(name, timeout, function( return DockerRunner.waitForContainer(name, timeout, function (
error, error,
exitCode exitCode
) { ) {
@ -231,7 +235,7 @@ module.exports = DockerRunner = {
containerReturned = true containerReturned = true
__guard__( __guard__(
options != null ? options.HostConfig : undefined, options != null ? options.HostConfig : undefined,
x => (x.SecurityOpt = null) (x) => (x.SecurityOpt = null)
) // small log line ) // small log line
logger.log({ err, exitCode, options }, 'docker container has exited') logger.log({ err, exitCode, options }, 'docker container has exited')
return callbackIfFinished() return callbackIfFinished()
@ -357,21 +361,18 @@ module.exports = DockerRunner = {
_fingerprintContainer(containerOptions) { _fingerprintContainer(containerOptions) {
// Yay, Hashing! // Yay, Hashing!
const json = JSON.stringify(containerOptions) const json = JSON.stringify(containerOptions)
return crypto return crypto.createHash('md5').update(json).digest('hex')
.createHash('md5')
.update(json)
.digest('hex')
}, },
startContainer(options, volumes, attachStreamHandler, callback) { startContainer(options, volumes, attachStreamHandler, callback) {
return LockManager.runWithLock( return LockManager.runWithLock(
options.name, options.name,
releaseLock => (releaseLock) =>
// Check that volumes exist before starting the container. // Check that volumes exist before starting the container.
// When a container is started with volume pointing to a // When a container is started with volume pointing to a
// non-existent directory then docker creates the directory but // non-existent directory then docker creates the directory but
// with root ownership. // with root ownership.
DockerRunner._checkVolumes(options, volumes, function(err) { DockerRunner._checkVolumes(options, volumes, function (err) {
if (err != null) { if (err != null) {
return releaseLock(err) return releaseLock(err)
} }
@ -390,7 +391,7 @@ module.exports = DockerRunner = {
// Check that volumes exist and are directories // Check that volumes exist and are directories
_checkVolumes(options, volumes, callback) { _checkVolumes(options, volumes, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, containerName) {} callback = function (error, containerName) {}
} }
if (usingSiblingContainers()) { if (usingSiblingContainers()) {
// Server Pro, with sibling-containers active, skip checks // Server Pro, with sibling-containers active, skip checks
@ -398,7 +399,7 @@ module.exports = DockerRunner = {
} }
const checkVolume = (path, cb) => const checkVolume = (path, cb) =>
fs.stat(path, function(err, stats) { fs.stat(path, function (err, stats) {
if (err != null) { if (err != null) {
return cb(err) return cb(err)
} }
@ -409,14 +410,14 @@ module.exports = DockerRunner = {
}) })
const jobs = [] const jobs = []
for (const vol in volumes) { for (const vol in volumes) {
;(vol => jobs.push(cb => checkVolume(vol, cb)))(vol) ;((vol) => jobs.push((cb) => checkVolume(vol, cb)))(vol)
} }
return async.series(jobs, callback) return async.series(jobs, callback)
}, },
_startContainer(options, volumes, attachStreamHandler, callback) { _startContainer(options, volumes, attachStreamHandler, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, output) {} callback = function (error, output) {}
} }
callback = _.once(callback) callback = _.once(callback)
const { name } = options const { name } = options
@ -425,7 +426,7 @@ module.exports = DockerRunner = {
const container = dockerode.getContainer(name) const container = dockerode.getContainer(name)
const createAndStartContainer = () => const createAndStartContainer = () =>
dockerode.createContainer(options, function(error, container) { dockerode.createContainer(options, function (error, container) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -435,11 +436,11 @@ module.exports = DockerRunner = {
DockerRunner.attachToContainer( DockerRunner.attachToContainer(
options.name, options.name,
attachStreamHandler, attachStreamHandler,
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return container.start(function(error) { return container.start(function (error) {
if ( if (
error != null && error != null &&
(error != null ? error.statusCode : undefined) !== 304 (error != null ? error.statusCode : undefined) !== 304
@ -452,7 +453,7 @@ module.exports = DockerRunner = {
}) })
} }
) )
return container.inspect(function(error, stats) { return container.inspect(function (error, stats) {
if ((error != null ? error.statusCode : undefined) === 404) { if ((error != null ? error.statusCode : undefined) === 404) {
return createAndStartContainer() return createAndStartContainer()
} else if (error != null) { } else if (error != null) {
@ -469,7 +470,7 @@ module.exports = DockerRunner = {
attachToContainer(containerId, attachStreamHandler, attachStartCallback) { attachToContainer(containerId, attachStreamHandler, attachStartCallback) {
const container = dockerode.getContainer(containerId) const container = dockerode.getContainer(containerId)
return container.attach({ stdout: 1, stderr: 1, stream: 1 }, function( return container.attach({ stdout: 1, stderr: 1, stream: 1 }, function (
error, error,
stream stream
) { ) {
@ -486,7 +487,7 @@ module.exports = DockerRunner = {
logger.log({ container_id: containerId }, 'attached to container') logger.log({ container_id: containerId }, 'attached to container')
const MAX_OUTPUT = 1024 * 1024 // limit output to 1MB const MAX_OUTPUT = 1024 * 1024 // limit output to 1MB
const createStringOutputStream = function(name) { const createStringOutputStream = function (name) {
return { return {
data: '', data: '',
overflowed: false, overflowed: false,
@ -519,7 +520,7 @@ module.exports = DockerRunner = {
container.modem.demuxStream(stream, stdout, stderr) container.modem.demuxStream(stream, stdout, stderr)
stream.on('error', err => stream.on('error', (err) =>
logger.error( logger.error(
{ err, container_id: containerId }, { err, container_id: containerId },
'error reading from container stream' 'error reading from container stream'
@ -534,28 +535,28 @@ module.exports = DockerRunner = {
waitForContainer(containerId, timeout, _callback) { waitForContainer(containerId, timeout, _callback) {
if (_callback == null) { if (_callback == null) {
_callback = function(error, exitCode) {} _callback = function (error, exitCode) {}
} }
const callback = function(...args) { const callback = function (...args) {
_callback(...Array.from(args || [])) _callback(...Array.from(args || []))
// Only call the callback once // Only call the callback once
return (_callback = function() {}) return (_callback = function () {})
} }
const container = dockerode.getContainer(containerId) const container = dockerode.getContainer(containerId)
let timedOut = false let timedOut = false
const timeoutId = setTimeout(function() { const timeoutId = setTimeout(function () {
timedOut = true timedOut = true
logger.log( logger.log(
{ container_id: containerId }, { container_id: containerId },
'timeout reached, killing container' 'timeout reached, killing container'
) )
return container.kill(function() {}) return container.kill(function () {})
}, timeout) }, timeout)
logger.log({ container_id: containerId }, 'waiting for docker container') logger.log({ container_id: containerId }, 'waiting for docker container')
return container.wait(function(error, res) { return container.wait(function (error, res) {
if (error != null) { if (error != null) {
clearTimeout(timeoutId) clearTimeout(timeoutId)
logger.error( logger.error(
@ -588,11 +589,11 @@ module.exports = DockerRunner = {
// error callback. We fall back to deleting by name if no id is // error callback. We fall back to deleting by name if no id is
// supplied. // supplied.
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return LockManager.runWithLock( return LockManager.runWithLock(
containerName, containerName,
releaseLock => (releaseLock) =>
DockerRunner._destroyContainer( DockerRunner._destroyContainer(
containerId || containerName, containerId || containerName,
shouldForce, shouldForce,
@ -604,11 +605,11 @@ module.exports = DockerRunner = {
_destroyContainer(containerId, shouldForce, callback) { _destroyContainer(containerId, shouldForce, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
logger.log({ container_id: containerId }, 'destroying docker container') logger.log({ container_id: containerId }, 'destroying docker container')
const container = dockerode.getContainer(containerId) const container = dockerode.getContainer(containerId)
return container.remove({ force: shouldForce === true }, function(error) { return container.remove({ force: shouldForce === true }, function (error) {
if ( if (
error != null && error != null &&
(error != null ? error.statusCode : undefined) === 404 (error != null ? error.statusCode : undefined) === 404
@ -638,7 +639,7 @@ module.exports = DockerRunner = {
examineOldContainer(container, callback) { examineOldContainer(container, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, name, id, ttl) {} callback = function (error, name, id, ttl) {}
} }
const name = const name =
container.Name || container.Name ||
@ -657,16 +658,19 @@ module.exports = DockerRunner = {
destroyOldContainers(callback) { destroyOldContainers(callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return dockerode.listContainers({ all: true }, function(error, containers) { return dockerode.listContainers({ all: true }, function (
error,
containers
) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
const jobs = [] const jobs = []
for (const container of Array.from(containers || [])) { for (const container of Array.from(containers || [])) {
;(container => ;((container) =>
DockerRunner.examineOldContainer(container, function( DockerRunner.examineOldContainer(container, function (
err, err,
name, name,
id, id,
@ -676,7 +680,7 @@ module.exports = DockerRunner = {
// strip the / prefix // strip the / prefix
// the LockManager uses the plain container name // the LockManager uses the plain container name
name = name.slice(1) name = name.slice(1)
return jobs.push(cb => return jobs.push((cb) =>
DockerRunner.destroyContainer(name, id, false, () => cb()) DockerRunner.destroyContainer(name, id, false, () => cb())
) )
} }

View file

@ -18,9 +18,9 @@ const logger = require('logger-sharelatex')
module.exports = DraftModeManager = { module.exports = DraftModeManager = {
injectDraftMode(filename, callback) { injectDraftMode(filename, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return fs.readFile(filename, 'utf8', function(error, content) { return fs.readFile(filename, 'utf8', function (error, content) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }

View file

@ -5,7 +5,7 @@
// TODO: This file was created by bulk-decaffeinate. // TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint. // Fix any style issues and re-enable lint.
let Errors let Errors
var NotFoundError = function(message) { var NotFoundError = function (message) {
const error = new Error(message) const error = new Error(message)
error.name = 'NotFoundError' error.name = 'NotFoundError'
error.__proto__ = NotFoundError.prototype error.__proto__ = NotFoundError.prototype
@ -13,7 +13,7 @@ var NotFoundError = function(message) {
} }
NotFoundError.prototype.__proto__ = Error.prototype NotFoundError.prototype.__proto__ = Error.prototype
var FilesOutOfSyncError = function(message) { var FilesOutOfSyncError = function (message) {
const error = new Error(message) const error = new Error(message)
error.name = 'FilesOutOfSyncError' error.name = 'FilesOutOfSyncError'
error.__proto__ = FilesOutOfSyncError.prototype error.__proto__ = FilesOutOfSyncError.prototype
@ -21,7 +21,7 @@ var FilesOutOfSyncError = function(message) {
} }
FilesOutOfSyncError.prototype.__proto__ = Error.prototype FilesOutOfSyncError.prototype.__proto__ = Error.prototype
var AlreadyCompilingError = function(message) { var AlreadyCompilingError = function (message) {
const error = new Error(message) const error = new Error(message)
error.name = 'AlreadyCompilingError' error.name = 'AlreadyCompilingError'
error.__proto__ = AlreadyCompilingError.prototype error.__proto__ = AlreadyCompilingError.prototype

View file

@ -27,7 +27,7 @@ module.exports = LatexRunner = {
runLatex(project_id, options, callback) { runLatex(project_id, options, callback) {
let command let command
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
let { let {
directory, directory,
@ -89,20 +89,20 @@ module.exports = LatexRunner = {
timeout, timeout,
environment, environment,
compileGroup, compileGroup,
function(error, output) { function (error, output) {
delete ProcessTable[id] delete ProcessTable[id]
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
const runs = const runs =
__guard__( __guard__(
__guard__(output != null ? output.stderr : undefined, x1 => __guard__(output != null ? output.stderr : undefined, (x1) =>
x1.match(/^Run number \d+ of .*latex/gm) x1.match(/^Run number \d+ of .*latex/gm)
), ),
x => x.length (x) => x.length
) || 0 ) || 0
const failed = const failed =
__guard__(output != null ? output.stdout : undefined, x2 => __guard__(output != null ? output.stdout : undefined, (x2) =>
x2.match(/^Latexmk: Errors/m) x2.match(/^Latexmk: Errors/m)
) != null ) != null
? 1 ? 1
@ -122,21 +122,21 @@ module.exports = LatexRunner = {
stderr != null stderr != null
? stderr.match(/Percent of CPU this job got: (\d+)/m) ? stderr.match(/Percent of CPU this job got: (\d+)/m)
: undefined, : undefined,
x3 => x3[1] (x3) => x3[1]
) || 0 ) || 0
timings['cpu-time'] = timings['cpu-time'] =
__guard__( __guard__(
stderr != null stderr != null
? stderr.match(/User time.*: (\d+.\d+)/m) ? stderr.match(/User time.*: (\d+.\d+)/m)
: undefined, : undefined,
x4 => x4[1] (x4) => x4[1]
) || 0 ) || 0
timings['sys-time'] = timings['sys-time'] =
__guard__( __guard__(
stderr != null stderr != null
? stderr.match(/System time.*: (\d+.\d+)/m) ? stderr.match(/System time.*: (\d+.\d+)/m)
: undefined, : undefined,
x5 => x5[1] (x5) => x5[1]
) || 0 ) || 0
// record output files // record output files
LatexRunner.writeLogOutput(project_id, directory, output, () => { LatexRunner.writeLogOutput(project_id, directory, output, () => {
@ -153,7 +153,7 @@ module.exports = LatexRunner = {
// internal method for writing non-empty log files // internal method for writing non-empty log files
function _writeFile(file, content, cb) { function _writeFile(file, content, cb) {
if (content && content.length > 0) { if (content && content.length > 0) {
fs.writeFile(file, content, err => { fs.writeFile(file, content, (err) => {
if (err) { if (err) {
logger.error({ project_id, file }, 'error writing log file') // don't fail on error logger.error({ project_id, file }, 'error writing log file') // don't fail on error
} }
@ -173,7 +173,7 @@ module.exports = LatexRunner = {
killLatex(project_id, callback) { killLatex(project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const id = `${project_id}` const id = `${project_id}`
logger.log({ id }, 'killing running compile') logger.log({ id }, 'killing running compile')
@ -202,7 +202,7 @@ module.exports = LatexRunner = {
return ( return (
__guard__( __guard__(
Settings != null ? Settings.clsi : undefined, Settings != null ? Settings.clsi : undefined,
x => x.latexmkCommandPrefix (x) => x.latexmkCommandPrefix
) || [] ) || []
).concat(args) ).concat(args)
}, },

View file

@ -33,11 +33,11 @@ module.exports = CommandRunner = {
) { ) {
let key, value let key, value
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} else { } else {
callback = _.once(callback) callback = _.once(callback)
} }
command = Array.from(command).map(arg => command = Array.from(command).map((arg) =>
arg.toString().replace('$COMPILE_DIR', directory) arg.toString().replace('$COMPILE_DIR', directory)
) )
logger.log({ project_id, command, directory }, 'running command') logger.log({ project_id, command, directory }, 'running command')
@ -58,9 +58,9 @@ module.exports = CommandRunner = {
const proc = spawn(command[0], command.slice(1), { cwd: directory, env }) const proc = spawn(command[0], command.slice(1), { cwd: directory, env })
let stdout = '' let stdout = ''
proc.stdout.setEncoding('utf8').on('data', data => (stdout += data)) proc.stdout.setEncoding('utf8').on('data', (data) => (stdout += data))
proc.on('error', function(err) { proc.on('error', function (err) {
logger.err( logger.err(
{ err, project_id, command, directory }, { err, project_id, command, directory },
'error running command' 'error running command'
@ -68,7 +68,7 @@ module.exports = CommandRunner = {
return callback(err) return callback(err)
}) })
proc.on('close', function(code, signal) { proc.on('close', function (code, signal) {
let err let err
logger.info({ code, signal, project_id }, 'command exited') logger.info({ code, signal, project_id }, 'command exited')
if (signal === 'SIGTERM') { if (signal === 'SIGTERM') {
@ -91,7 +91,7 @@ module.exports = CommandRunner = {
kill(pid, callback) { kill(pid, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
try { try {
process.kill(-pid) // kill all processes in group process.kill(-pid) // kill all processes in group

View file

@ -25,20 +25,20 @@ module.exports = LockManager = {
runWithLock(path, runner, callback) { runWithLock(path, runner, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const lockOpts = { const lockOpts = {
wait: this.MAX_LOCK_WAIT_TIME, wait: this.MAX_LOCK_WAIT_TIME,
pollPeriod: this.LOCK_TEST_INTERVAL, pollPeriod: this.LOCK_TEST_INTERVAL,
stale: this.LOCK_STALE stale: this.LOCK_STALE
} }
return Lockfile.lock(path, lockOpts, function(error) { return Lockfile.lock(path, lockOpts, function (error) {
if ((error != null ? error.code : undefined) === 'EEXIST') { if ((error != null ? error.code : undefined) === 'EEXIST') {
return callback(new Errors.AlreadyCompilingError('compile in progress')) return callback(new Errors.AlreadyCompilingError('compile in progress'))
} else if (error != null) { } else if (error != null) {
return fs.lstat(path, (statLockErr, statLock) => return fs.lstat(path, (statLockErr, statLock) =>
fs.lstat(Path.dirname(path), (statDirErr, statDir) => fs.lstat(Path.dirname(path), (statDirErr, statDir) =>
fs.readdir(Path.dirname(path), function(readdirErr, readdirDir) { fs.readdir(Path.dirname(path), function (readdirErr, readdirDir) {
logger.err( logger.err(
{ {
error, error,
@ -58,7 +58,7 @@ module.exports = LockManager = {
) )
} else { } else {
return runner((error1, ...args) => return runner((error1, ...args) =>
Lockfile.unlock(path, function(error2) { Lockfile.unlock(path, function (error2) {
error = error1 || error2 error = error1 || error2
if (error != null) { if (error != null) {
return callback(error) return callback(error)

View file

@ -47,9 +47,9 @@ module.exports = OutputCacheManager = {
generateBuildId(callback) { generateBuildId(callback) {
// generate a secure build id from Date.now() and 8 random bytes in hex // generate a secure build id from Date.now() and 8 random bytes in hex
if (callback == null) { if (callback == null) {
callback = function(error, buildId) {} callback = function (error, buildId) {}
} }
return crypto.randomBytes(8, function(err, buf) { return crypto.randomBytes(8, function (err, buf) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
@ -61,9 +61,9 @@ module.exports = OutputCacheManager = {
saveOutputFiles(outputFiles, compileDir, callback) { saveOutputFiles(outputFiles, compileDir, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return OutputCacheManager.generateBuildId(function(err, buildId) { return OutputCacheManager.generateBuildId(function (err, buildId) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
@ -80,7 +80,7 @@ module.exports = OutputCacheManager = {
// make a compileDir/CACHE_SUBDIR/build_id directory and // make a compileDir/CACHE_SUBDIR/build_id directory and
// copy all the output files into it // copy all the output files into it
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const cacheRoot = Path.join(compileDir, OutputCacheManager.CACHE_SUBDIR) const cacheRoot = Path.join(compileDir, OutputCacheManager.CACHE_SUBDIR)
// Put the files into a new cache subdirectory // Put the files into a new cache subdirectory
@ -99,17 +99,20 @@ module.exports = OutputCacheManager = {
(Settings.clsi != null ? Settings.clsi.archive_logs : undefined) || (Settings.clsi != null ? Settings.clsi.archive_logs : undefined) ||
(Settings.clsi != null ? Settings.clsi.strace : undefined) (Settings.clsi != null ? Settings.clsi.strace : undefined)
) { ) {
OutputCacheManager.archiveLogs(outputFiles, compileDir, buildId, function( OutputCacheManager.archiveLogs(
err outputFiles,
) { compileDir,
if (err != null) { buildId,
return logger.warn({ err }, 'erroring archiving log files') function (err) {
if (err != null) {
return logger.warn({ err }, 'erroring archiving log files')
}
} }
}) )
} }
// make the new cache directory // make the new cache directory
return fse.ensureDir(cacheDir, function(err) { return fse.ensureDir(cacheDir, function (err) {
if (err != null) { if (err != null) {
logger.error( logger.error(
{ err, directory: cacheDir }, { err, directory: cacheDir },
@ -121,7 +124,7 @@ module.exports = OutputCacheManager = {
const results = [] const results = []
return async.mapSeries( return async.mapSeries(
outputFiles, outputFiles,
function(file, cb) { function (file, cb) {
// don't send dot files as output, express doesn't serve them // don't send dot files as output, express doesn't serve them
if (OutputCacheManager._fileIsHidden(file.path)) { if (OutputCacheManager._fileIsHidden(file.path)) {
logger.debug( logger.debug(
@ -136,7 +139,7 @@ module.exports = OutputCacheManager = {
Path.join(compileDir, file.path), Path.join(compileDir, file.path),
Path.join(cacheDir, file.path) Path.join(cacheDir, file.path)
]) ])
return OutputCacheManager._checkFileIsSafe(src, function( return OutputCacheManager._checkFileIsSafe(src, function (
err, err,
isSafe isSafe
) { ) {
@ -146,7 +149,7 @@ module.exports = OutputCacheManager = {
if (!isSafe) { if (!isSafe) {
return cb() return cb()
} }
return OutputCacheManager._checkIfShouldCopy(src, function( return OutputCacheManager._checkIfShouldCopy(src, function (
err, err,
shouldCopy shouldCopy
) { ) {
@ -156,7 +159,7 @@ module.exports = OutputCacheManager = {
if (!shouldCopy) { if (!shouldCopy) {
return cb() return cb()
} }
return OutputCacheManager._copyFile(src, dst, function(err) { return OutputCacheManager._copyFile(src, dst, function (err) {
if (err != null) { if (err != null) {
return cb(err) return cb(err)
} }
@ -167,12 +170,12 @@ module.exports = OutputCacheManager = {
}) })
}) })
}, },
function(err) { function (err) {
if (err != null) { if (err != null) {
// pass back the original files if we encountered *any* error // pass back the original files if we encountered *any* error
callback(err, outputFiles) callback(err, outputFiles)
// clean up the directory we just created // clean up the directory we just created
return fse.remove(cacheDir, function(err) { return fse.remove(cacheDir, function (err) {
if (err != null) { if (err != null) {
return logger.error( return logger.error(
{ err, dir: cacheDir }, { err, dir: cacheDir },
@ -197,7 +200,7 @@ module.exports = OutputCacheManager = {
archiveLogs(outputFiles, compileDir, buildId, callback) { archiveLogs(outputFiles, compileDir, buildId, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const archiveDir = Path.join( const archiveDir = Path.join(
compileDir, compileDir,
@ -205,18 +208,18 @@ module.exports = OutputCacheManager = {
buildId buildId
) )
logger.log({ dir: archiveDir }, 'archiving log files for project') logger.log({ dir: archiveDir }, 'archiving log files for project')
return fse.ensureDir(archiveDir, function(err) { return fse.ensureDir(archiveDir, function (err) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
return async.mapSeries( return async.mapSeries(
outputFiles, outputFiles,
function(file, cb) { function (file, cb) {
const [src, dst] = Array.from([ const [src, dst] = Array.from([
Path.join(compileDir, file.path), Path.join(compileDir, file.path),
Path.join(archiveDir, file.path) Path.join(archiveDir, file.path)
]) ])
return OutputCacheManager._checkFileIsSafe(src, function( return OutputCacheManager._checkFileIsSafe(src, function (
err, err,
isSafe isSafe
) { ) {
@ -226,7 +229,7 @@ module.exports = OutputCacheManager = {
if (!isSafe) { if (!isSafe) {
return cb() return cb()
} }
return OutputCacheManager._checkIfShouldArchive(src, function( return OutputCacheManager._checkIfShouldArchive(src, function (
err, err,
shouldArchive shouldArchive
) { ) {
@ -248,9 +251,9 @@ module.exports = OutputCacheManager = {
expireOutputFiles(cacheRoot, options, callback) { expireOutputFiles(cacheRoot, options, callback) {
// look in compileDir for build dirs and delete if > N or age of mod time > T // look in compileDir for build dirs and delete if > N or age of mod time > T
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return fs.readdir(cacheRoot, function(err, results) { return fs.readdir(cacheRoot, function (err, results) {
if (err != null) { if (err != null) {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
return callback(null) return callback(null)
@ -262,7 +265,7 @@ module.exports = OutputCacheManager = {
const dirs = results.sort().reverse() const dirs = results.sort().reverse()
const currentTime = Date.now() const currentTime = Date.now()
const isExpired = function(dir, index) { const isExpired = function (dir, index) {
if ((options != null ? options.keep : undefined) === dir) { if ((options != null ? options.keep : undefined) === dir) {
return false return false
} }
@ -280,7 +283,7 @@ module.exports = OutputCacheManager = {
// we can get the build time from the first part of the directory name DDDD-RRRR // we can get the build time from the first part of the directory name DDDD-RRRR
// DDDD is date and RRRR is random bytes // DDDD is date and RRRR is random bytes
const dirTime = parseInt( const dirTime = parseInt(
__guard__(dir.split('-'), x => x[0]), __guard__(dir.split('-'), (x) => x[0]),
16 16
) )
const age = currentTime - dirTime const age = currentTime - dirTime
@ -290,7 +293,7 @@ module.exports = OutputCacheManager = {
const toRemove = _.filter(dirs, isExpired) const toRemove = _.filter(dirs, isExpired)
const removeDir = (dir, cb) => const removeDir = (dir, cb) =>
fse.remove(Path.join(cacheRoot, dir), function(err, result) { fse.remove(Path.join(cacheRoot, dir), function (err, result) {
logger.log({ cache: cacheRoot, dir }, 'removed expired cache dir') logger.log({ cache: cacheRoot, dir }, 'removed expired cache dir')
if (err != null) { if (err != null) {
logger.error({ err, dir }, 'cache remove error') logger.error({ err, dir }, 'cache remove error')
@ -312,9 +315,9 @@ module.exports = OutputCacheManager = {
_checkFileIsSafe(src, callback) { _checkFileIsSafe(src, callback) {
// check if we have a valid file to copy into the cache // check if we have a valid file to copy into the cache
if (callback == null) { if (callback == null) {
callback = function(error, isSafe) {} callback = function (error, isSafe) {}
} }
return fs.stat(src, function(err, stats) { return fs.stat(src, function (err, stats) {
if ((err != null ? err.code : undefined) === 'ENOENT') { if ((err != null ? err.code : undefined) === 'ENOENT') {
logger.warn( logger.warn(
{ err, file: src }, { err, file: src },
@ -341,7 +344,7 @@ module.exports = OutputCacheManager = {
_copyFile(src, dst, callback) { _copyFile(src, dst, callback) {
// copy output file into the cache // copy output file into the cache
return fse.copy(src, dst, function(err) { return fse.copy(src, dst, function (err) {
if ((err != null ? err.code : undefined) === 'ENOENT') { if ((err != null ? err.code : undefined) === 'ENOENT') {
logger.warn( logger.warn(
{ err, file: src }, { err, file: src },
@ -368,7 +371,7 @@ module.exports = OutputCacheManager = {
_checkIfShouldCopy(src, callback) { _checkIfShouldCopy(src, callback) {
if (callback == null) { if (callback == null) {
callback = function(err, shouldCopy) {} callback = function (err, shouldCopy) {}
} }
return callback(null, !Path.basename(src).match(/^strace/)) return callback(null, !Path.basename(src).match(/^strace/))
}, },
@ -376,7 +379,7 @@ module.exports = OutputCacheManager = {
_checkIfShouldArchive(src, callback) { _checkIfShouldArchive(src, callback) {
let needle let needle
if (callback == null) { if (callback == null) {
callback = function(err, shouldCopy) {} callback = function (err, shouldCopy) {}
} }
if (Path.basename(src).match(/^strace/)) { if (Path.basename(src).match(/^strace/)) {
return callback(null, true) return callback(null, true)

View file

@ -24,14 +24,14 @@ const logger = require('logger-sharelatex')
module.exports = OutputFileFinder = { module.exports = OutputFileFinder = {
findOutputFiles(resources, directory, callback) { findOutputFiles(resources, directory, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, outputFiles, allFiles) {} callback = function (error, outputFiles, allFiles) {}
} }
const incomingResources = {} const incomingResources = {}
for (const resource of Array.from(resources)) { for (const resource of Array.from(resources)) {
incomingResources[resource.path] = true incomingResources[resource.path] = true
} }
return OutputFileFinder._getAllFiles(directory, function(error, allFiles) { return OutputFileFinder._getAllFiles(directory, function (error, allFiles) {
if (allFiles == null) { if (allFiles == null) {
allFiles = [] allFiles = []
} }
@ -44,7 +44,7 @@ module.exports = OutputFileFinder = {
if (!incomingResources[file]) { if (!incomingResources[file]) {
outputFiles.push({ outputFiles.push({
path: file, path: file,
type: __guard__(file.match(/\.([^\.]+)$/), x => x[1]) type: __guard__(file.match(/\.([^\.]+)$/), (x) => x[1])
}) })
} }
} }
@ -54,11 +54,11 @@ module.exports = OutputFileFinder = {
_getAllFiles(directory, _callback) { _getAllFiles(directory, _callback) {
if (_callback == null) { if (_callback == null) {
_callback = function(error, fileList) {} _callback = function (error, fileList) {}
} }
const callback = function(error, fileList) { const callback = function (error, fileList) {
_callback(error, fileList) _callback(error, fileList)
return (_callback = function() {}) return (_callback = function () {})
} }
// don't include clsi-specific files/directories in the output list // don't include clsi-specific files/directories in the output list
@ -87,9 +87,9 @@ module.exports = OutputFileFinder = {
const proc = spawn('find', args) const proc = spawn('find', args)
let stdout = '' let stdout = ''
proc.stdout.setEncoding('utf8').on('data', chunk => (stdout += chunk)) proc.stdout.setEncoding('utf8').on('data', (chunk) => (stdout += chunk))
proc.on('error', callback) proc.on('error', callback)
return proc.on('close', function(code) { return proc.on('close', function (code) {
if (code !== 0) { if (code !== 0) {
logger.warn( logger.warn(
{ directory, code }, { directory, code },
@ -98,7 +98,7 @@ module.exports = OutputFileFinder = {
return callback(null, []) return callback(null, [])
} }
let fileList = stdout.trim().split('\n') let fileList = stdout.trim().split('\n')
fileList = fileList.map(function(file) { fileList = fileList.map(function (file) {
// Strip leading directory // Strip leading directory
let path let path
return (path = Path.relative(directory, file)) return (path = Path.relative(directory, file))

View file

@ -26,10 +26,10 @@ module.exports = OutputFileOptimiser = {
// check output file (src) and see if we can optimise it, storing // check output file (src) and see if we can optimise it, storing
// the result in the build directory (dst) // the result in the build directory (dst)
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
if (src.match(/\/output\.pdf$/)) { if (src.match(/\/output\.pdf$/)) {
return OutputFileOptimiser.checkIfPDFIsOptimised(src, function( return OutputFileOptimiser.checkIfPDFIsOptimised(src, function (
err, err,
isOptimised isOptimised
) { ) {
@ -46,12 +46,12 @@ module.exports = OutputFileOptimiser = {
checkIfPDFIsOptimised(file, callback) { checkIfPDFIsOptimised(file, callback) {
const SIZE = 16 * 1024 // check the header of the pdf const SIZE = 16 * 1024 // check the header of the pdf
const result = Buffer.alloc(SIZE) // fills with zeroes by default const result = Buffer.alloc(SIZE) // fills with zeroes by default
return fs.open(file, 'r', function(err, fd) { return fs.open(file, 'r', function (err, fd) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
return fs.read(fd, result, 0, SIZE, 0, (errRead, bytesRead, buffer) => return fs.read(fd, result, 0, SIZE, 0, (errRead, bytesRead, buffer) =>
fs.close(fd, function(errClose) { fs.close(fd, function (errClose) {
if (errRead != null) { if (errRead != null) {
return callback(errRead) return callback(errRead)
} }
@ -68,7 +68,7 @@ module.exports = OutputFileOptimiser = {
optimisePDF(src, dst, callback) { optimisePDF(src, dst, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const tmpOutput = dst + '.opt' const tmpOutput = dst + '.opt'
const args = ['--linearize', src, tmpOutput] const args = ['--linearize', src, tmpOutput]
@ -77,19 +77,19 @@ module.exports = OutputFileOptimiser = {
const timer = new Metrics.Timer('qpdf') const timer = new Metrics.Timer('qpdf')
const proc = spawn('qpdf', args) const proc = spawn('qpdf', args)
let stdout = '' let stdout = ''
proc.stdout.setEncoding('utf8').on('data', chunk => (stdout += chunk)) proc.stdout.setEncoding('utf8').on('data', (chunk) => (stdout += chunk))
callback = _.once(callback) // avoid double call back for error and close event callback = _.once(callback) // avoid double call back for error and close event
proc.on('error', function(err) { proc.on('error', function (err) {
logger.warn({ err, args }, 'qpdf failed') logger.warn({ err, args }, 'qpdf failed')
return callback(null) return callback(null)
}) // ignore the error }) // ignore the error
return proc.on('close', function(code) { return proc.on('close', function (code) {
timer.done() timer.done()
if (code !== 0) { if (code !== 0) {
logger.warn({ code, args }, 'qpdf returned error') logger.warn({ code, args }, 'qpdf returned error')
return callback(null) // ignore the error return callback(null) // ignore the error
} }
return fs.rename(tmpOutput, dst, function(err) { return fs.rename(tmpOutput, dst, function (err) {
if (err != null) { if (err != null) {
logger.warn( logger.warn(
{ tmpOutput, dst }, { tmpOutput, dst },

View file

@ -27,9 +27,9 @@ module.exports = ProjectPersistenceManager = {
refreshExpiryTimeout(callback) { refreshExpiryTimeout(callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
diskusage.check('/', function(err, stats) { diskusage.check('/', function (err, stats) {
if (err) { if (err) {
logger.err({ err: err }, 'error getting disk usage') logger.err({ err: err }, 'error getting disk usage')
return callback(err) return callback(err)
@ -48,9 +48,9 @@ module.exports = ProjectPersistenceManager = {
}, },
markProjectAsJustAccessed(project_id, callback) { markProjectAsJustAccessed(project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const job = cb => const job = (cb) =>
db.Project.findOrCreate({ where: { project_id } }) db.Project.findOrCreate({ where: { project_id } })
.spread((project, created) => .spread((project, created) =>
project project
@ -64,9 +64,9 @@ module.exports = ProjectPersistenceManager = {
clearExpiredProjects(callback) { clearExpiredProjects(callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return ProjectPersistenceManager._findExpiredProjectIds(function( return ProjectPersistenceManager._findExpiredProjectIds(function (
error, error,
project_ids project_ids
) { ) {
@ -74,9 +74,9 @@ module.exports = ProjectPersistenceManager = {
return callback(error) return callback(error)
} }
logger.log({ project_ids }, 'clearing expired projects') logger.log({ project_ids }, 'clearing expired projects')
const jobs = Array.from(project_ids || []).map(project_id => const jobs = Array.from(project_ids || []).map((project_id) =>
(project_id => callback => ((project_id) => (callback) =>
ProjectPersistenceManager.clearProjectFromCache(project_id, function( ProjectPersistenceManager.clearProjectFromCache(project_id, function (
err err
) { ) {
if (err != null) { if (err != null) {
@ -85,13 +85,13 @@ module.exports = ProjectPersistenceManager = {
return callback() return callback()
}))(project_id) }))(project_id)
) )
return async.series(jobs, function(error) { return async.series(jobs, function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return CompileManager.clearExpiredProjects( return CompileManager.clearExpiredProjects(
ProjectPersistenceManager.EXPIRY_TIMEOUT, ProjectPersistenceManager.EXPIRY_TIMEOUT,
error => callback() (error) => callback()
) )
}) })
}) })
@ -99,16 +99,16 @@ module.exports = ProjectPersistenceManager = {
clearProject(project_id, user_id, callback) { clearProject(project_id, user_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
logger.log({ project_id, user_id }, 'clearing project for user') logger.log({ project_id, user_id }, 'clearing project for user')
return CompileManager.clearProject(project_id, user_id, function(error) { return CompileManager.clearProject(project_id, user_id, function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return ProjectPersistenceManager.clearProjectFromCache( return ProjectPersistenceManager.clearProjectFromCache(
project_id, project_id,
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -120,17 +120,17 @@ module.exports = ProjectPersistenceManager = {
clearProjectFromCache(project_id, callback) { clearProjectFromCache(project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
logger.log({ project_id }, 'clearing project from cache') logger.log({ project_id }, 'clearing project from cache')
return UrlCache.clearProject(project_id, function(error) { return UrlCache.clearProject(project_id, function (error) {
if (error != null) { if (error != null) {
logger.err({ error, project_id }, 'error clearing project from cache') logger.err({ error, project_id }, 'error clearing project from cache')
return callback(error) return callback(error)
} }
return ProjectPersistenceManager._clearProjectFromDatabase( return ProjectPersistenceManager._clearProjectFromDatabase(
project_id, project_id,
function(error) { function (error) {
if (error != null) { if (error != null) {
logger.err( logger.err(
{ error, project_id }, { error, project_id },
@ -145,10 +145,10 @@ module.exports = ProjectPersistenceManager = {
_clearProjectFromDatabase(project_id, callback) { _clearProjectFromDatabase(project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
logger.log({ project_id }, 'clearing project from database') logger.log({ project_id }, 'clearing project from database')
const job = cb => const job = (cb) =>
db.Project.destroy({ where: { project_id } }) db.Project.destroy({ where: { project_id } })
.then(() => cb()) .then(() => cb())
.error(cb) .error(cb)
@ -157,19 +157,19 @@ module.exports = ProjectPersistenceManager = {
_findExpiredProjectIds(callback) { _findExpiredProjectIds(callback) {
if (callback == null) { if (callback == null) {
callback = function(error, project_ids) {} callback = function (error, project_ids) {}
} }
const job = function(cb) { const job = function (cb) {
const keepProjectsFrom = new Date( const keepProjectsFrom = new Date(
Date.now() - ProjectPersistenceManager.EXPIRY_TIMEOUT Date.now() - ProjectPersistenceManager.EXPIRY_TIMEOUT
) )
const q = {} const q = {}
q[db.op.lt] = keepProjectsFrom q[db.op.lt] = keepProjectsFrom
return db.Project.findAll({ where: { lastAccessed: q } }) return db.Project.findAll({ where: { lastAccessed: q } })
.then(projects => .then((projects) =>
cb( cb(
null, null,
projects.map(project => project.project_id) projects.map((project) => project.project_id)
) )
) )
.error(cb) .error(cb)

View file

@ -27,7 +27,7 @@ module.exports = RequestParser = {
parse(body, callback) { parse(body, callback) {
let resource let resource
if (callback == null) { if (callback == null) {
callback = function(error, data) {} callback = function (error, data) {}
} }
const response = {} const response = {}

View file

@ -41,13 +41,13 @@ module.exports = ResourceStateManager = {
saveProjectState(state, resources, basePath, callback) { saveProjectState(state, resources, basePath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const stateFile = Path.join(basePath, this.SYNC_STATE_FILE) const stateFile = Path.join(basePath, this.SYNC_STATE_FILE)
if (state == null) { if (state == null) {
// remove the file if no state passed in // remove the file if no state passed in
logger.log({ state, basePath }, 'clearing sync state') logger.log({ state, basePath }, 'clearing sync state')
return fs.unlink(stateFile, function(err) { return fs.unlink(stateFile, function (err) {
if (err != null && err.code !== 'ENOENT') { if (err != null && err.code !== 'ENOENT') {
return callback(err) return callback(err)
} else { } else {
@ -56,7 +56,9 @@ module.exports = ResourceStateManager = {
}) })
} else { } else {
logger.log({ state, basePath }, 'writing sync state') logger.log({ state, basePath }, 'writing sync state')
const resourceList = Array.from(resources).map(resource => resource.path) const resourceList = Array.from(resources).map(
(resource) => resource.path
)
return fs.writeFile( return fs.writeFile(
stateFile, stateFile,
[...Array.from(resourceList), `stateHash:${state}`].join('\n'), [...Array.from(resourceList), `stateHash:${state}`].join('\n'),
@ -67,11 +69,11 @@ module.exports = ResourceStateManager = {
checkProjectStateMatches(state, basePath, callback) { checkProjectStateMatches(state, basePath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, resources) {} callback = function (error, resources) {}
} }
const stateFile = Path.join(basePath, this.SYNC_STATE_FILE) const stateFile = Path.join(basePath, this.SYNC_STATE_FILE)
const size = this.SYNC_STATE_MAX_SIZE const size = this.SYNC_STATE_MAX_SIZE
return SafeReader.readFile(stateFile, size, 'utf8', function( return SafeReader.readFile(stateFile, size, 'utf8', function (
err, err,
result, result,
bytesRead bytesRead
@ -86,7 +88,7 @@ module.exports = ResourceStateManager = {
) )
} }
const array = const array =
__guard__(result != null ? result.toString() : undefined, x => __guard__(result != null ? result.toString() : undefined, (x) =>
x.split('\n') x.split('\n')
) || [] ) || []
const adjustedLength = Math.max(array.length, 1) const adjustedLength = Math.max(array.length, 1)
@ -102,7 +104,7 @@ module.exports = ResourceStateManager = {
new Errors.FilesOutOfSyncError('invalid state for incremental update') new Errors.FilesOutOfSyncError('invalid state for incremental update')
) )
} else { } else {
const resources = Array.from(resourceList).map(path => ({ path })) const resources = Array.from(resourceList).map((path) => ({ path }))
return callback(null, resources) return callback(null, resources)
} }
}) })
@ -112,11 +114,11 @@ module.exports = ResourceStateManager = {
// check the paths are all relative to current directory // check the paths are all relative to current directory
let file let file
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
for (file of Array.from(resources || [])) { for (file of Array.from(resources || [])) {
for (const dir of Array.from( for (const dir of Array.from(
__guard__(file != null ? file.path : undefined, x => x.split('/')) __guard__(file != null ? file.path : undefined, (x) => x.split('/'))
)) { )) {
if (dir === '..') { if (dir === '..') {
return callback(new Error('relative path in resource file list')) return callback(new Error('relative path in resource file list'))
@ -129,8 +131,8 @@ module.exports = ResourceStateManager = {
seenFile[file] = true seenFile[file] = true
} }
const missingFiles = Array.from(resources) const missingFiles = Array.from(resources)
.filter(resource => !seenFile[resource.path]) .filter((resource) => !seenFile[resource.path])
.map(resource => resource.path) .map((resource) => resource.path)
if ((missingFiles != null ? missingFiles.length : undefined) > 0) { if ((missingFiles != null ? missingFiles.length : undefined) > 0) {
logger.err( logger.err(
{ missingFiles, basePath, allFiles, resources }, { missingFiles, basePath, allFiles, resources },

View file

@ -30,7 +30,7 @@ const parallelFileDownloads = settings.parallelFileDownloads || 1
module.exports = ResourceWriter = { module.exports = ResourceWriter = {
syncResourcesToDisk(request, basePath, callback) { syncResourcesToDisk(request, basePath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, resourceList) {} callback = function (error, resourceList) {}
} }
if (request.syncType === 'incremental') { if (request.syncType === 'incremental') {
logger.log( logger.log(
@ -40,14 +40,14 @@ module.exports = ResourceWriter = {
return ResourceStateManager.checkProjectStateMatches( return ResourceStateManager.checkProjectStateMatches(
request.syncState, request.syncState,
basePath, basePath,
function(error, resourceList) { function (error, resourceList) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return ResourceWriter._removeExtraneousFiles( return ResourceWriter._removeExtraneousFiles(
resourceList, resourceList,
basePath, basePath,
function(error, outputFiles, allFiles) { function (error, outputFiles, allFiles) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -55,7 +55,7 @@ module.exports = ResourceWriter = {
resourceList, resourceList,
allFiles, allFiles,
basePath, basePath,
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -63,7 +63,7 @@ module.exports = ResourceWriter = {
request.project_id, request.project_id,
request.resources, request.resources,
basePath, basePath,
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -85,7 +85,7 @@ module.exports = ResourceWriter = {
request.project_id, request.project_id,
request.resources, request.resources,
basePath, basePath,
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -93,7 +93,7 @@ module.exports = ResourceWriter = {
request.syncState, request.syncState,
request.resources, request.resources,
basePath, basePath,
function(error) { function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -107,15 +107,15 @@ module.exports = ResourceWriter = {
saveIncrementalResourcesToDisk(project_id, resources, basePath, callback) { saveIncrementalResourcesToDisk(project_id, resources, basePath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return this._createDirectory(basePath, error => { return this._createDirectory(basePath, (error) => {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
const jobs = Array.from(resources).map(resource => const jobs = Array.from(resources).map((resource) =>
(resource => { ((resource) => {
return callback => return (callback) =>
this._writeResourceToDisk(project_id, resource, basePath, callback) this._writeResourceToDisk(project_id, resource, basePath, callback)
})(resource) })(resource)
) )
@ -125,19 +125,19 @@ module.exports = ResourceWriter = {
saveAllResourcesToDisk(project_id, resources, basePath, callback) { saveAllResourcesToDisk(project_id, resources, basePath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return this._createDirectory(basePath, error => { return this._createDirectory(basePath, (error) => {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return this._removeExtraneousFiles(resources, basePath, error => { return this._removeExtraneousFiles(resources, basePath, (error) => {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
const jobs = Array.from(resources).map(resource => const jobs = Array.from(resources).map((resource) =>
(resource => { ((resource) => {
return callback => return (callback) =>
this._writeResourceToDisk( this._writeResourceToDisk(
project_id, project_id,
resource, resource,
@ -153,9 +153,9 @@ module.exports = ResourceWriter = {
_createDirectory(basePath, callback) { _createDirectory(basePath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return fs.mkdir(basePath, function(err) { return fs.mkdir(basePath, function (err) {
if (err != null) { if (err != null) {
if (err.code === 'EEXIST') { if (err.code === 'EEXIST') {
return callback() return callback()
@ -171,15 +171,15 @@ module.exports = ResourceWriter = {
_removeExtraneousFiles(resources, basePath, _callback) { _removeExtraneousFiles(resources, basePath, _callback) {
if (_callback == null) { if (_callback == null) {
_callback = function(error, outputFiles, allFiles) {} _callback = function (error, outputFiles, allFiles) {}
} }
const timer = new Metrics.Timer('unlink-output-files') const timer = new Metrics.Timer('unlink-output-files')
const callback = function(error, ...result) { const callback = function (error, ...result) {
timer.done() timer.done()
return _callback(error, ...Array.from(result)) return _callback(error, ...Array.from(result))
} }
return OutputFileFinder.findOutputFiles(resources, basePath, function( return OutputFileFinder.findOutputFiles(resources, basePath, function (
error, error,
outputFiles, outputFiles,
allFiles allFiles
@ -190,7 +190,7 @@ module.exports = ResourceWriter = {
const jobs = [] const jobs = []
for (const file of Array.from(outputFiles || [])) { for (const file of Array.from(outputFiles || [])) {
;(function(file) { ;(function (file) {
const { path } = file const { path } = file
let should_delete = true let should_delete = true
if ( if (
@ -242,7 +242,7 @@ module.exports = ResourceWriter = {
should_delete = true should_delete = true
} }
if (should_delete) { if (should_delete) {
return jobs.push(callback => return jobs.push((callback) =>
ResourceWriter._deleteFileIfNotDirectory( ResourceWriter._deleteFileIfNotDirectory(
Path.join(basePath, path), Path.join(basePath, path),
callback callback
@ -252,7 +252,7 @@ module.exports = ResourceWriter = {
})(file) })(file)
} }
return async.series(jobs, function(error) { return async.series(jobs, function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -263,9 +263,9 @@ module.exports = ResourceWriter = {
_deleteFileIfNotDirectory(path, callback) { _deleteFileIfNotDirectory(path, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return fs.stat(path, function(error, stat) { return fs.stat(path, function (error, stat) {
if (error != null && error.code === 'ENOENT') { if (error != null && error.code === 'ENOENT') {
return callback() return callback()
} else if (error != null) { } else if (error != null) {
@ -275,7 +275,7 @@ module.exports = ResourceWriter = {
) )
return callback(error) return callback(error)
} else if (stat.isFile()) { } else if (stat.isFile()) {
return fs.unlink(path, function(error) { return fs.unlink(path, function (error) {
if (error != null) { if (error != null) {
logger.err( logger.err(
{ err: error, path }, { err: error, path },
@ -294,16 +294,18 @@ module.exports = ResourceWriter = {
_writeResourceToDisk(project_id, resource, basePath, callback) { _writeResourceToDisk(project_id, resource, basePath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return ResourceWriter.checkPath(basePath, resource.path, function( return ResourceWriter.checkPath(basePath, resource.path, function (
error, error,
path path
) { ) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return fs.mkdir(Path.dirname(path), { recursive: true }, function(error) { return fs.mkdir(Path.dirname(path), { recursive: true }, function (
error
) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -314,7 +316,7 @@ module.exports = ResourceWriter = {
resource.url, resource.url,
path, path,
resource.modified, resource.modified,
function(err) { function (err) {
if (err != null) { if (err != null) {
logger.err( logger.err(
{ {

View file

@ -22,9 +22,9 @@ module.exports = SafeReader = {
readFile(file, size, encoding, callback) { readFile(file, size, encoding, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, result) {} callback = function (error, result) {}
} }
return fs.open(file, 'r', function(err, fd) { return fs.open(file, 'r', function (err, fd) {
if (err != null && err.code === 'ENOENT') { if (err != null && err.code === 'ENOENT') {
return callback() return callback()
} }
@ -34,7 +34,7 @@ module.exports = SafeReader = {
// safely return always closing the file // safely return always closing the file
const callbackWithClose = (err, ...result) => const callbackWithClose = (err, ...result) =>
fs.close(fd, function(err1) { fs.close(fd, function (err1) {
if (err != null) { if (err != null) {
return callback(err) return callback(err)
} }
@ -44,7 +44,7 @@ module.exports = SafeReader = {
return callback(null, ...Array.from(result)) return callback(null, ...Array.from(result))
}) })
const buff = Buffer.alloc(size) // fills with zeroes by default const buff = Buffer.alloc(size) // fills with zeroes by default
return fs.read(fd, buff, 0, buff.length, 0, function( return fs.read(fd, buff, 0, buff.length, 0, function (
err, err,
bytesRead, bytesRead,
buffer buffer

View file

@ -21,12 +21,12 @@ const Settings = require('settings-sharelatex')
const logger = require('logger-sharelatex') const logger = require('logger-sharelatex')
const url = require('url') const url = require('url')
module.exports = ForbidSymlinks = function(staticFn, root, options) { module.exports = ForbidSymlinks = function (staticFn, root, options) {
const expressStatic = staticFn(root, options) const expressStatic = staticFn(root, options)
const basePath = Path.resolve(root) const basePath = Path.resolve(root)
return function(req, res, next) { return function (req, res, next) {
let file, project_id, result let file, project_id, result
const path = __guard__(url.parse(req.url), x => x.pathname) const path = __guard__(url.parse(req.url), (x) => x.pathname)
// check that the path is of the form /project_id_or_name/path/to/file.log // check that the path is of the form /project_id_or_name/path/to/file.log
if ((result = path.match(/^\/?([a-zA-Z0-9_-]+)\/(.*)/))) { if ((result = path.match(/^\/?([a-zA-Z0-9_-]+)\/(.*)/))) {
project_id = result[1] project_id = result[1]
@ -52,7 +52,7 @@ module.exports = ForbidSymlinks = function(staticFn, root, options) {
return res.sendStatus(404) return res.sendStatus(404)
} }
// check that the requested path is not a symlink // check that the requested path is not a symlink
return fs.realpath(requestedFsPath, function(err, realFsPath) { return fs.realpath(requestedFsPath, function (err, realFsPath) {
if (err != null) { if (err != null) {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
return res.sendStatus(404) return res.sendStatus(404)

View file

@ -26,7 +26,7 @@ module.exports = TikzManager = {
checkMainFile(compileDir, mainFile, resources, callback) { checkMainFile(compileDir, mainFile, resources, callback) {
// if there's already an output.tex file, we don't want to touch it // if there's already an output.tex file, we don't want to touch it
if (callback == null) { if (callback == null) {
callback = function(error, needsMainFile) {} callback = function (error, needsMainFile) {}
} }
for (const resource of Array.from(resources)) { for (const resource of Array.from(resources)) {
if (resource.path === 'output.tex') { if (resource.path === 'output.tex') {
@ -35,14 +35,17 @@ module.exports = TikzManager = {
} }
} }
// if there's no output.tex, see if we are using tikz/pgf or pstool in the main file // if there's no output.tex, see if we are using tikz/pgf or pstool in the main file
return ResourceWriter.checkPath(compileDir, mainFile, function( return ResourceWriter.checkPath(compileDir, mainFile, function (
error, error,
path path
) { ) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return SafeReader.readFile(path, 65536, 'utf8', function(error, content) { return SafeReader.readFile(path, 65536, 'utf8', function (
error,
content
) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -64,16 +67,16 @@ module.exports = TikzManager = {
injectOutputFile(compileDir, mainFile, callback) { injectOutputFile(compileDir, mainFile, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return ResourceWriter.checkPath(compileDir, mainFile, function( return ResourceWriter.checkPath(compileDir, mainFile, function (
error, error,
path path
) { ) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return fs.readFile(path, 'utf8', function(error, content) { return fs.readFile(path, 'utf8', function (error, content) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }

View file

@ -25,7 +25,7 @@ const async = require('async')
module.exports = UrlCache = { module.exports = UrlCache = {
downloadUrlToFile(project_id, url, destPath, lastModified, callback) { downloadUrlToFile(project_id, url, destPath, lastModified, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return UrlCache._ensureUrlIsInCache( return UrlCache._ensureUrlIsInCache(
project_id, project_id,
@ -35,7 +35,7 @@ module.exports = UrlCache = {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return UrlCache._copyFile(pathToCachedUrl, destPath, function(error) { return UrlCache._copyFile(pathToCachedUrl, destPath, function (error) {
if (error != null) { if (error != null) {
return UrlCache._clearUrlDetails(project_id, url, () => return UrlCache._clearUrlDetails(project_id, url, () =>
callback(error) callback(error)
@ -50,9 +50,9 @@ module.exports = UrlCache = {
clearProject(project_id, callback) { clearProject(project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return UrlCache._findAllUrlsInProject(project_id, function(error, urls) { return UrlCache._findAllUrlsInProject(project_id, function (error, urls) {
logger.log( logger.log(
{ project_id, url_count: urls.length }, { project_id, url_count: urls.length },
'clearing project URLs' 'clearing project URLs'
@ -60,9 +60,9 @@ module.exports = UrlCache = {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
const jobs = Array.from(urls || []).map(url => const jobs = Array.from(urls || []).map((url) =>
(url => callback => ((url) => (callback) =>
UrlCache._clearUrlFromCache(project_id, url, function(error) { UrlCache._clearUrlFromCache(project_id, url, function (error) {
if (error != null) { if (error != null) {
logger.error( logger.error(
{ err: error, project_id, url }, { err: error, project_id, url },
@ -78,7 +78,7 @@ module.exports = UrlCache = {
_ensureUrlIsInCache(project_id, url, lastModified, callback) { _ensureUrlIsInCache(project_id, url, lastModified, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, pathOnDisk) {} callback = function (error, pathOnDisk) {}
} }
if (lastModified != null) { if (lastModified != null) {
// MYSQL only stores dates to an accuracy of a second but the incoming lastModified might have milliseconds. // MYSQL only stores dates to an accuracy of a second but the incoming lastModified might have milliseconds.
@ -98,7 +98,7 @@ module.exports = UrlCache = {
return UrlFetcher.pipeUrlToFileWithRetry( return UrlFetcher.pipeUrlToFileWithRetry(
url, url,
UrlCache._cacheFilePathForUrl(project_id, url), UrlCache._cacheFilePathForUrl(project_id, url),
error => { (error) => {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -106,7 +106,7 @@ module.exports = UrlCache = {
project_id, project_id,
url, url,
lastModified, lastModified,
error => { (error) => {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -128,12 +128,12 @@ module.exports = UrlCache = {
_doesUrlNeedDownloading(project_id, url, lastModified, callback) { _doesUrlNeedDownloading(project_id, url, lastModified, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, needsDownloading) {} callback = function (error, needsDownloading) {}
} }
if (lastModified == null) { if (lastModified == null) {
return callback(null, true) return callback(null, true)
} }
return UrlCache._findUrlDetails(project_id, url, function( return UrlCache._findUrlDetails(project_id, url, function (
error, error,
urlDetails urlDetails
) { ) {
@ -153,14 +153,7 @@ module.exports = UrlCache = {
}, },
_cacheFileNameForUrl(project_id, url) { _cacheFileNameForUrl(project_id, url) {
return ( return project_id + ':' + crypto.createHash('md5').update(url).digest('hex')
project_id +
':' +
crypto
.createHash('md5')
.update(url)
.digest('hex')
)
}, },
_cacheFilePathForUrl(project_id, url) { _cacheFilePathForUrl(project_id, url) {
@ -172,14 +165,14 @@ module.exports = UrlCache = {
_copyFile(from, to, _callback) { _copyFile(from, to, _callback) {
if (_callback == null) { if (_callback == null) {
_callback = function(error) {} _callback = function (error) {}
} }
const callbackOnce = function(error) { const callbackOnce = function (error) {
if (error != null) { if (error != null) {
logger.error({ err: error, from, to }, 'error copying file from cache') logger.error({ err: error, from, to }, 'error copying file from cache')
} }
_callback(error) _callback(error)
return (_callback = function() {}) return (_callback = function () {})
} }
const writeStream = fs.createWriteStream(to) const writeStream = fs.createWriteStream(to)
const readStream = fs.createReadStream(from) const readStream = fs.createReadStream(from)
@ -191,13 +184,15 @@ module.exports = UrlCache = {
_clearUrlFromCache(project_id, url, callback) { _clearUrlFromCache(project_id, url, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return UrlCache._clearUrlDetails(project_id, url, function(error) { return UrlCache._clearUrlDetails(project_id, url, function (error) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
return UrlCache._deleteUrlCacheFromDisk(project_id, url, function(error) { return UrlCache._deleteUrlCacheFromDisk(project_id, url, function (
error
) {
if (error != null) { if (error != null) {
return callback(error) return callback(error)
} }
@ -208,9 +203,9 @@ module.exports = UrlCache = {
_deleteUrlCacheFromDisk(project_id, url, callback) { _deleteUrlCacheFromDisk(project_id, url, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
return fs.unlink(UrlCache._cacheFilePathForUrl(project_id, url), function( return fs.unlink(UrlCache._cacheFilePathForUrl(project_id, url), function (
error error
) { ) {
if (error != null && error.code !== 'ENOENT') { if (error != null && error.code !== 'ENOENT') {
@ -224,20 +219,20 @@ module.exports = UrlCache = {
_findUrlDetails(project_id, url, callback) { _findUrlDetails(project_id, url, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, urlDetails) {} callback = function (error, urlDetails) {}
} }
const job = cb => const job = (cb) =>
db.UrlCache.findOne({ where: { url, project_id } }) db.UrlCache.findOne({ where: { url, project_id } })
.then(urlDetails => cb(null, urlDetails)) .then((urlDetails) => cb(null, urlDetails))
.error(cb) .error(cb)
return dbQueue.queue.push(job, callback) return dbQueue.queue.push(job, callback)
}, },
_updateOrCreateUrlDetails(project_id, url, lastModified, callback) { _updateOrCreateUrlDetails(project_id, url, lastModified, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const job = cb => const job = (cb) =>
db.UrlCache.findOrCreate({ where: { url, project_id } }) db.UrlCache.findOrCreate({ where: { url, project_id } })
.spread((urlDetails, created) => .spread((urlDetails, created) =>
urlDetails urlDetails
@ -251,9 +246,9 @@ module.exports = UrlCache = {
_clearUrlDetails(project_id, url, callback) { _clearUrlDetails(project_id, url, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const job = cb => const job = (cb) =>
db.UrlCache.destroy({ where: { url, project_id } }) db.UrlCache.destroy({ where: { url, project_id } })
.then(() => cb(null)) .then(() => cb(null))
.error(cb) .error(cb)
@ -262,14 +257,14 @@ module.exports = UrlCache = {
_findAllUrlsInProject(project_id, callback) { _findAllUrlsInProject(project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, urls) {} callback = function (error, urls) {}
} }
const job = cb => const job = (cb) =>
db.UrlCache.findAll({ where: { project_id } }) db.UrlCache.findAll({ where: { project_id } })
.then(urlEntries => .then((urlEntries) =>
cb( cb(
null, null,
urlEntries.map(entry => entry.url) urlEntries.map((entry) => entry.url)
) )
) )
.error(cb) .error(cb)

View file

@ -24,7 +24,7 @@ const oneMinute = 60 * 1000
module.exports = UrlFetcher = { module.exports = UrlFetcher = {
pipeUrlToFileWithRetry(url, filePath, callback) { pipeUrlToFileWithRetry(url, filePath, callback) {
const doDownload = function(cb) { const doDownload = function (cb) {
UrlFetcher.pipeUrlToFile(url, filePath, cb) UrlFetcher.pipeUrlToFile(url, filePath, cb)
} }
async.retry(3, doDownload, callback) async.retry(3, doDownload, callback)
@ -32,14 +32,14 @@ module.exports = UrlFetcher = {
pipeUrlToFile(url, filePath, _callback) { pipeUrlToFile(url, filePath, _callback) {
if (_callback == null) { if (_callback == null) {
_callback = function(error) {} _callback = function (error) {}
} }
const callbackOnce = function(error) { const callbackOnce = function (error) {
if (timeoutHandler != null) { if (timeoutHandler != null) {
clearTimeout(timeoutHandler) clearTimeout(timeoutHandler)
} }
_callback(error) _callback(error)
return (_callback = function() {}) return (_callback = function () {})
} }
if (settings.filestoreDomainOveride != null) { if (settings.filestoreDomainOveride != null) {
@ -47,7 +47,7 @@ module.exports = UrlFetcher = {
url = `${settings.filestoreDomainOveride}${p}` url = `${settings.filestoreDomainOveride}${p}`
} }
var timeoutHandler = setTimeout( var timeoutHandler = setTimeout(
function() { function () {
timeoutHandler = null timeoutHandler = null
logger.error({ url, filePath }, 'Timed out downloading file to cache') logger.error({ url, filePath }, 'Timed out downloading file to cache')
return callbackOnce( return callbackOnce(
@ -63,7 +63,7 @@ module.exports = UrlFetcher = {
urlStream.pause() // stop data flowing until we are ready urlStream.pause() // stop data flowing until we are ready
// attach handlers before setting up pipes // attach handlers before setting up pipes
urlStream.on('error', function(error) { urlStream.on('error', function (error) {
logger.error({ err: error, url, filePath }, 'error downloading url') logger.error({ err: error, url, filePath }, 'error downloading url')
return callbackOnce( return callbackOnce(
error || new Error(`Something went wrong downloading the URL ${url}`) error || new Error(`Something went wrong downloading the URL ${url}`)
@ -74,17 +74,17 @@ module.exports = UrlFetcher = {
logger.log({ url, filePath }, 'finished downloading file into cache') logger.log({ url, filePath }, 'finished downloading file into cache')
) )
return urlStream.on('response', function(res) { return urlStream.on('response', function (res) {
if (res.statusCode >= 200 && res.statusCode < 300) { if (res.statusCode >= 200 && res.statusCode < 300) {
const fileStream = fs.createWriteStream(filePath) const fileStream = fs.createWriteStream(filePath)
// attach handlers before setting up pipes // attach handlers before setting up pipes
fileStream.on('error', function(error) { fileStream.on('error', function (error) {
logger.error( logger.error(
{ err: error, url, filePath }, { err: error, url, filePath },
'error writing file into cache' 'error writing file into cache'
) )
return fs.unlink(filePath, function(err) { return fs.unlink(filePath, function (err) {
if (err != null) { if (err != null) {
logger.err({ err, filePath }, 'error deleting file from cache') logger.err({ err, filePath }, 'error deleting file from cache')
} }
@ -92,7 +92,7 @@ module.exports = UrlFetcher = {
}) })
}) })
fileStream.on('finish', function() { fileStream.on('finish', function () {
logger.log({ url, filePath }, 'finished writing file into cache') logger.log({ url, filePath }, 'finished writing file into cache')
return callbackOnce() return callbackOnce()
}) })

View file

@ -62,6 +62,6 @@ module.exports = {
return sequelize return sequelize
.sync() .sync()
.then(() => logger.log('db sync complete')) .then(() => logger.log('db sync complete'))
.catch(err => console.log(err, 'error syncing')) .catch((err) => console.log(err, 'error syncing'))
} }
} }

View file

@ -1,11 +1,9 @@
clsi clsi
--acceptance-creds=None
--data-dirs=cache,compiles,db --data-dirs=cache,compiles,db
--dependencies= --dependencies=
--docker-repos=gcr.io/overleaf-ops --docker-repos=gcr.io/overleaf-ops
--env-add= --env-add=
--env-pass-through=TEXLIVE_IMAGE --env-pass-through=TEXLIVE_IMAGE
--language=es
--node-version=10.21.0 --node-version=10.21.0
--public-repo=True --public-repo=True
--script-version=2.1.0 --script-version=3.3.2

View file

@ -10,6 +10,7 @@ services:
command: npm run test:unit:_run command: npm run test:unit:_run
environment: environment:
NODE_ENV: test NODE_ENV: test
NODE_OPTIONS: "--unhandled-rejections=strict"
test_acceptance: test_acceptance:
@ -25,6 +26,7 @@ services:
POSTGRES_HOST: postgres POSTGRES_HOST: postgres
MOCHA_GREP: ${MOCHA_GREP} MOCHA_GREP: ${MOCHA_GREP}
NODE_ENV: test NODE_ENV: test
NODE_OPTIONS: "--unhandled-rejections=strict"
TEXLIVE_IMAGE: TEXLIVE_IMAGE:
command: npm run test:acceptance:_run command: npm run test:acceptance:_run

View file

@ -15,7 +15,8 @@ services:
environment: environment:
MOCHA_GREP: ${MOCHA_GREP} MOCHA_GREP: ${MOCHA_GREP}
NODE_ENV: test NODE_ENV: test
command: npm run test:unit NODE_OPTIONS: "--unhandled-rejections=strict"
command: npm run --silent test:unit
test_acceptance: test_acceptance:
build: build:
@ -35,5 +36,6 @@ services:
MOCHA_GREP: ${MOCHA_GREP} MOCHA_GREP: ${MOCHA_GREP}
LOG_LEVEL: ERROR LOG_LEVEL: ERROR
NODE_ENV: test NODE_ENV: test
command: npm run test:acceptance NODE_OPTIONS: "--unhandled-rejections=strict"
command: npm run --silent test:acceptance

View file

@ -8,7 +8,6 @@
"execMap": { "execMap": {
"js": "npm run start" "js": "npm run start"
}, },
"watch": [ "watch": [
"app/js/", "app/js/",
"app.js", "app.js",

View file

@ -4770,9 +4770,9 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "1.19.1", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==",
"dev": true "dev": true
}, },
"prettier-eslint": { "prettier-eslint": {
@ -5004,6 +5004,12 @@
"mimic-fn": "^1.0.0" "mimic-fn": "^1.0.0"
} }
}, },
"prettier": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"dev": true
},
"restore-cursor": { "restore-cursor": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",

View file

@ -13,7 +13,7 @@
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js", "test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP", "test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
"nodemon": "nodemon --config nodemon.json", "nodemon": "nodemon --config nodemon.json",
"lint": "node_modules/.bin/eslint .", "lint": "node_modules/.bin/eslint --max-warnings 0 .",
"format": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --list-different", "format": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --list-different",
"format:fix": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --write" "format:fix": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --write"
}, },
@ -59,7 +59,7 @@
"eslint-plugin-react": "^7.19.0", "eslint-plugin-react": "^7.19.0",
"eslint-plugin-standard": "^4.0.1", "eslint-plugin-standard": "^4.0.1",
"mocha": "^7.1.0", "mocha": "^7.1.0",
"prettier": "^1.19.1", "prettier": "^2.0.0",
"prettier-eslint-cli": "^5.0.0", "prettier-eslint-cli": "^5.0.0",
"sandboxed-module": "^2.0.3", "sandboxed-module": "^2.0.3",
"sinon": "~9.0.1", "sinon": "~9.0.1",

View file

@ -2,8 +2,8 @@ const Client = require('./helpers/Client')
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
const { expect } = require('chai') const { expect } = require('chai')
describe('AllowedImageNames', function() { describe('AllowedImageNames', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.request = { this.request = {
options: { options: {
@ -24,8 +24,8 @@ Hello world
ClsiApp.ensureRunning(done) ClsiApp.ensureRunning(done)
}) })
describe('with a valid name', function() { describe('with a valid name', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.request.options.imageName = process.env.TEXLIVE_IMAGE this.request.options.imageName = process.env.TEXLIVE_IMAGE
Client.compile(this.project_id, this.request, (error, res, body) => { Client.compile(this.project_id, this.request, (error, res, body) => {
@ -35,11 +35,11 @@ Hello world
done(error) done(error)
}) })
}) })
it('should return success', function() { it('should return success', function () {
expect(this.res.statusCode).to.equal(200) expect(this.res.statusCode).to.equal(200)
}) })
it('should return a PDF', function() { it('should return a PDF', function () {
let pdf let pdf
try { try {
pdf = Client.getOutputFile(this.body, 'pdf') pdf = Client.getOutputFile(this.body, 'pdf')
@ -48,8 +48,8 @@ Hello world
}) })
}) })
describe('with an invalid name', function() { describe('with an invalid name', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.request.options.imageName = 'something/evil:1337' this.request.options.imageName = 'something/evil:1337'
Client.compile(this.project_id, this.request, (error, res, body) => { Client.compile(this.project_id, this.request, (error, res, body) => {
this.error = error this.error = error
@ -58,11 +58,11 @@ Hello world
done(error) done(error)
}) })
}) })
it('should return non success', function() { it('should return non success', function () {
expect(this.res.statusCode).to.not.equal(200) expect(this.res.statusCode).to.not.equal(200)
}) })
it('should not return a PDF', function() { it('should not return a PDF', function () {
let pdf let pdf
try { try {
pdf = Client.getOutputFile(this.body, 'pdf') pdf = Client.getOutputFile(this.body, 'pdf')
@ -71,11 +71,11 @@ Hello world
}) })
}) })
describe('wordcount', function() { describe('wordcount', function () {
beforeEach(function(done) { beforeEach(function (done) {
Client.compile(this.project_id, this.request, done) Client.compile(this.project_id, this.request, done)
}) })
it('should error out with an invalid imageName', function() { it('should error out with an invalid imageName', function () {
Client.wordcountWithImage( Client.wordcountWithImage(
this.project_id, this.project_id,
'main.tex', 'main.tex',
@ -86,7 +86,7 @@ Hello world
) )
}) })
it('should produce a texcout a valid imageName', function() { it('should produce a texcout a valid imageName', function () {
Client.wordcountWithImage( Client.wordcountWithImage(
this.project_id, this.project_id,
'main.tex', 'main.tex',

View file

@ -13,8 +13,8 @@ const request = require('request')
require('chai').should() require('chai').should()
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
describe('Broken LaTeX file', function() { describe('Broken LaTeX file', function () {
before(function(done) { before(function (done) {
this.broken_request = { this.broken_request = {
resources: [ resources: [
{ {
@ -44,8 +44,8 @@ Hello world
return ClsiApp.ensureRunning(done) return ClsiApp.ensureRunning(done)
}) })
describe('on first run', function() { describe('on first run', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
return Client.compile( return Client.compile(
this.project_id, this.project_id,
@ -59,13 +59,13 @@ Hello world
) )
}) })
return it('should return a failure status', function() { return it('should return a failure status', function () {
return this.body.compile.status.should.equal('failure') return this.body.compile.status.should.equal('failure')
}) })
}) })
return describe('on second run', function() { return describe('on second run', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
return Client.compile(this.project_id, this.correct_request, () => { return Client.compile(this.project_id, this.correct_request, () => {
return Client.compile( return Client.compile(
@ -81,7 +81,7 @@ Hello world
}) })
}) })
return it('should return a failure status', function() { return it('should return a failure status', function () {
return this.body.compile.status.should.equal('failure') return this.body.compile.status.should.equal('failure')
}) })
}) })

View file

@ -13,8 +13,8 @@ const request = require('request')
require('chai').should() require('chai').should()
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
describe('Deleting Old Files', function() { describe('Deleting Old Files', function () {
before(function(done) { before(function (done) {
this.request = { this.request = {
resources: [ resources: [
{ {
@ -31,8 +31,8 @@ Hello world
return ClsiApp.ensureRunning(done) return ClsiApp.ensureRunning(done)
}) })
return describe('on first run', function() { return describe('on first run', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
return Client.compile( return Client.compile(
this.project_id, this.project_id,
@ -46,12 +46,12 @@ Hello world
) )
}) })
it('should return a success status', function() { it('should return a success status', function () {
return this.body.compile.status.should.equal('success') return this.body.compile.status.should.equal('success')
}) })
return describe('after file has been deleted', function() { return describe('after file has been deleted', function () {
before(function(done) { before(function (done) {
this.request.resources = [] this.request.resources = []
return Client.compile( return Client.compile(
this.project_id, this.project_id,
@ -65,7 +65,7 @@ Hello world
) )
}) })
return it('should return a failure status', function() { return it('should return a failure status', function () {
return this.body.compile.status.should.equal('failure') return this.body.compile.status.should.equal('failure')
}) })
}) })

View file

@ -24,7 +24,7 @@ const ChildProcess = require('child_process')
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
const logger = require('logger-sharelatex') const logger = require('logger-sharelatex')
const Path = require('path') const Path = require('path')
const fixturePath = path => { const fixturePath = (path) => {
if (path.slice(0, 3) === 'tmp') { if (path.slice(0, 3) === 'tmp') {
return '/tmp/clsi_acceptance_tests' + path.slice(3) return '/tmp/clsi_acceptance_tests' + path.slice(3)
} }
@ -41,23 +41,23 @@ console.log(
const MOCHA_LATEX_TIMEOUT = 60 * 1000 const MOCHA_LATEX_TIMEOUT = 60 * 1000
const convertToPng = function(pdfPath, pngPath, callback) { const convertToPng = function (pdfPath, pngPath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const command = `convert ${fixturePath(pdfPath)} ${fixturePath(pngPath)}` const command = `convert ${fixturePath(pdfPath)} ${fixturePath(pngPath)}`
console.log('COMMAND') console.log('COMMAND')
console.log(command) console.log(command)
const convert = ChildProcess.exec(command) const convert = ChildProcess.exec(command)
const stdout = '' const stdout = ''
convert.stdout.on('data', chunk => console.log('STDOUT', chunk.toString())) convert.stdout.on('data', (chunk) => console.log('STDOUT', chunk.toString()))
convert.stderr.on('data', chunk => console.log('STDERR', chunk.toString())) convert.stderr.on('data', (chunk) => console.log('STDERR', chunk.toString()))
return convert.on('exit', () => callback()) return convert.on('exit', () => callback())
} }
const compare = function(originalPath, generatedPath, callback) { const compare = function (originalPath, generatedPath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, same) {} callback = function (error, same) {}
} }
const diff_file = `${fixturePath(generatedPath)}-diff.png` const diff_file = `${fixturePath(generatedPath)}-diff.png`
const proc = ChildProcess.exec( const proc = ChildProcess.exec(
@ -66,11 +66,11 @@ const compare = function(originalPath, generatedPath, callback) {
)} ${diff_file}` )} ${diff_file}`
) )
let stderr = '' let stderr = ''
proc.stderr.on('data', chunk => (stderr += chunk)) proc.stderr.on('data', (chunk) => (stderr += chunk))
return proc.on('exit', () => { return proc.on('exit', () => {
if (stderr.trim() === '0 (0)') { if (stderr.trim() === '0 (0)') {
// remove output diff if test matches expected image // remove output diff if test matches expected image
fs.unlink(diff_file, err => { fs.unlink(diff_file, (err) => {
if (err) { if (err) {
throw err throw err
} }
@ -83,14 +83,14 @@ const compare = function(originalPath, generatedPath, callback) {
}) })
} }
const checkPdfInfo = function(pdfPath, callback) { const checkPdfInfo = function (pdfPath, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, output) {} callback = function (error, output) {}
} }
const proc = ChildProcess.exec(`pdfinfo ${fixturePath(pdfPath)}`) const proc = ChildProcess.exec(`pdfinfo ${fixturePath(pdfPath)}`)
let stdout = '' let stdout = ''
proc.stdout.on('data', chunk => (stdout += chunk)) proc.stdout.on('data', (chunk) => (stdout += chunk))
proc.stderr.on('data', chunk => console.log('STDERR', chunk.toString())) proc.stderr.on('data', (chunk) => console.log('STDERR', chunk.toString()))
return proc.on('exit', () => { return proc.on('exit', () => {
if (stdout.match(/Optimized:\s+yes/)) { if (stdout.match(/Optimized:\s+yes/)) {
return callback(null, true) return callback(null, true)
@ -100,11 +100,11 @@ const checkPdfInfo = function(pdfPath, callback) {
}) })
} }
const compareMultiplePages = function(project_id, callback) { const compareMultiplePages = function (project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
var compareNext = function(page_no, callback) { var compareNext = function (page_no, callback) {
const path = `tmp/${project_id}-source-${page_no}.png` const path = `tmp/${project_id}-source-${page_no}.png`
return fs.stat(fixturePath(path), (error, stat) => { return fs.stat(fixturePath(path), (error, stat) => {
if (error != null) { if (error != null) {
@ -127,23 +127,23 @@ const compareMultiplePages = function(project_id, callback) {
return compareNext(0, callback) return compareNext(0, callback)
} }
const comparePdf = function(project_id, example_dir, callback) { const comparePdf = function (project_id, example_dir, callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
console.log('CONVERT') console.log('CONVERT')
console.log(`tmp/${project_id}.pdf`, `tmp/${project_id}-generated.png`) console.log(`tmp/${project_id}.pdf`, `tmp/${project_id}-generated.png`)
return convertToPng( return convertToPng(
`tmp/${project_id}.pdf`, `tmp/${project_id}.pdf`,
`tmp/${project_id}-generated.png`, `tmp/${project_id}-generated.png`,
error => { (error) => {
if (error != null) { if (error != null) {
throw error throw error
} }
return convertToPng( return convertToPng(
`examples/${example_dir}/output.pdf`, `examples/${example_dir}/output.pdf`,
`tmp/${project_id}-source.png`, `tmp/${project_id}-source.png`,
error => { (error) => {
if (error != null) { if (error != null) {
throw error throw error
} }
@ -163,7 +163,7 @@ const comparePdf = function(project_id, example_dir, callback) {
} }
) )
} else { } else {
return compareMultiplePages(project_id, error => { return compareMultiplePages(project_id, (error) => {
if (error != null) { if (error != null) {
throw error throw error
} }
@ -178,9 +178,14 @@ const comparePdf = function(project_id, example_dir, callback) {
) )
} }
const downloadAndComparePdf = function(project_id, example_dir, url, callback) { const downloadAndComparePdf = function (
project_id,
example_dir,
url,
callback
) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
const writeStream = fs.createWriteStream(fixturePath(`tmp/${project_id}.pdf`)) const writeStream = fs.createWriteStream(fixturePath(`tmp/${project_id}.pdf`))
request.get(url).pipe(writeStream) request.get(url).pipe(writeStream)
@ -198,85 +203,96 @@ const downloadAndComparePdf = function(project_id, example_dir, url, callback) {
Client.runServer(4242, fixturePath('examples')) Client.runServer(4242, fixturePath('examples'))
describe('Example Documents', function() { describe('Example Documents', function () {
before(function(done) { before(function (done) {
ClsiApp.ensureRunning(done) ClsiApp.ensureRunning(done)
}) })
before(function(done) { before(function (done) {
fsExtra.remove(fixturePath('tmp'), done) fsExtra.remove(fixturePath('tmp'), done)
}) })
before(function(done) { before(function (done) {
fs.mkdir(fixturePath('tmp'), done) fs.mkdir(fixturePath('tmp'), done)
}) })
after(function(done) { after(function (done) {
fsExtra.remove(fixturePath('tmp'), done) fsExtra.remove(fixturePath('tmp'), done)
}) })
return Array.from(fs.readdirSync(fixturePath('examples'))).map(example_dir => return Array.from(fs.readdirSync(fixturePath('examples'))).map(
(example_dir => (example_dir) =>
describe(example_dir, function() { ((example_dir) =>
before(function() { describe(example_dir, function () {
return (this.project_id = Client.randomId() + '_' + example_dir) before(function () {
}) return (this.project_id = Client.randomId() + '_' + example_dir)
})
it('should generate the correct pdf', function(done) { it('should generate the correct pdf', function (done) {
this.timeout(MOCHA_LATEX_TIMEOUT) this.timeout(MOCHA_LATEX_TIMEOUT)
return Client.compileDirectory( return Client.compileDirectory(
this.project_id, this.project_id,
fixturePath('examples'), fixturePath('examples'),
example_dir, example_dir,
4242, 4242,
(error, res, body) => { (error, res, body) => {
if ( if (
error || error ||
__guard__( __guard__(
body != null ? body.compile : undefined, body != null ? body.compile : undefined,
x => x.status (x) => x.status
) === 'failure' ) === 'failure'
) { ) {
console.log('DEBUG: error', error, 'body', JSON.stringify(body)) console.log(
return done(new Error('Compile failed')) 'DEBUG: error',
error,
'body',
JSON.stringify(body)
)
return done(new Error('Compile failed'))
}
const pdf = Client.getOutputFile(body, 'pdf')
return downloadAndComparePdf(
this.project_id,
example_dir,
pdf.url,
done
)
} }
const pdf = Client.getOutputFile(body, 'pdf') )
return downloadAndComparePdf( })
this.project_id,
example_dir,
pdf.url,
done
)
}
)
})
return it('should generate the correct pdf on the second run as well', function(done) { return it('should generate the correct pdf on the second run as well', function (done) {
this.timeout(MOCHA_LATEX_TIMEOUT) this.timeout(MOCHA_LATEX_TIMEOUT)
return Client.compileDirectory( return Client.compileDirectory(
this.project_id, this.project_id,
fixturePath('examples'), fixturePath('examples'),
example_dir, example_dir,
4242, 4242,
(error, res, body) => { (error, res, body) => {
if ( if (
error || error ||
__guard__( __guard__(
body != null ? body.compile : undefined, body != null ? body.compile : undefined,
x => x.status (x) => x.status
) === 'failure' ) === 'failure'
) { ) {
console.log('DEBUG: error', error, 'body', JSON.stringify(body)) console.log(
return done(new Error('Compile failed')) 'DEBUG: error',
error,
'body',
JSON.stringify(body)
)
return done(new Error('Compile failed'))
}
const pdf = Client.getOutputFile(body, 'pdf')
return downloadAndComparePdf(
this.project_id,
example_dir,
pdf.url,
done
)
} }
const pdf = Client.getOutputFile(body, 'pdf') )
return downloadAndComparePdf( })
this.project_id, }))(example_dir)
example_dir,
pdf.url,
done
)
}
)
})
}))(example_dir)
) )
}) })

View file

@ -13,8 +13,8 @@ const request = require('request')
require('chai').should() require('chai').should()
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
describe('Simple LaTeX file', function() { describe('Simple LaTeX file', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.request = { this.request = {
resources: [ resources: [
@ -43,17 +43,17 @@ Hello world
}) })
}) })
it('should return the PDF', function() { it('should return the PDF', function () {
const pdf = Client.getOutputFile(this.body, 'pdf') const pdf = Client.getOutputFile(this.body, 'pdf')
return pdf.type.should.equal('pdf') return pdf.type.should.equal('pdf')
}) })
it('should return the log', function() { it('should return the log', function () {
const log = Client.getOutputFile(this.body, 'log') const log = Client.getOutputFile(this.body, 'log')
return log.type.should.equal('log') return log.type.should.equal('log')
}) })
it('should provide the pdf for download', function(done) { it('should provide the pdf for download', function (done) {
const pdf = Client.getOutputFile(this.body, 'pdf') const pdf = Client.getOutputFile(this.body, 'pdf')
return request.get(pdf.url, (error, res, body) => { return request.get(pdf.url, (error, res, body) => {
res.statusCode.should.equal(200) res.statusCode.should.equal(200)
@ -61,7 +61,7 @@ Hello world
}) })
}) })
return it('should provide the log for download', function(done) { return it('should provide the log for download', function (done) {
const log = Client.getOutputFile(this.body, 'pdf') const log = Client.getOutputFile(this.body, 'pdf')
return request.get(log.url, (error, res, body) => { return request.get(log.url, (error, res, body) => {
res.statusCode.should.equal(200) res.statusCode.should.equal(200)

View file

@ -16,8 +16,8 @@ const { expect } = require('chai')
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
const crypto = require('crypto') const crypto = require('crypto')
describe('Syncing', function() { describe('Syncing', function () {
before(function(done) { before(function (done) {
const content = `\ const content = `\
\\documentclass{article} \\documentclass{article}
\\begin{document} \\begin{document}
@ -47,8 +47,8 @@ Hello world
}) })
}) })
describe('from code to pdf', function() { describe('from code to pdf', function () {
return it('should return the correct location', function(done) { return it('should return the correct location', function (done) {
return Client.syncFromCode( return Client.syncFromCode(
this.project_id, this.project_id,
'main.tex', 'main.tex',
@ -69,8 +69,8 @@ Hello world
}) })
}) })
describe('from pdf to code', function() { describe('from pdf to code', function () {
return it('should return the correct location', function(done) { return it('should return the correct location', function (done) {
return Client.syncFromPdf( return Client.syncFromPdf(
this.project_id, this.project_id,
1, 1,
@ -89,12 +89,12 @@ Hello world
}) })
}) })
describe('when the project directory is not available', function() { describe('when the project directory is not available', function () {
before(function() { before(function () {
this.other_project_id = Client.randomId() this.other_project_id = Client.randomId()
}) })
describe('from code to pdf', function() { describe('from code to pdf', function () {
it('should return a 404 response', function(done) { it('should return a 404 response', function (done) {
return Client.syncFromCode( return Client.syncFromCode(
this.other_project_id, this.other_project_id,
'main.tex', 'main.tex',
@ -110,8 +110,8 @@ Hello world
) )
}) })
}) })
describe('from pdf to code', function() { describe('from pdf to code', function () {
it('should return a 404 response', function(done) { it('should return a 404 response', function (done) {
return Client.syncFromPdf( return Client.syncFromPdf(
this.other_project_id, this.other_project_id,
1, 1,
@ -129,8 +129,8 @@ Hello world
}) })
}) })
describe('when the synctex file is not available', function() { describe('when the synctex file is not available', function () {
before(function(done) { before(function (done) {
this.broken_project_id = Client.randomId() this.broken_project_id = Client.randomId()
const content = 'this is not valid tex' // not a valid tex file const content = 'this is not valid tex' // not a valid tex file
this.request = { this.request = {
@ -153,8 +153,8 @@ Hello world
) )
}) })
describe('from code to pdf', function() { describe('from code to pdf', function () {
it('should return a 404 response', function(done) { it('should return a 404 response', function (done) {
return Client.syncFromCode( return Client.syncFromCode(
this.broken_project_id, this.broken_project_id,
'main.tex', 'main.tex',
@ -170,8 +170,8 @@ Hello world
) )
}) })
}) })
describe('from pdf to code', function() { describe('from pdf to code', function () {
it('should return a 404 response', function(done) { it('should return a 404 response', function (done) {
return Client.syncFromPdf( return Client.syncFromPdf(
this.broken_project_id, this.broken_project_id,
1, 1,

View file

@ -13,8 +13,8 @@ const request = require('request')
require('chai').should() require('chai').should()
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
describe('Timed out compile', function() { describe('Timed out compile', function () {
before(function(done) { before(function (done) {
this.request = { this.request = {
options: { options: {
timeout: 10 timeout: 10
@ -47,16 +47,16 @@ describe('Timed out compile', function() {
}) })
}) })
it('should return a timeout error', function() { it('should return a timeout error', function () {
return this.body.compile.error.should.equal('container timed out') return this.body.compile.error.should.equal('container timed out')
}) })
it('should return a timedout status', function() { it('should return a timedout status', function () {
return this.body.compile.status.should.equal('timedout') return this.body.compile.status.should.equal('timedout')
}) })
return it('should return the log output file name', function() { return it('should return the log output file name', function () {
const outputFilePaths = this.body.compile.outputFiles.map(x => x.path) const outputFilePaths = this.body.compile.outputFiles.map((x) => x.path)
return outputFilePaths.should.include('output.log') return outputFilePaths.should.include('output.log')
}) })
}) })

View file

@ -35,17 +35,15 @@ const Server = {
getFile() {}, getFile() {},
randomId() { randomId() {
return Math.random() return Math.random().toString(16).slice(2)
.toString(16)
.slice(2)
} }
} }
Server.run() Server.run()
describe('Url Caching', function() { describe('Url Caching', function () {
describe('Downloading an image for the first time', function() { describe('Downloading an image for the first time', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.file = `${Server.randomId()}/lion.png` this.file = `${Server.randomId()}/lion.png`
this.request = { this.request = {
@ -82,17 +80,17 @@ describe('Url Caching', function() {
}) })
}) })
afterEach(function() { afterEach(function () {
return Server.getFile.restore() return Server.getFile.restore()
}) })
return it('should download the image', function() { return it('should download the image', function () {
return Server.getFile.calledWith(`/${this.file}`).should.equal(true) return Server.getFile.calledWith(`/${this.file}`).should.equal(true)
}) })
}) })
describe('When an image is in the cache and the last modified date is unchanged', function() { describe('When an image is in the cache and the last modified date is unchanged', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.file = `${Server.randomId()}/lion.png` this.file = `${Server.randomId()}/lion.png`
this.request = { this.request = {
@ -137,17 +135,17 @@ describe('Url Caching', function() {
) )
}) })
after(function() { after(function () {
return Server.getFile.restore() return Server.getFile.restore()
}) })
return it('should not download the image again', function() { return it('should not download the image again', function () {
return Server.getFile.called.should.equal(false) return Server.getFile.called.should.equal(false)
}) })
}) })
describe('When an image is in the cache and the last modified date is advanced', function() { describe('When an image is in the cache and the last modified date is advanced', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.file = `${Server.randomId()}/lion.png` this.file = `${Server.randomId()}/lion.png`
this.request = { this.request = {
@ -193,17 +191,17 @@ describe('Url Caching', function() {
) )
}) })
afterEach(function() { afterEach(function () {
return Server.getFile.restore() return Server.getFile.restore()
}) })
return it('should download the image again', function() { return it('should download the image again', function () {
return Server.getFile.called.should.equal(true) return Server.getFile.called.should.equal(true)
}) })
}) })
describe('When an image is in the cache and the last modified date is further in the past', function() { describe('When an image is in the cache and the last modified date is further in the past', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.file = `${Server.randomId()}/lion.png` this.file = `${Server.randomId()}/lion.png`
this.request = { this.request = {
@ -249,17 +247,17 @@ describe('Url Caching', function() {
) )
}) })
afterEach(function() { afterEach(function () {
return Server.getFile.restore() return Server.getFile.restore()
}) })
return it('should not download the image again', function() { return it('should not download the image again', function () {
return Server.getFile.called.should.equal(false) return Server.getFile.called.should.equal(false)
}) })
}) })
describe('When an image is in the cache and the last modified date is not specified', function() { describe('When an image is in the cache and the last modified date is not specified', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.file = `${Server.randomId()}/lion.png` this.file = `${Server.randomId()}/lion.png`
this.request = { this.request = {
@ -305,17 +303,17 @@ describe('Url Caching', function() {
) )
}) })
afterEach(function() { afterEach(function () {
return Server.getFile.restore() return Server.getFile.restore()
}) })
return it('should download the image again', function() { return it('should download the image again', function () {
return Server.getFile.called.should.equal(true) return Server.getFile.called.should.equal(true)
}) })
}) })
return describe('After clearing the cache', function() { return describe('After clearing the cache', function () {
before(function(done) { before(function (done) {
this.project_id = Client.randomId() this.project_id = Client.randomId()
this.file = `${Server.randomId()}/lion.png` this.file = `${Server.randomId()}/lion.png`
this.request = { this.request = {
@ -338,7 +336,7 @@ describe('Url Caching', function() {
] ]
} }
return Client.compile(this.project_id, this.request, error => { return Client.compile(this.project_id, this.request, (error) => {
if (error != null) { if (error != null) {
throw error throw error
} }
@ -361,11 +359,11 @@ describe('Url Caching', function() {
}) })
}) })
afterEach(function() { afterEach(function () {
return Server.getFile.restore() return Server.getFile.restore()
}) })
return it('should download the image again', function() { return it('should download the image again', function () {
return Server.getFile.called.should.equal(true) return Server.getFile.called.should.equal(true)
}) })
}) })

View file

@ -17,8 +17,8 @@ const path = require('path')
const fs = require('fs') const fs = require('fs')
const ClsiApp = require('./helpers/ClsiApp') const ClsiApp = require('./helpers/ClsiApp')
describe('Syncing', function() { describe('Syncing', function () {
before(function(done) { before(function (done) {
this.request = { this.request = {
resources: [ resources: [
{ {
@ -45,8 +45,8 @@ describe('Syncing', function() {
}) })
}) })
return describe('wordcount file', function() { return describe('wordcount file', function () {
return it('should return wordcount info', function(done) { return it('should return wordcount info', function (done) {
return Client.wordcount(this.project_id, 'main.tex', (error, result) => { return Client.wordcount(this.project_id, 'main.tex', (error, result) => {
if (error != null) { if (error != null) {
throw error throw error

View file

@ -23,14 +23,12 @@ module.exports = Client = {
host: Settings.apis.clsi.url, host: Settings.apis.clsi.url,
randomId() { randomId() {
return Math.random() return Math.random().toString(16).slice(2)
.toString(16)
.slice(2)
}, },
compile(project_id, data, callback) { compile(project_id, data, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, res, body) {} callback = function (error, res, body) {}
} }
return request.post( return request.post(
{ {
@ -45,7 +43,7 @@ module.exports = Client = {
clearCache(project_id, callback) { clearCache(project_id, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, res, body) {} callback = function (error, res, body) {}
} }
return request.del(`${this.host}/project/${project_id}`, callback) return request.del(`${this.host}/project/${project_id}`, callback)
}, },
@ -64,7 +62,7 @@ module.exports = Client = {
const app = express() const app = express()
app.use(express.static(directory)) app.use(express.static(directory))
console.log('starting test server on', port, host) console.log('starting test server on', port, host)
return app.listen(port, host).on('error', error => { return app.listen(port, host).on('error', (error) => {
console.error('error starting server:', error.message) console.error('error starting server:', error.message)
return process.exit(1) return process.exit(1)
}) })
@ -72,7 +70,7 @@ module.exports = Client = {
syncFromCode(project_id, file, line, column, callback) { syncFromCode(project_id, file, line, column, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, pdfPositions) {} callback = function (error, pdfPositions) {}
} }
return request.get( return request.get(
{ {
@ -95,7 +93,7 @@ module.exports = Client = {
syncFromPdf(project_id, page, h, v, callback) { syncFromPdf(project_id, page, h, v, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, pdfPositions) {} callback = function (error, pdfPositions) {}
} }
return request.get( return request.get(
{ {
@ -118,7 +116,7 @@ module.exports = Client = {
compileDirectory(project_id, baseDirectory, directory, serverPort, callback) { compileDirectory(project_id, baseDirectory, directory, serverPort, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, res, body) {} callback = function (error, res, body) {}
} }
const resources = [] const resources = []
let entities = fs.readdirSync(`${baseDirectory}/${directory}`) let entities = fs.readdirSync(`${baseDirectory}/${directory}`)
@ -130,7 +128,7 @@ module.exports = Client = {
entities = entities.concat( entities = entities.concat(
fs fs
.readdirSync(`${baseDirectory}/${directory}/${entity}`) .readdirSync(`${baseDirectory}/${directory}/${entity}`)
.map(subEntity => { .map((subEntity) => {
if (subEntity === 'main.tex') { if (subEntity === 'main.tex') {
rootResourcePath = `${entity}/${subEntity}` rootResourcePath = `${entity}/${subEntity}`
} }
@ -195,7 +193,7 @@ module.exports = Client = {
wordcountWithImage(project_id, file, image, callback) { wordcountWithImage(project_id, file, image, callback) {
if (callback == null) { if (callback == null) {
callback = function(error, pdfPositions) {} callback = function (error, pdfPositions) {}
} }
return request.get( return request.get(
{ {

View file

@ -23,7 +23,7 @@ module.exports = {
callbacks: [], callbacks: [],
ensureRunning(callback) { ensureRunning(callback) {
if (callback == null) { if (callback == null) {
callback = function(error) {} callback = function (error) {}
} }
if (this.running) { if (this.running) {
return callback() return callback()
@ -35,10 +35,10 @@ module.exports = {
return app.listen( return app.listen(
__guard__( __guard__(
Settings.internal != null ? Settings.internal.clsi : undefined, Settings.internal != null ? Settings.internal.clsi : undefined,
x => x.port (x) => x.port
), ),
'localhost', 'localhost',
error => { (error) => {
if (error != null) { if (error != null) {
throw error throw error
} }

View file

@ -17,7 +17,7 @@ const _ = require('lodash')
const concurentCompiles = 5 const concurentCompiles = 5
const totalCompiles = 50 const totalCompiles = 50
const buildUrl = path => const buildUrl = (path) =>
`http://${Settings.internal.clsi.host}:${Settings.internal.clsi.port}/${path}` `http://${Settings.internal.clsi.host}:${Settings.internal.clsi.port}/${path}`
const mainTexContent = fs.readFileSync('./bulk.tex', 'utf-8') const mainTexContent = fs.readFileSync('./bulk.tex', 'utf-8')
@ -25,12 +25,12 @@ const mainTexContent = fs.readFileSync('./bulk.tex', 'utf-8')
const compileTimes = [] const compileTimes = []
let failedCount = 0 let failedCount = 0
const getAverageCompileTime = function() { const getAverageCompileTime = function () {
const totalTime = _.reduce(compileTimes, (sum, time) => sum + time, 0) const totalTime = _.reduce(compileTimes, (sum, time) => sum + time, 0)
return totalTime / compileTimes.length return totalTime / compileTimes.length
} }
const makeRequest = function(compileNumber, callback) { const makeRequest = function (compileNumber, callback) {
let bulkBodyCount = 7 let bulkBodyCount = 7
let bodyContent = '' let bodyContent = ''
while (--bulkBodyCount) { while (--bulkBodyCount) {
@ -74,12 +74,12 @@ ${bodyContent}
) )
} }
const jobs = _.map(__range__(1, totalCompiles, true), i => cb => const jobs = _.map(__range__(1, totalCompiles, true), (i) => (cb) =>
makeRequest(i, cb) makeRequest(i, cb)
) )
const startTime = new Date() const startTime = new Date()
async.parallelLimit(jobs, concurentCompiles, err => { async.parallelLimit(jobs, concurentCompiles, (err) => {
if (err != null) { if (err != null) {
console.error(err) console.error(err)
} }

View file

@ -1,20 +1,20 @@
const request = require('request') const request = require('request')
const Settings = require('settings-sharelatex') const Settings = require('settings-sharelatex')
const buildUrl = path => const buildUrl = (path) =>
`http://${Settings.internal.clsi.host}:${Settings.internal.clsi.port}/${path}` `http://${Settings.internal.clsi.host}:${Settings.internal.clsi.port}/${path}`
const url = buildUrl(`project/smoketest-${process.pid}/compile`) const url = buildUrl(`project/smoketest-${process.pid}/compile`)
module.exports = { module.exports = {
sendNewResult(res) { sendNewResult(res) {
this._run(error => this._sendResponse(res, error)) this._run((error) => this._sendResponse(res, error))
}, },
sendLastResult(res) { sendLastResult(res) {
this._sendResponse(res, this._lastError) this._sendResponse(res, this._lastError)
}, },
triggerRun(cb) { triggerRun(cb) {
this._run(error => { this._run((error) => {
this._lastError = error this._lastError = error
cb(error) cb(error)
}) })

View file

@ -19,8 +19,8 @@ const modulePath = require('path').join(
) )
const tk = require('timekeeper') const tk = require('timekeeper')
describe('CompileController', function() { describe('CompileController', function () {
beforeEach(function() { beforeEach(function () {
this.CompileController = SandboxedModule.require(modulePath, { this.CompileController = SandboxedModule.require(modulePath, {
requires: { requires: {
'./CompileManager': (this.CompileManager = {}), './CompileManager': (this.CompileManager = {}),
@ -47,8 +47,8 @@ describe('CompileController', function() {
return (this.next = sinon.stub()) return (this.next = sinon.stub())
}) })
describe('compile', function() { describe('compile', function () {
beforeEach(function() { beforeEach(function () {
this.req.body = { this.req.body = {
compile: 'mock-body' compile: 'mock-body'
} }
@ -82,40 +82,40 @@ describe('CompileController', function() {
return (this.res.send = sinon.stub()) return (this.res.send = sinon.stub())
}) })
describe('successfully', function() { describe('successfully', function () {
beforeEach(function() { beforeEach(function () {
this.CompileManager.doCompileWithLock = sinon this.CompileManager.doCompileWithLock = sinon
.stub() .stub()
.callsArgWith(1, null, this.output_files) .callsArgWith(1, null, this.output_files)
return this.CompileController.compile(this.req, this.res) return this.CompileController.compile(this.req, this.res)
}) })
it('should parse the request', function() { it('should parse the request', function () {
return this.RequestParser.parse return this.RequestParser.parse
.calledWith(this.req.body) .calledWith(this.req.body)
.should.equal(true) .should.equal(true)
}) })
it('should run the compile for the specified project', function() { it('should run the compile for the specified project', function () {
return this.CompileManager.doCompileWithLock return this.CompileManager.doCompileWithLock
.calledWith(this.request_with_project_id) .calledWith(this.request_with_project_id)
.should.equal(true) .should.equal(true)
}) })
it('should mark the project as accessed', function() { it('should mark the project as accessed', function () {
return this.ProjectPersistenceManager.markProjectAsJustAccessed return this.ProjectPersistenceManager.markProjectAsJustAccessed
.calledWith(this.project_id) .calledWith(this.project_id)
.should.equal(true) .should.equal(true)
}) })
return it('should return the JSON response', function() { return it('should return the JSON response', function () {
this.res.status.calledWith(200).should.equal(true) this.res.status.calledWith(200).should.equal(true)
return this.res.send return this.res.send
.calledWith({ .calledWith({
compile: { compile: {
status: 'success', status: 'success',
error: null, error: null,
outputFiles: this.output_files.map(file => { outputFiles: this.output_files.map((file) => {
return { return {
url: `${this.Settings.apis.clsi.url}/project/${this.project_id}/build/${file.build}/output/${file.path}`, url: `${this.Settings.apis.clsi.url}/project/${this.project_id}/build/${file.build}/output/${file.path}`,
path: file.path, path: file.path,
@ -129,15 +129,15 @@ describe('CompileController', function() {
}) })
}) })
describe('with an error', function() { describe('with an error', function () {
beforeEach(function() { beforeEach(function () {
this.CompileManager.doCompileWithLock = sinon this.CompileManager.doCompileWithLock = sinon
.stub() .stub()
.callsArgWith(1, new Error((this.message = 'error message')), null) .callsArgWith(1, new Error((this.message = 'error message')), null)
return this.CompileController.compile(this.req, this.res) return this.CompileController.compile(this.req, this.res)
}) })
return it('should return the JSON response with the error', function() { return it('should return the JSON response with the error', function () {
this.res.status.calledWith(500).should.equal(true) this.res.status.calledWith(500).should.equal(true)
return this.res.send return this.res.send
.calledWith({ .calledWith({
@ -151,8 +151,8 @@ describe('CompileController', function() {
}) })
}) })
describe('when the request times out', function() { describe('when the request times out', function () {
beforeEach(function() { beforeEach(function () {
this.error = new Error((this.message = 'container timed out')) this.error = new Error((this.message = 'container timed out'))
this.error.timedout = true this.error.timedout = true
this.CompileManager.doCompileWithLock = sinon this.CompileManager.doCompileWithLock = sinon
@ -161,7 +161,7 @@ describe('CompileController', function() {
return this.CompileController.compile(this.req, this.res) return this.CompileController.compile(this.req, this.res)
}) })
return it('should return the JSON response with the timeout status', function() { return it('should return the JSON response with the timeout status', function () {
this.res.status.calledWith(200).should.equal(true) this.res.status.calledWith(200).should.equal(true)
return this.res.send return this.res.send
.calledWith({ .calledWith({
@ -175,15 +175,15 @@ describe('CompileController', function() {
}) })
}) })
return describe('when the request returns no output files', function() { return describe('when the request returns no output files', function () {
beforeEach(function() { beforeEach(function () {
this.CompileManager.doCompileWithLock = sinon this.CompileManager.doCompileWithLock = sinon
.stub() .stub()
.callsArgWith(1, null, []) .callsArgWith(1, null, [])
return this.CompileController.compile(this.req, this.res) return this.CompileController.compile(this.req, this.res)
}) })
return it('should return the JSON response with the failure status', function() { return it('should return the JSON response with the failure status', function () {
this.res.status.calledWith(200).should.equal(true) this.res.status.calledWith(200).should.equal(true)
return this.res.send return this.res.send
.calledWith({ .calledWith({
@ -198,8 +198,8 @@ describe('CompileController', function() {
}) })
}) })
describe('syncFromCode', function() { describe('syncFromCode', function () {
beforeEach(function() { beforeEach(function () {
this.file = 'main.tex' this.file = 'main.tex'
this.line = 42 this.line = 42
this.column = 5 this.column = 5
@ -218,7 +218,7 @@ describe('CompileController', function() {
return this.CompileController.syncFromCode(this.req, this.res, this.next) return this.CompileController.syncFromCode(this.req, this.res, this.next)
}) })
it('should find the corresponding location in the PDF', function() { it('should find the corresponding location in the PDF', function () {
return this.CompileManager.syncFromCode return this.CompileManager.syncFromCode
.calledWith( .calledWith(
this.project_id, this.project_id,
@ -230,7 +230,7 @@ describe('CompileController', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should return the positions', function() { return it('should return the positions', function () {
return this.res.json return this.res.json
.calledWith({ .calledWith({
pdf: this.pdfPositions pdf: this.pdfPositions
@ -239,8 +239,8 @@ describe('CompileController', function() {
}) })
}) })
describe('syncFromPdf', function() { describe('syncFromPdf', function () {
beforeEach(function() { beforeEach(function () {
this.page = 5 this.page = 5
this.h = 100.23 this.h = 100.23
this.v = 45.67 this.v = 45.67
@ -259,13 +259,13 @@ describe('CompileController', function() {
return this.CompileController.syncFromPdf(this.req, this.res, this.next) return this.CompileController.syncFromPdf(this.req, this.res, this.next)
}) })
it('should find the corresponding location in the code', function() { it('should find the corresponding location in the code', function () {
return this.CompileManager.syncFromPdf return this.CompileManager.syncFromPdf
.calledWith(this.project_id, undefined, this.page, this.h, this.v) .calledWith(this.project_id, undefined, this.page, this.h, this.v)
.should.equal(true) .should.equal(true)
}) })
return it('should return the positions', function() { return it('should return the positions', function () {
return this.res.json return this.res.json
.calledWith({ .calledWith({
code: this.codePositions code: this.codePositions
@ -274,8 +274,8 @@ describe('CompileController', function() {
}) })
}) })
return describe('wordcount', function() { return describe('wordcount', function () {
beforeEach(function() { beforeEach(function () {
this.file = 'main.tex' this.file = 'main.tex'
this.project_id = 'mock-project-id' this.project_id = 'mock-project-id'
this.req.params = { project_id: this.project_id } this.req.params = { project_id: this.project_id }
@ -290,14 +290,14 @@ describe('CompileController', function() {
.callsArgWith(4, null, (this.texcount = ['mock-texcount'])) .callsArgWith(4, null, (this.texcount = ['mock-texcount']))
}) })
it('should return the word count of a file', function() { it('should return the word count of a file', function () {
this.CompileController.wordcount(this.req, this.res, this.next) this.CompileController.wordcount(this.req, this.res, this.next)
return this.CompileManager.wordcount return this.CompileManager.wordcount
.calledWith(this.project_id, undefined, this.file, this.image) .calledWith(this.project_id, undefined, this.file, this.image)
.should.equal(true) .should.equal(true)
}) })
it('should return the texcount info', function() { it('should return the texcount info', function () {
this.CompileController.wordcount(this.req, this.res, this.next) this.CompileController.wordcount(this.req, this.res, this.next)
return this.res.json return this.res.json
.calledWith({ .calledWith({
@ -306,8 +306,8 @@ describe('CompileController', function() {
.should.equal(true) .should.equal(true)
}) })
describe('when allowedImages is set', function() { describe('when allowedImages is set', function () {
beforeEach(function() { beforeEach(function () {
this.Settings.clsi = { docker: {} } this.Settings.clsi = { docker: {} }
this.Settings.clsi.docker.allowedImages = [ this.Settings.clsi.docker.allowedImages = [
'repo/image:tag1', 'repo/image:tag1',
@ -317,28 +317,28 @@ describe('CompileController', function() {
this.res.status = sinon.stub().returns({ send: this.res.send }) this.res.status = sinon.stub().returns({ send: this.res.send })
}) })
describe('with an invalid image', function() { describe('with an invalid image', function () {
beforeEach(function() { beforeEach(function () {
this.req.query.image = 'something/evil:1337' this.req.query.image = 'something/evil:1337'
this.CompileController.wordcount(this.req, this.res, this.next) this.CompileController.wordcount(this.req, this.res, this.next)
}) })
it('should return a 400', function() { it('should return a 400', function () {
expect(this.res.status.calledWith(400)).to.equal(true) expect(this.res.status.calledWith(400)).to.equal(true)
}) })
it('should not run the query', function() { it('should not run the query', function () {
expect(this.CompileManager.wordcount.called).to.equal(false) expect(this.CompileManager.wordcount.called).to.equal(false)
}) })
}) })
describe('with a valid image', function() { describe('with a valid image', function () {
beforeEach(function() { beforeEach(function () {
this.req.query.image = 'repo/image:tag1' this.req.query.image = 'repo/image:tag1'
this.CompileController.wordcount(this.req, this.res, this.next) this.CompileController.wordcount(this.req, this.res, this.next)
}) })
it('should not return a 400', function() { it('should not return a 400', function () {
expect(this.res.status.calledWith(400)).to.equal(false) expect(this.res.status.calledWith(400)).to.equal(false)
}) })
it('should run the query', function() { it('should run the query', function () {
expect(this.CompileManager.wordcount.called).to.equal(true) expect(this.CompileManager.wordcount.called).to.equal(true)
}) })
}) })

View file

@ -24,8 +24,8 @@ const tk = require('timekeeper')
const { EventEmitter } = require('events') const { EventEmitter } = require('events')
const Path = require('path') const Path = require('path')
describe('CompileManager', function() { describe('CompileManager', function () {
beforeEach(function() { beforeEach(function () {
this.CompileManager = SandboxedModule.require(modulePath, { this.CompileManager = SandboxedModule.require(modulePath, {
requires: { requires: {
'./LatexRunner': (this.LatexRunner = {}), './LatexRunner': (this.LatexRunner = {}),
@ -60,8 +60,8 @@ describe('CompileManager', function() {
this.project_id = 'project-id-123' this.project_id = 'project-id-123'
return (this.user_id = '1234') return (this.user_id = '1234')
}) })
describe('doCompileWithLock', function() { describe('doCompileWithLock', function () {
beforeEach(function() { beforeEach(function () {
this.request = { this.request = {
resources: (this.resources = 'mock-resources'), resources: (this.resources = 'mock-resources'),
project_id: this.project_id, project_id: this.project_id,
@ -77,33 +77,33 @@ describe('CompileManager', function() {
runner((err, ...result) => callback(err, ...Array.from(result)))) runner((err, ...result) => callback(err, ...Array.from(result))))
}) })
describe('when the project is not locked', function() { describe('when the project is not locked', function () {
beforeEach(function() { beforeEach(function () {
return this.CompileManager.doCompileWithLock( return this.CompileManager.doCompileWithLock(
this.request, this.request,
this.callback this.callback
) )
}) })
it('should ensure that the compile directory exists', function() { it('should ensure that the compile directory exists', function () {
return this.fse.ensureDir.calledWith(this.compileDir).should.equal(true) return this.fse.ensureDir.calledWith(this.compileDir).should.equal(true)
}) })
it('should call doCompile with the request', function() { it('should call doCompile with the request', function () {
return this.CompileManager.doCompile return this.CompileManager.doCompile
.calledWith(this.request) .calledWith(this.request)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with the output files', function() { return it('should call the callback with the output files', function () {
return this.callback return this.callback
.calledWithExactly(null, this.output_files) .calledWithExactly(null, this.output_files)
.should.equal(true) .should.equal(true)
}) })
}) })
return describe('when the project is locked', function() { return describe('when the project is locked', function () {
beforeEach(function() { beforeEach(function () {
this.error = new Error('locked') this.error = new Error('locked')
this.LockManager.runWithLock = (lockFile, runner, callback) => { this.LockManager.runWithLock = (lockFile, runner, callback) => {
return callback(this.error) return callback(this.error)
@ -114,22 +114,22 @@ describe('CompileManager', function() {
) )
}) })
it('should ensure that the compile directory exists', function() { it('should ensure that the compile directory exists', function () {
return this.fse.ensureDir.calledWith(this.compileDir).should.equal(true) return this.fse.ensureDir.calledWith(this.compileDir).should.equal(true)
}) })
it('should not call doCompile with the request', function() { it('should not call doCompile with the request', function () {
return this.CompileManager.doCompile.called.should.equal(false) return this.CompileManager.doCompile.called.should.equal(false)
}) })
return it('should call the callback with the error', function() { return it('should call the callback with the error', function () {
return this.callback.calledWithExactly(this.error).should.equal(true) return this.callback.calledWithExactly(this.error).should.equal(true)
}) })
}) })
}) })
describe('doCompile', function() { describe('doCompile', function () {
beforeEach(function() { beforeEach(function () {
this.output_files = [ this.output_files = [
{ {
path: 'output.log', path: 'output.log',
@ -180,18 +180,18 @@ describe('CompileManager', function() {
return (this.TikzManager.checkMainFile = sinon.stub().callsArg(3, false)) return (this.TikzManager.checkMainFile = sinon.stub().callsArg(3, false))
}) })
describe('normally', function() { describe('normally', function () {
beforeEach(function() { beforeEach(function () {
return this.CompileManager.doCompile(this.request, this.callback) return this.CompileManager.doCompile(this.request, this.callback)
}) })
it('should write the resources to disk', function() { it('should write the resources to disk', function () {
return this.ResourceWriter.syncResourcesToDisk return this.ResourceWriter.syncResourcesToDisk
.calledWith(this.request, this.compileDir) .calledWith(this.request, this.compileDir)
.should.equal(true) .should.equal(true)
}) })
it('should run LaTeX', function() { it('should run LaTeX', function () {
return this.LatexRunner.runLatex return this.LatexRunner.runLatex
.calledWith(`${this.project_id}-${this.user_id}`, { .calledWith(`${this.project_id}-${this.user_id}`, {
directory: this.compileDir, directory: this.compileDir,
@ -206,43 +206,43 @@ describe('CompileManager', function() {
.should.equal(true) .should.equal(true)
}) })
it('should find the output files', function() { it('should find the output files', function () {
return this.OutputFileFinder.findOutputFiles return this.OutputFileFinder.findOutputFiles
.calledWith(this.resources, this.compileDir) .calledWith(this.resources, this.compileDir)
.should.equal(true) .should.equal(true)
}) })
it('should return the output files', function() { it('should return the output files', function () {
return this.callback return this.callback
.calledWith(null, this.build_files) .calledWith(null, this.build_files)
.should.equal(true) .should.equal(true)
}) })
return it('should not inject draft mode by default', function() { return it('should not inject draft mode by default', function () {
return this.DraftModeManager.injectDraftMode.called.should.equal(false) return this.DraftModeManager.injectDraftMode.called.should.equal(false)
}) })
}) })
describe('with draft mode', function() { describe('with draft mode', function () {
beforeEach(function() { beforeEach(function () {
this.request.draft = true this.request.draft = true
return this.CompileManager.doCompile(this.request, this.callback) return this.CompileManager.doCompile(this.request, this.callback)
}) })
return it('should inject the draft mode header', function() { return it('should inject the draft mode header', function () {
return this.DraftModeManager.injectDraftMode return this.DraftModeManager.injectDraftMode
.calledWith(this.compileDir + '/' + this.rootResourcePath) .calledWith(this.compileDir + '/' + this.rootResourcePath)
.should.equal(true) .should.equal(true)
}) })
}) })
describe('with a check option', function() { describe('with a check option', function () {
beforeEach(function() { beforeEach(function () {
this.request.check = 'error' this.request.check = 'error'
return this.CompileManager.doCompile(this.request, this.callback) return this.CompileManager.doCompile(this.request, this.callback)
}) })
return it('should run chktex', function() { return it('should run chktex', function () {
return this.LatexRunner.runLatex return this.LatexRunner.runLatex
.calledWith(`${this.project_id}-${this.user_id}`, { .calledWith(`${this.project_id}-${this.user_id}`, {
directory: this.compileDir, directory: this.compileDir,
@ -262,14 +262,14 @@ describe('CompileManager', function() {
}) })
}) })
return describe('with a knitr file and check options', function() { return describe('with a knitr file and check options', function () {
beforeEach(function() { beforeEach(function () {
this.request.rootResourcePath = 'main.Rtex' this.request.rootResourcePath = 'main.Rtex'
this.request.check = 'error' this.request.check = 'error'
return this.CompileManager.doCompile(this.request, this.callback) return this.CompileManager.doCompile(this.request, this.callback)
}) })
return it('should not run chktex', function() { return it('should not run chktex', function () {
return this.LatexRunner.runLatex return this.LatexRunner.runLatex
.calledWith(`${this.project_id}-${this.user_id}`, { .calledWith(`${this.project_id}-${this.user_id}`, {
directory: this.compileDir, directory: this.compileDir,
@ -286,9 +286,9 @@ describe('CompileManager', function() {
}) })
}) })
describe('clearProject', function() { describe('clearProject', function () {
describe('succesfully', function() { describe('succesfully', function () {
beforeEach(function() { beforeEach(function () {
this.Settings.compileDir = 'compiles' this.Settings.compileDir = 'compiles'
this.fs.lstat = sinon.stub().callsArgWith(1, null, { this.fs.lstat = sinon.stub().callsArgWith(1, null, {
isDirectory() { isDirectory() {
@ -308,7 +308,7 @@ describe('CompileManager', function() {
return this.proc.emit('close', 0) return this.proc.emit('close', 0)
}) })
it('should remove the project directory', function() { it('should remove the project directory', function () {
return this.child_process.spawn return this.child_process.spawn
.calledWith('rm', [ .calledWith('rm', [
'-r', '-r',
@ -317,13 +317,13 @@ describe('CompileManager', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
return describe('with a non-success status code', function() { return describe('with a non-success status code', function () {
beforeEach(function() { beforeEach(function () {
this.Settings.compileDir = 'compiles' this.Settings.compileDir = 'compiles'
this.fs.lstat = sinon.stub().callsArgWith(1, null, { this.fs.lstat = sinon.stub().callsArgWith(1, null, {
isDirectory() { isDirectory() {
@ -344,7 +344,7 @@ describe('CompileManager', function() {
return this.proc.emit('close', 1) return this.proc.emit('close', 1)
}) })
it('should remove the project directory', function() { it('should remove the project directory', function () {
return this.child_process.spawn return this.child_process.spawn
.calledWith('rm', [ .calledWith('rm', [
'-r', '-r',
@ -353,7 +353,7 @@ describe('CompileManager', function() {
.should.equal(true) .should.equal(true)
}) })
it('should call the callback with an error from the stderr', function() { it('should call the callback with an error from the stderr', function () {
this.callback.calledWithExactly(sinon.match(Error)).should.equal(true) this.callback.calledWithExactly(sinon.match(Error)).should.equal(true)
this.callback.args[0][0].message.should.equal( this.callback.args[0][0].message.should.equal(
@ -363,8 +363,8 @@ describe('CompileManager', function() {
}) })
}) })
describe('syncing', function() { describe('syncing', function () {
beforeEach(function() { beforeEach(function () {
this.page = 1 this.page = 1
this.h = 42.23 this.h = 42.23
this.v = 87.56 this.v = 87.56
@ -374,12 +374,12 @@ describe('CompileManager', function() {
this.column = 3 this.column = 3
this.file_name = 'main.tex' this.file_name = 'main.tex'
this.child_process.execFile = sinon.stub() this.child_process.execFile = sinon.stub()
return (this.Settings.path.synctexBaseDir = project_id => return (this.Settings.path.synctexBaseDir = (project_id) =>
`${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`) `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`)
}) })
describe('syncFromCode', function() { describe('syncFromCode', function () {
beforeEach(function() { beforeEach(function () {
this.fs.stat = sinon.stub().callsArgWith(1, null, { this.fs.stat = sinon.stub().callsArgWith(1, null, {
isFile() { isFile() {
return true return true
@ -399,7 +399,7 @@ describe('CompileManager', function() {
) )
}) })
it('should execute the synctex binary', function() { it('should execute the synctex binary', function () {
const bin_path = Path.resolve(__dirname + '/../../../bin/synctex') const bin_path = Path.resolve(__dirname + '/../../../bin/synctex')
const synctex_path = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/output.pdf` const synctex_path = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/output.pdf`
const file_path = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/${this.file_name}` const file_path = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/${this.file_name}`
@ -422,7 +422,7 @@ describe('CompileManager', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with the parsed output', function() { return it('should call the callback with the parsed output', function () {
return this.callback return this.callback
.calledWith(null, [ .calledWith(null, [
{ {
@ -437,8 +437,8 @@ describe('CompileManager', function() {
}) })
}) })
return describe('syncFromPdf', function() { return describe('syncFromPdf', function () {
beforeEach(function() { beforeEach(function () {
this.fs.stat = sinon.stub().callsArgWith(1, null, { this.fs.stat = sinon.stub().callsArgWith(1, null, {
isFile() { isFile() {
return true return true
@ -458,7 +458,7 @@ describe('CompileManager', function() {
) )
}) })
it('should execute the synctex binary', function() { it('should execute the synctex binary', function () {
const bin_path = Path.resolve(__dirname + '/../../../bin/synctex') const bin_path = Path.resolve(__dirname + '/../../../bin/synctex')
const synctex_path = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/output.pdf` const synctex_path = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/output.pdf`
return this.CommandRunner.run return this.CommandRunner.run
@ -473,7 +473,7 @@ describe('CompileManager', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with the parsed output', function() { return it('should call the callback with the parsed output', function () {
return this.callback return this.callback
.calledWith(null, [ .calledWith(null, [
{ {
@ -487,8 +487,8 @@ describe('CompileManager', function() {
}) })
}) })
return describe('wordcount', function() { return describe('wordcount', function () {
beforeEach(function() { beforeEach(function () {
this.CommandRunner.run = sinon.stub().callsArg(7) this.CommandRunner.run = sinon.stub().callsArg(7)
this.fs.readFile = sinon this.fs.readFile = sinon
.stub() .stub()
@ -514,7 +514,7 @@ describe('CompileManager', function() {
) )
}) })
it('should run the texcount command', function() { it('should run the texcount command', function () {
this.directory = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}` this.directory = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`
this.file_path = `$COMPILE_DIR/${this.file_name}` this.file_path = `$COMPILE_DIR/${this.file_name}`
this.command = [ this.command = [
@ -537,7 +537,7 @@ describe('CompileManager', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with the parsed output', function() { return it('should call the callback with the parsed output', function () {
return this.callback return this.callback
.calledWith(null, { .calledWith(null, {
encode: 'ascii', encode: 'ascii',

View file

@ -18,61 +18,61 @@ const modulePath = require('path').join(
'../../../app/js/ContentTypeMapper' '../../../app/js/ContentTypeMapper'
) )
describe('ContentTypeMapper', function() { describe('ContentTypeMapper', function () {
beforeEach(function() { beforeEach(function () {
return (this.ContentTypeMapper = SandboxedModule.require(modulePath)) return (this.ContentTypeMapper = SandboxedModule.require(modulePath))
}) })
return describe('map', function() { return describe('map', function () {
it('should map .txt to text/plain', function() { it('should map .txt to text/plain', function () {
const content_type = this.ContentTypeMapper.map('example.txt') const content_type = this.ContentTypeMapper.map('example.txt')
return content_type.should.equal('text/plain') return content_type.should.equal('text/plain')
}) })
it('should map .csv to text/csv', function() { it('should map .csv to text/csv', function () {
const content_type = this.ContentTypeMapper.map('example.csv') const content_type = this.ContentTypeMapper.map('example.csv')
return content_type.should.equal('text/csv') return content_type.should.equal('text/csv')
}) })
it('should map .pdf to application/pdf', function() { it('should map .pdf to application/pdf', function () {
const content_type = this.ContentTypeMapper.map('example.pdf') const content_type = this.ContentTypeMapper.map('example.pdf')
return content_type.should.equal('application/pdf') return content_type.should.equal('application/pdf')
}) })
it('should fall back to octet-stream', function() { it('should fall back to octet-stream', function () {
const content_type = this.ContentTypeMapper.map('example.unknown') const content_type = this.ContentTypeMapper.map('example.unknown')
return content_type.should.equal('application/octet-stream') return content_type.should.equal('application/octet-stream')
}) })
describe('coercing web files to plain text', function() { describe('coercing web files to plain text', function () {
it('should map .js to plain text', function() { it('should map .js to plain text', function () {
const content_type = this.ContentTypeMapper.map('example.js') const content_type = this.ContentTypeMapper.map('example.js')
return content_type.should.equal('text/plain') return content_type.should.equal('text/plain')
}) })
it('should map .html to plain text', function() { it('should map .html to plain text', function () {
const content_type = this.ContentTypeMapper.map('example.html') const content_type = this.ContentTypeMapper.map('example.html')
return content_type.should.equal('text/plain') return content_type.should.equal('text/plain')
}) })
return it('should map .css to plain text', function() { return it('should map .css to plain text', function () {
const content_type = this.ContentTypeMapper.map('example.css') const content_type = this.ContentTypeMapper.map('example.css')
return content_type.should.equal('text/plain') return content_type.should.equal('text/plain')
}) })
}) })
return describe('image files', function() { return describe('image files', function () {
it('should map .png to image/png', function() { it('should map .png to image/png', function () {
const content_type = this.ContentTypeMapper.map('example.png') const content_type = this.ContentTypeMapper.map('example.png')
return content_type.should.equal('image/png') return content_type.should.equal('image/png')
}) })
it('should map .jpeg to image/jpeg', function() { it('should map .jpeg to image/jpeg', function () {
const content_type = this.ContentTypeMapper.map('example.jpeg') const content_type = this.ContentTypeMapper.map('example.jpeg')
return content_type.should.equal('image/jpeg') return content_type.should.equal('image/jpeg')
}) })
return it('should map .svg to text/plain to protect against XSS (SVG can execute JS)', function() { return it('should map .svg to text/plain to protect against XSS (SVG can execute JS)', function () {
const content_type = this.ContentTypeMapper.map('example.svg') const content_type = this.ContentTypeMapper.map('example.svg')
return content_type.should.equal('text/plain') return content_type.should.equal('text/plain')
}) })

View file

@ -17,8 +17,8 @@ const modulePath = require('path').join(
'../../../app/js/DockerLockManager' '../../../app/js/DockerLockManager'
) )
describe('LockManager', function() { describe('LockManager', function () {
beforeEach(function() { beforeEach(function () {
return (this.LockManager = SandboxedModule.require(modulePath, { return (this.LockManager = SandboxedModule.require(modulePath, {
requires: { requires: {
'settings-sharelatex': (this.Settings = { clsi: { docker: {} } }), 'settings-sharelatex': (this.Settings = { clsi: { docker: {} } }),
@ -30,13 +30,13 @@ describe('LockManager', function() {
})) }))
}) })
return describe('runWithLock', function() { return describe('runWithLock', function () {
describe('with a single lock', function() { describe('with a single lock', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.callback = sinon.stub() this.callback = sinon.stub()
return this.LockManager.runWithLock( return this.LockManager.runWithLock(
'lock-one', 'lock-one',
releaseLock => (releaseLock) =>
setTimeout(() => releaseLock(null, 'hello', 'world'), 100), setTimeout(() => releaseLock(null, 'hello', 'world'), 100),
(err, ...args) => { (err, ...args) => {
@ -46,20 +46,20 @@ describe('LockManager', function() {
) )
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback return this.callback
.calledWith(null, 'hello', 'world') .calledWith(null, 'hello', 'world')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('with two locks', function() { describe('with two locks', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.callback1 = sinon.stub() this.callback1 = sinon.stub()
this.callback2 = sinon.stub() this.callback2 = sinon.stub()
this.LockManager.runWithLock( this.LockManager.runWithLock(
'lock-one', 'lock-one',
releaseLock => (releaseLock) =>
setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100), setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100),
(err, ...args) => { (err, ...args) => {
@ -68,7 +68,7 @@ describe('LockManager', function() {
) )
return this.LockManager.runWithLock( return this.LockManager.runWithLock(
'lock-two', 'lock-two',
releaseLock => (releaseLock) =>
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200), setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200),
(err, ...args) => { (err, ...args) => {
@ -78,29 +78,29 @@ describe('LockManager', function() {
) )
}) })
it('should call the first callback', function() { it('should call the first callback', function () {
return this.callback1 return this.callback1
.calledWith(null, 'hello', 'world', 'one') .calledWith(null, 'hello', 'world', 'one')
.should.equal(true) .should.equal(true)
}) })
return it('should call the second callback', function() { return it('should call the second callback', function () {
return this.callback2 return this.callback2
.calledWith(null, 'hello', 'world', 'two') .calledWith(null, 'hello', 'world', 'two')
.should.equal(true) .should.equal(true)
}) })
}) })
return describe('with lock contention', function() { return describe('with lock contention', function () {
describe('where the first lock is released quickly', function() { describe('where the first lock is released quickly', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.LockManager.MAX_LOCK_WAIT_TIME = 1000 this.LockManager.MAX_LOCK_WAIT_TIME = 1000
this.LockManager.LOCK_TEST_INTERVAL = 100 this.LockManager.LOCK_TEST_INTERVAL = 100
this.callback1 = sinon.stub() this.callback1 = sinon.stub()
this.callback2 = sinon.stub() this.callback2 = sinon.stub()
this.LockManager.runWithLock( this.LockManager.runWithLock(
'lock', 'lock',
releaseLock => (releaseLock) =>
setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100), setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100),
(err, ...args) => { (err, ...args) => {
@ -109,7 +109,7 @@ describe('LockManager', function() {
) )
return this.LockManager.runWithLock( return this.LockManager.runWithLock(
'lock', 'lock',
releaseLock => (releaseLock) =>
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200), setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200),
(err, ...args) => { (err, ...args) => {
@ -119,21 +119,21 @@ describe('LockManager', function() {
) )
}) })
it('should call the first callback', function() { it('should call the first callback', function () {
return this.callback1 return this.callback1
.calledWith(null, 'hello', 'world', 'one') .calledWith(null, 'hello', 'world', 'one')
.should.equal(true) .should.equal(true)
}) })
return it('should call the second callback', function() { return it('should call the second callback', function () {
return this.callback2 return this.callback2
.calledWith(null, 'hello', 'world', 'two') .calledWith(null, 'hello', 'world', 'two')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('where the first lock is held longer than the waiting time', function() { describe('where the first lock is held longer than the waiting time', function () {
beforeEach(function(done) { beforeEach(function (done) {
let doneTwo let doneTwo
this.LockManager.MAX_LOCK_HOLD_TIME = 10000 this.LockManager.MAX_LOCK_HOLD_TIME = 10000
this.LockManager.MAX_LOCK_WAIT_TIME = 1000 this.LockManager.MAX_LOCK_WAIT_TIME = 1000
@ -141,7 +141,7 @@ describe('LockManager', function() {
this.callback1 = sinon.stub() this.callback1 = sinon.stub()
this.callback2 = sinon.stub() this.callback2 = sinon.stub()
let doneOne = (doneTwo = false) let doneOne = (doneTwo = false)
const finish = function(key) { const finish = function (key) {
if (key === 1) { if (key === 1) {
doneOne = true doneOne = true
} }
@ -154,7 +154,7 @@ describe('LockManager', function() {
} }
this.LockManager.runWithLock( this.LockManager.runWithLock(
'lock', 'lock',
releaseLock => (releaseLock) =>
setTimeout( setTimeout(
() => releaseLock(null, 'hello', 'world', 'one'), () => releaseLock(null, 'hello', 'world', 'one'),
1100 1100
@ -167,7 +167,7 @@ describe('LockManager', function() {
) )
return this.LockManager.runWithLock( return this.LockManager.runWithLock(
'lock', 'lock',
releaseLock => (releaseLock) =>
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100), setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100),
(err, ...args) => { (err, ...args) => {
@ -177,20 +177,20 @@ describe('LockManager', function() {
) )
}) })
it('should call the first callback', function() { it('should call the first callback', function () {
return this.callback1 return this.callback1
.calledWith(null, 'hello', 'world', 'one') .calledWith(null, 'hello', 'world', 'one')
.should.equal(true) .should.equal(true)
}) })
return it('should call the second callback with an error', function() { return it('should call the second callback with an error', function () {
const error = sinon.match.instanceOf(Error) const error = sinon.match.instanceOf(Error)
return this.callback2.calledWith(error).should.equal(true) return this.callback2.calledWith(error).should.equal(true)
}) })
}) })
return describe('where the first lock is held longer than the max holding time', function() { return describe('where the first lock is held longer than the max holding time', function () {
beforeEach(function(done) { beforeEach(function (done) {
let doneTwo let doneTwo
this.LockManager.MAX_LOCK_HOLD_TIME = 1000 this.LockManager.MAX_LOCK_HOLD_TIME = 1000
this.LockManager.MAX_LOCK_WAIT_TIME = 2000 this.LockManager.MAX_LOCK_WAIT_TIME = 2000
@ -198,7 +198,7 @@ describe('LockManager', function() {
this.callback1 = sinon.stub() this.callback1 = sinon.stub()
this.callback2 = sinon.stub() this.callback2 = sinon.stub()
let doneOne = (doneTwo = false) let doneOne = (doneTwo = false)
const finish = function(key) { const finish = function (key) {
if (key === 1) { if (key === 1) {
doneOne = true doneOne = true
} }
@ -211,7 +211,7 @@ describe('LockManager', function() {
} }
this.LockManager.runWithLock( this.LockManager.runWithLock(
'lock', 'lock',
releaseLock => (releaseLock) =>
setTimeout( setTimeout(
() => releaseLock(null, 'hello', 'world', 'one'), () => releaseLock(null, 'hello', 'world', 'one'),
1500 1500
@ -224,7 +224,7 @@ describe('LockManager', function() {
) )
return this.LockManager.runWithLock( return this.LockManager.runWithLock(
'lock', 'lock',
releaseLock => (releaseLock) =>
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100), setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100),
(err, ...args) => { (err, ...args) => {
@ -234,13 +234,13 @@ describe('LockManager', function() {
) )
}) })
it('should call the first callback', function() { it('should call the first callback', function () {
return this.callback1 return this.callback1
.calledWith(null, 'hello', 'world', 'one') .calledWith(null, 'hello', 'world', 'one')
.should.equal(true) .should.equal(true)
}) })
return it('should call the second callback', function() { return it('should call the second callback', function () {
return this.callback2 return this.callback2
.calledWith(null, 'hello', 'world', 'two') .calledWith(null, 'hello', 'world', 'two')
.should.equal(true) .should.equal(true)

View file

@ -23,8 +23,8 @@ const modulePath = require('path').join(
) )
const Path = require('path') const Path = require('path')
describe('DockerRunner', function() { describe('DockerRunner', function () {
beforeEach(function() { beforeEach(function () {
let container, Docker, Timer let container, Docker, Timer
this.container = container = {} this.container = container = {}
this.DockerRunner = SandboxedModule.require(modulePath, { this.DockerRunner = SandboxedModule.require(modulePath, {
@ -39,7 +39,7 @@ describe('DockerRunner', function() {
info: sinon.stub(), info: sinon.stub(),
warn: sinon.stub() warn: sinon.stub()
}), }),
dockerode: (Docker = (function() { dockerode: (Docker = (function () {
Docker = class Docker { Docker = class Docker {
static initClass() { static initClass() {
this.prototype.getContainer = sinon.stub().returns(container) this.prototype.getContainer = sinon.stub().returns(container)
@ -90,12 +90,12 @@ describe('DockerRunner', function() {
return (this.Settings.clsi.docker.env = { PATH: 'mock-path' }) return (this.Settings.clsi.docker.env = { PATH: 'mock-path' })
}) })
afterEach(function() { afterEach(function () {
this.DockerRunner.stopContainerMonitor() this.DockerRunner.stopContainerMonitor()
}) })
describe('run', function() { describe('run', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.DockerRunner._getContainerOptions = sinon this.DockerRunner._getContainerOptions = sinon
.stub() .stub()
.returns((this.options = { mockoptions: 'foo' })) .returns((this.options = { mockoptions: 'foo' }))
@ -111,8 +111,8 @@ describe('DockerRunner', function() {
return done() return done()
}) })
describe('successfully', function() { describe('successfully', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.DockerRunner._runAndWaitForContainer = sinon this.DockerRunner._runAndWaitForContainer = sinon
.stub() .stub()
.callsArgWith(3, null, (this.output = 'mock-output')) .callsArgWith(3, null, (this.output = 'mock-output'))
@ -131,7 +131,7 @@ describe('DockerRunner', function() {
) )
}) })
it('should generate the options for the container', function() { it('should generate the options for the container', function () {
return this.DockerRunner._getContainerOptions return this.DockerRunner._getContainerOptions
.calledWith( .calledWith(
this.command_with_dir, this.command_with_dir,
@ -142,25 +142,25 @@ describe('DockerRunner', function() {
.should.equal(true) .should.equal(true)
}) })
it('should generate the fingerprint from the returned options', function() { it('should generate the fingerprint from the returned options', function () {
return this.DockerRunner._fingerprintContainer return this.DockerRunner._fingerprintContainer
.calledWith(this.options) .calledWith(this.options)
.should.equal(true) .should.equal(true)
}) })
it('should do the run', function() { it('should do the run', function () {
return this.DockerRunner._runAndWaitForContainer return this.DockerRunner._runAndWaitForContainer
.calledWith(this.options, this.volumes, this.timeout) .calledWith(this.options, this.volumes, this.timeout)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.calledWith(null, this.output).should.equal(true) return this.callback.calledWith(null, this.output).should.equal(true)
}) })
}) })
describe('when path.sandboxedCompilesHostDir is set', function() { describe('when path.sandboxedCompilesHostDir is set', function () {
beforeEach(function() { beforeEach(function () {
this.Settings.path.sandboxedCompilesHostDir = '/some/host/dir/compiles' this.Settings.path.sandboxedCompilesHostDir = '/some/host/dir/compiles'
this.directory = '/var/lib/sharelatex/data/compiles/xyz' this.directory = '/var/lib/sharelatex/data/compiles/xyz'
this.DockerRunner._runAndWaitForContainer = sinon this.DockerRunner._runAndWaitForContainer = sinon
@ -178,7 +178,7 @@ describe('DockerRunner', function() {
) )
}) })
it('should re-write the bind directory', function() { it('should re-write the bind directory', function () {
const volumes = this.DockerRunner._runAndWaitForContainer.lastCall const volumes = this.DockerRunner._runAndWaitForContainer.lastCall
.args[1] .args[1]
return expect(volumes).to.deep.equal({ return expect(volumes).to.deep.equal({
@ -186,13 +186,13 @@ describe('DockerRunner', function() {
}) })
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.calledWith(null, this.output).should.equal(true) return this.callback.calledWith(null, this.output).should.equal(true)
}) })
}) })
describe('when the run throws an error', function() { describe('when the run throws an error', function () {
beforeEach(function() { beforeEach(function () {
let firstTime = true let firstTime = true
this.output = 'mock-output' this.output = 'mock-output'
this.DockerRunner._runAndWaitForContainer = ( this.DockerRunner._runAndWaitForContainer = (
@ -202,7 +202,7 @@ describe('DockerRunner', function() {
callback callback
) => { ) => {
if (callback == null) { if (callback == null) {
callback = function(error, output) {} callback = function (error, output) {}
} }
if (firstTime) { if (firstTime) {
firstTime = false firstTime = false
@ -227,25 +227,25 @@ describe('DockerRunner', function() {
) )
}) })
it('should do the run twice', function() { it('should do the run twice', function () {
return this.DockerRunner._runAndWaitForContainer.calledTwice.should.equal( return this.DockerRunner._runAndWaitForContainer.calledTwice.should.equal(
true true
) )
}) })
it('should destroy the container in between', function() { it('should destroy the container in between', function () {
return this.DockerRunner.destroyContainer return this.DockerRunner.destroyContainer
.calledWith(this.name, null) .calledWith(this.name, null)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.calledWith(null, this.output).should.equal(true) return this.callback.calledWith(null, this.output).should.equal(true)
}) })
}) })
describe('with no image', function() { describe('with no image', function () {
beforeEach(function() { beforeEach(function () {
this.DockerRunner._runAndWaitForContainer = sinon this.DockerRunner._runAndWaitForContainer = sinon
.stub() .stub()
.callsArgWith(3, null, (this.output = 'mock-output')) .callsArgWith(3, null, (this.output = 'mock-output'))
@ -261,7 +261,7 @@ describe('DockerRunner', function() {
) )
}) })
return it('should use the default image', function() { return it('should use the default image', function () {
return this.DockerRunner._getContainerOptions return this.DockerRunner._getContainerOptions
.calledWith( .calledWith(
this.command_with_dir, this.command_with_dir,
@ -273,8 +273,8 @@ describe('DockerRunner', function() {
}) })
}) })
describe('with image override', function() { describe('with image override', function () {
beforeEach(function() { beforeEach(function () {
this.Settings.texliveImageNameOveride = 'overrideimage.com/something' this.Settings.texliveImageNameOveride = 'overrideimage.com/something'
this.DockerRunner._runAndWaitForContainer = sinon this.DockerRunner._runAndWaitForContainer = sinon
.stub() .stub()
@ -291,14 +291,14 @@ describe('DockerRunner', function() {
) )
}) })
return it('should use the override and keep the tag', function() { return it('should use the override and keep the tag', function () {
const image = this.DockerRunner._getContainerOptions.args[0][1] const image = this.DockerRunner._getContainerOptions.args[0][1]
return image.should.equal('overrideimage.com/something/image:2016.2') return image.should.equal('overrideimage.com/something/image:2016.2')
}) })
}) })
describe('with image restriction', function() { describe('with image restriction', function () {
beforeEach(function() { beforeEach(function () {
this.Settings.clsi.docker.allowedImages = [ this.Settings.clsi.docker.allowedImages = [
'repo/image:tag1', 'repo/image:tag1',
'repo/image:tag2' 'repo/image:tag2'
@ -308,8 +308,8 @@ describe('DockerRunner', function() {
.callsArgWith(3, null, (this.output = 'mock-output')) .callsArgWith(3, null, (this.output = 'mock-output'))
}) })
describe('with a valid image', function() { describe('with a valid image', function () {
beforeEach(function() { beforeEach(function () {
this.DockerRunner.run( this.DockerRunner.run(
this.project_id, this.project_id,
this.command, this.command,
@ -322,13 +322,13 @@ describe('DockerRunner', function() {
) )
}) })
it('should setup the container', function() { it('should setup the container', function () {
this.DockerRunner._getContainerOptions.called.should.equal(true) this.DockerRunner._getContainerOptions.called.should.equal(true)
}) })
}) })
describe('with a invalid image', function() { describe('with a invalid image', function () {
beforeEach(function() { beforeEach(function () {
this.DockerRunner.run( this.DockerRunner.run(
this.project_id, this.project_id,
this.command, this.command,
@ -341,21 +341,21 @@ describe('DockerRunner', function() {
) )
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
const err = new Error('image not allowed') const err = new Error('image not allowed')
this.callback.called.should.equal(true) this.callback.called.should.equal(true)
this.callback.args[0][0].message.should.equal(err.message) this.callback.args[0][0].message.should.equal(err.message)
}) })
it('should not setup the container', function() { it('should not setup the container', function () {
this.DockerRunner._getContainerOptions.called.should.equal(false) this.DockerRunner._getContainerOptions.called.should.equal(false)
}) })
}) })
}) })
}) })
describe('run with _getOptions', function() { describe('run with _getOptions', function () {
beforeEach(function(done) { beforeEach(function (done) {
// this.DockerRunner._getContainerOptions = sinon // this.DockerRunner._getContainerOptions = sinon
// .stub() // .stub()
// .returns((this.options = { mockoptions: 'foo' })) // .returns((this.options = { mockoptions: 'foo' }))
@ -371,8 +371,8 @@ describe('DockerRunner', function() {
return done() return done()
}) })
describe('when a compile group config is set', function() { describe('when a compile group config is set', function () {
beforeEach(function() { beforeEach(function () {
this.Settings.clsi.docker.compileGroupConfig = { this.Settings.clsi.docker.compileGroupConfig = {
'compile-group': { 'compile-group': {
'HostConfig.newProperty': 'new-property' 'HostConfig.newProperty': 'new-property'
@ -394,7 +394,7 @@ describe('DockerRunner', function() {
) )
}) })
it('should set the docker options for the compile group', function() { it('should set the docker options for the compile group', function () {
const options = this.DockerRunner._runAndWaitForContainer.lastCall const options = this.DockerRunner._runAndWaitForContainer.lastCall
.args[0] .args[0]
return expect(options.HostConfig).to.deep.include({ return expect(options.HostConfig).to.deep.include({
@ -406,14 +406,14 @@ describe('DockerRunner', function() {
}) })
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.calledWith(null, this.output).should.equal(true) return this.callback.calledWith(null, this.output).should.equal(true)
}) })
}) })
}) })
describe('_runAndWaitForContainer', function() { describe('_runAndWaitForContainer', function () {
beforeEach(function() { beforeEach(function () {
this.options = { mockoptions: 'foo', name: (this.name = 'mock-name') } this.options = { mockoptions: 'foo', name: (this.name = 'mock-name') }
this.DockerRunner.startContainer = ( this.DockerRunner.startContainer = (
options, options,
@ -436,25 +436,25 @@ describe('DockerRunner', function() {
) )
}) })
it('should create/start the container', function() { it('should create/start the container', function () {
return this.DockerRunner.startContainer return this.DockerRunner.startContainer
.calledWith(this.options, this.volumes) .calledWith(this.options, this.volumes)
.should.equal(true) .should.equal(true)
}) })
it('should wait for the container to finish', function() { it('should wait for the container to finish', function () {
return this.DockerRunner.waitForContainer return this.DockerRunner.waitForContainer
.calledWith(this.name, this.timeout) .calledWith(this.name, this.timeout)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with the output', function() { return it('should call the callback with the output', function () {
return this.callback.calledWith(null, this.output).should.equal(true) return this.callback.calledWith(null, this.output).should.equal(true)
}) })
}) })
describe('startContainer', function() { describe('startContainer', function () {
beforeEach(function() { beforeEach(function () {
this.attachStreamHandler = sinon.stub() this.attachStreamHandler = sinon.stub()
this.attachStreamHandler.cock = true this.attachStreamHandler.cock = true
this.options = { mockoptions: 'foo', name: 'mock-name' } this.options = { mockoptions: 'foo', name: 'mock-name' }
@ -470,8 +470,8 @@ describe('DockerRunner', function() {
return sinon.spy(this.DockerRunner, 'attachToContainer') return sinon.spy(this.DockerRunner, 'attachToContainer')
}) })
describe('when the container exists', function() { describe('when the container exists', function () {
beforeEach(function() { beforeEach(function () {
this.container.inspect = sinon.stub().callsArgWith(0) this.container.inspect = sinon.stub().callsArgWith(0)
this.container.start = sinon.stub().yields() this.container.start = sinon.stub().yields()
@ -483,24 +483,24 @@ describe('DockerRunner', function() {
) )
}) })
it('should start the container with the given name', function() { it('should start the container with the given name', function () {
this.getContainer.calledWith(this.options.name).should.equal(true) this.getContainer.calledWith(this.options.name).should.equal(true)
return this.container.start.called.should.equal(true) return this.container.start.called.should.equal(true)
}) })
it('should not try to create the container', function() { it('should not try to create the container', function () {
return this.createContainer.called.should.equal(false) return this.createContainer.called.should.equal(false)
}) })
it('should attach to the container', function() { it('should attach to the container', function () {
return this.DockerRunner.attachToContainer.called.should.equal(true) return this.DockerRunner.attachToContainer.called.should.equal(true)
}) })
it('should call the callback', function() { it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
return it('should attach before the container starts', function() { return it('should attach before the container starts', function () {
return sinon.assert.callOrder( return sinon.assert.callOrder(
this.DockerRunner.attachToContainer, this.DockerRunner.attachToContainer,
this.container.start this.container.start
@ -508,8 +508,8 @@ describe('DockerRunner', function() {
}) })
}) })
describe('when the container does not exist', function() { describe('when the container does not exist', function () {
beforeEach(function() { beforeEach(function () {
const exists = false const exists = false
this.container.start = sinon.stub().yields() this.container.start = sinon.stub().yields()
this.container.inspect = sinon this.container.inspect = sinon
@ -523,20 +523,20 @@ describe('DockerRunner', function() {
) )
}) })
it('should create the container', function() { it('should create the container', function () {
return this.createContainer.calledWith(this.options).should.equal(true) return this.createContainer.calledWith(this.options).should.equal(true)
}) })
it('should call the callback and stream handler', function() { it('should call the callback and stream handler', function () {
this.attachStreamHandler.called.should.equal(true) this.attachStreamHandler.called.should.equal(true)
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
it('should attach to the container', function() { it('should attach to the container', function () {
return this.DockerRunner.attachToContainer.called.should.equal(true) return this.DockerRunner.attachToContainer.called.should.equal(true)
}) })
return it('should attach before the container starts', function() { return it('should attach before the container starts', function () {
return sinon.assert.callOrder( return sinon.assert.callOrder(
this.DockerRunner.attachToContainer, this.DockerRunner.attachToContainer,
this.container.start this.container.start
@ -544,8 +544,8 @@ describe('DockerRunner', function() {
}) })
}) })
describe('when the container is already running', function() { describe('when the container is already running', function () {
beforeEach(function() { beforeEach(function () {
const error = new Error( const error = new Error(
`HTTP code is 304 which indicates error: server error - start: Cannot start container ${this.name}: The container MOCKID is already running.` `HTTP code is 304 which indicates error: server error - start: Cannot start container ${this.name}: The container MOCKID is already running.`
) )
@ -560,18 +560,18 @@ describe('DockerRunner', function() {
) )
}) })
it('should not try to create the container', function() { it('should not try to create the container', function () {
return this.createContainer.called.should.equal(false) return this.createContainer.called.should.equal(false)
}) })
return it('should call the callback and stream handler without an error', function() { return it('should call the callback and stream handler without an error', function () {
this.attachStreamHandler.called.should.equal(true) this.attachStreamHandler.called.should.equal(true)
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
describe('when a volume does not exist', function() { describe('when a volume does not exist', function () {
beforeEach(function() { beforeEach(function () {
this.fs.stat = sinon.stub().yields(new Error('no such path')) this.fs.stat = sinon.stub().yields(new Error('no such path'))
return this.DockerRunner.startContainer( return this.DockerRunner.startContainer(
this.options, this.options,
@ -581,17 +581,17 @@ describe('DockerRunner', function() {
) )
}) })
it('should not try to create the container', function() { it('should not try to create the container', function () {
return this.createContainer.called.should.equal(false) return this.createContainer.called.should.equal(false)
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
}) })
}) })
describe('when a volume exists but is not a directory', function() { describe('when a volume exists but is not a directory', function () {
beforeEach(function() { beforeEach(function () {
this.fs.stat = sinon.stub().yields(null, { this.fs.stat = sinon.stub().yields(null, {
isDirectory() { isDirectory() {
return false return false
@ -605,17 +605,17 @@ describe('DockerRunner', function() {
) )
}) })
it('should not try to create the container', function() { it('should not try to create the container', function () {
return this.createContainer.called.should.equal(false) return this.createContainer.called.should.equal(false)
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
}) })
}) })
describe('when a volume does not exist, but sibling-containers are used', function() { describe('when a volume does not exist, but sibling-containers are used', function () {
beforeEach(function() { beforeEach(function () {
this.fs.stat = sinon.stub().yields(new Error('no such path')) this.fs.stat = sinon.stub().yields(new Error('no such path'))
this.Settings.path.sandboxedCompilesHostDir = '/some/path' this.Settings.path.sandboxedCompilesHostDir = '/some/path'
this.container.start = sinon.stub().yields() this.container.start = sinon.stub().yields()
@ -626,30 +626,30 @@ describe('DockerRunner', function() {
) )
}) })
afterEach(function() { afterEach(function () {
return delete this.Settings.path.sandboxedCompilesHostDir return delete this.Settings.path.sandboxedCompilesHostDir
}) })
it('should start the container with the given name', function() { it('should start the container with the given name', function () {
this.getContainer.calledWith(this.options.name).should.equal(true) this.getContainer.calledWith(this.options.name).should.equal(true)
return this.container.start.called.should.equal(true) return this.container.start.called.should.equal(true)
}) })
it('should not try to create the container', function() { it('should not try to create the container', function () {
return this.createContainer.called.should.equal(false) return this.createContainer.called.should.equal(false)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
this.callback.called.should.equal(true) this.callback.called.should.equal(true)
return this.callback.calledWith(new Error()).should.equal(false) return this.callback.calledWith(new Error()).should.equal(false)
}) })
}) })
return describe('when the container tries to be created, but already has been (race condition)', function() {}) return describe('when the container tries to be created, but already has been (race condition)', function () {})
}) })
describe('waitForContainer', function() { describe('waitForContainer', function () {
beforeEach(function() { beforeEach(function () {
this.containerId = 'container-id' this.containerId = 'container-id'
this.timeout = 5000 this.timeout = 5000
this.container.wait = sinon this.container.wait = sinon
@ -658,8 +658,8 @@ describe('DockerRunner', function() {
return (this.container.kill = sinon.stub().yields()) return (this.container.kill = sinon.stub().yields())
}) })
describe('when the container returns in time', function() { describe('when the container returns in time', function () {
beforeEach(function() { beforeEach(function () {
return this.DockerRunner.waitForContainer( return this.DockerRunner.waitForContainer(
this.containerId, this.containerId,
this.timeout, this.timeout,
@ -667,23 +667,23 @@ describe('DockerRunner', function() {
) )
}) })
it('should wait for the container', function() { it('should wait for the container', function () {
this.getContainer.calledWith(this.containerId).should.equal(true) this.getContainer.calledWith(this.containerId).should.equal(true)
return this.container.wait.called.should.equal(true) return this.container.wait.called.should.equal(true)
}) })
return it('should call the callback with the exit', function() { return it('should call the callback with the exit', function () {
return this.callback return this.callback
.calledWith(null, this.statusCode) .calledWith(null, this.statusCode)
.should.equal(true) .should.equal(true)
}) })
}) })
return describe('when the container does not return before the timeout', function() { return describe('when the container does not return before the timeout', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.container.wait = function(callback) { this.container.wait = function (callback) {
if (callback == null) { if (callback == null) {
callback = function(error, exitCode) {} callback = function (error, exitCode) {}
} }
return setTimeout(() => callback(null, { StatusCode: 42 }), 100) return setTimeout(() => callback(null, { StatusCode: 42 }), 100)
} }
@ -698,12 +698,12 @@ describe('DockerRunner', function() {
) )
}) })
it('should call kill on the container', function() { it('should call kill on the container', function () {
this.getContainer.calledWith(this.containerId).should.equal(true) this.getContainer.calledWith(this.containerId).should.equal(true)
return this.container.kill.called.should.equal(true) return this.container.kill.called.should.equal(true)
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
const errorObj = this.callback.args[0][0] const errorObj = this.callback.args[0][0]
@ -713,8 +713,8 @@ describe('DockerRunner', function() {
}) })
}) })
describe('destroyOldContainers', function() { describe('destroyOldContainers', function () {
beforeEach(function(done) { beforeEach(function (done) {
const oneHourInSeconds = 60 * 60 const oneHourInSeconds = 60 * 60
const oneHourInMilliseconds = oneHourInSeconds * 1000 const oneHourInMilliseconds = oneHourInSeconds * 1000
const nowInSeconds = Date.now() / 1000 const nowInSeconds = Date.now() / 1000
@ -738,42 +738,42 @@ describe('DockerRunner', function() {
this.DockerRunner.MAX_CONTAINER_AGE = oneHourInMilliseconds this.DockerRunner.MAX_CONTAINER_AGE = oneHourInMilliseconds
this.listContainers.callsArgWith(1, null, this.containers) this.listContainers.callsArgWith(1, null, this.containers)
this.DockerRunner.destroyContainer = sinon.stub().callsArg(3) this.DockerRunner.destroyContainer = sinon.stub().callsArg(3)
return this.DockerRunner.destroyOldContainers(error => { return this.DockerRunner.destroyOldContainers((error) => {
this.callback(error) this.callback(error)
return done() return done()
}) })
}) })
it('should list all containers', function() { it('should list all containers', function () {
return this.listContainers.calledWith({ all: true }).should.equal(true) return this.listContainers.calledWith({ all: true }).should.equal(true)
}) })
it('should destroy old containers', function() { it('should destroy old containers', function () {
this.DockerRunner.destroyContainer.callCount.should.equal(1) this.DockerRunner.destroyContainer.callCount.should.equal(1)
return this.DockerRunner.destroyContainer return this.DockerRunner.destroyContainer
.calledWith('project-old-container-name', 'old-container-id') .calledWith('project-old-container-name', 'old-container-id')
.should.equal(true) .should.equal(true)
}) })
it('should not destroy new containers', function() { it('should not destroy new containers', function () {
return this.DockerRunner.destroyContainer return this.DockerRunner.destroyContainer
.calledWith('project-new-container-name', 'new-container-id') .calledWith('project-new-container-name', 'new-container-id')
.should.equal(false) .should.equal(false)
}) })
it('should not destroy non-project containers', function() { it('should not destroy non-project containers', function () {
return this.DockerRunner.destroyContainer return this.DockerRunner.destroyContainer
.calledWith('totally-not-a-project-container', 'some-random-id') .calledWith('totally-not-a-project-container', 'some-random-id')
.should.equal(false) .should.equal(false)
}) })
return it('should callback the callback', function() { return it('should callback the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
describe('_destroyContainer', function() { describe('_destroyContainer', function () {
beforeEach(function() { beforeEach(function () {
this.containerId = 'some_id' this.containerId = 'some_id'
this.fakeContainer = { remove: sinon.stub().callsArgWith(1, null) } this.fakeContainer = { remove: sinon.stub().callsArgWith(1, null) }
return (this.Docker.prototype.getContainer = sinon return (this.Docker.prototype.getContainer = sinon
@ -781,11 +781,11 @@ describe('DockerRunner', function() {
.returns(this.fakeContainer)) .returns(this.fakeContainer))
}) })
it('should get the container', function(done) { it('should get the container', function (done) {
return this.DockerRunner._destroyContainer( return this.DockerRunner._destroyContainer(
this.containerId, this.containerId,
false, false,
err => { (err) => {
this.Docker.prototype.getContainer.callCount.should.equal(1) this.Docker.prototype.getContainer.callCount.should.equal(1)
this.Docker.prototype.getContainer this.Docker.prototype.getContainer
.calledWith(this.containerId) .calledWith(this.containerId)
@ -795,11 +795,11 @@ describe('DockerRunner', function() {
) )
}) })
it('should try to force-destroy the container when shouldForce=true', function(done) { it('should try to force-destroy the container when shouldForce=true', function (done) {
return this.DockerRunner._destroyContainer( return this.DockerRunner._destroyContainer(
this.containerId, this.containerId,
true, true,
err => { (err) => {
this.fakeContainer.remove.callCount.should.equal(1) this.fakeContainer.remove.callCount.should.equal(1)
this.fakeContainer.remove this.fakeContainer.remove
.calledWith({ force: true }) .calledWith({ force: true })
@ -809,11 +809,11 @@ describe('DockerRunner', function() {
) )
}) })
it('should not try to force-destroy the container when shouldForce=false', function(done) { it('should not try to force-destroy the container when shouldForce=false', function (done) {
return this.DockerRunner._destroyContainer( return this.DockerRunner._destroyContainer(
this.containerId, this.containerId,
false, false,
err => { (err) => {
this.fakeContainer.remove.callCount.should.equal(1) this.fakeContainer.remove.callCount.should.equal(1)
this.fakeContainer.remove this.fakeContainer.remove
.calledWith({ force: false }) .calledWith({ force: false })
@ -823,19 +823,19 @@ describe('DockerRunner', function() {
) )
}) })
it('should not produce an error', function(done) { it('should not produce an error', function (done) {
return this.DockerRunner._destroyContainer( return this.DockerRunner._destroyContainer(
this.containerId, this.containerId,
false, false,
err => { (err) => {
expect(err).to.equal(null) expect(err).to.equal(null)
return done() return done()
} }
) )
}) })
describe('when the container is already gone', function() { describe('when the container is already gone', function () {
beforeEach(function() { beforeEach(function () {
this.fakeError = new Error('woops') this.fakeError = new Error('woops')
this.fakeError.statusCode = 404 this.fakeError.statusCode = 404
this.fakeContainer = { this.fakeContainer = {
@ -846,11 +846,11 @@ describe('DockerRunner', function() {
.returns(this.fakeContainer)) .returns(this.fakeContainer))
}) })
return it('should not produce an error', function(done) { return it('should not produce an error', function (done) {
return this.DockerRunner._destroyContainer( return this.DockerRunner._destroyContainer(
this.containerId, this.containerId,
false, false,
err => { (err) => {
expect(err).to.equal(null) expect(err).to.equal(null)
return done() return done()
} }
@ -858,8 +858,8 @@ describe('DockerRunner', function() {
}) })
}) })
return describe('when container.destroy produces an error', function(done) { return describe('when container.destroy produces an error', function (done) {
beforeEach(function() { beforeEach(function () {
this.fakeError = new Error('woops') this.fakeError = new Error('woops')
this.fakeError.statusCode = 500 this.fakeError.statusCode = 500
this.fakeContainer = { this.fakeContainer = {
@ -870,11 +870,11 @@ describe('DockerRunner', function() {
.returns(this.fakeContainer)) .returns(this.fakeContainer))
}) })
return it('should produce an error', function(done) { return it('should produce an error', function (done) {
return this.DockerRunner._destroyContainer( return this.DockerRunner._destroyContainer(
this.containerId, this.containerId,
false, false,
err => { (err) => {
expect(err).to.not.equal(null) expect(err).to.not.equal(null)
expect(err).to.equal(this.fakeError) expect(err).to.equal(this.fakeError)
return done() return done()
@ -884,8 +884,8 @@ describe('DockerRunner', function() {
}) })
}) })
return describe('kill', function() { return describe('kill', function () {
beforeEach(function() { beforeEach(function () {
this.containerId = 'some_id' this.containerId = 'some_id'
this.fakeContainer = { kill: sinon.stub().callsArgWith(0, null) } this.fakeContainer = { kill: sinon.stub().callsArgWith(0, null) }
return (this.Docker.prototype.getContainer = sinon return (this.Docker.prototype.getContainer = sinon
@ -893,8 +893,8 @@ describe('DockerRunner', function() {
.returns(this.fakeContainer)) .returns(this.fakeContainer))
}) })
it('should get the container', function(done) { it('should get the container', function (done) {
return this.DockerRunner.kill(this.containerId, err => { return this.DockerRunner.kill(this.containerId, (err) => {
this.Docker.prototype.getContainer.callCount.should.equal(1) this.Docker.prototype.getContainer.callCount.should.equal(1)
this.Docker.prototype.getContainer this.Docker.prototype.getContainer
.calledWith(this.containerId) .calledWith(this.containerId)
@ -903,22 +903,22 @@ describe('DockerRunner', function() {
}) })
}) })
it('should try to force-destroy the container', function(done) { it('should try to force-destroy the container', function (done) {
return this.DockerRunner.kill(this.containerId, err => { return this.DockerRunner.kill(this.containerId, (err) => {
this.fakeContainer.kill.callCount.should.equal(1) this.fakeContainer.kill.callCount.should.equal(1)
return done() return done()
}) })
}) })
it('should not produce an error', function(done) { it('should not produce an error', function (done) {
return this.DockerRunner.kill(this.containerId, err => { return this.DockerRunner.kill(this.containerId, (err) => {
expect(err).to.equal(undefined) expect(err).to.equal(undefined)
return done() return done()
}) })
}) })
describe('when the container is not actually running', function() { describe('when the container is not actually running', function () {
beforeEach(function() { beforeEach(function () {
this.fakeError = new Error('woops') this.fakeError = new Error('woops')
this.fakeError.statusCode = 500 this.fakeError.statusCode = 500
this.fakeError.message = this.fakeError.message =
@ -931,16 +931,16 @@ describe('DockerRunner', function() {
.returns(this.fakeContainer)) .returns(this.fakeContainer))
}) })
return it('should not produce an error', function(done) { return it('should not produce an error', function (done) {
return this.DockerRunner.kill(this.containerId, err => { return this.DockerRunner.kill(this.containerId, (err) => {
expect(err).to.equal(undefined) expect(err).to.equal(undefined)
return done() return done()
}) })
}) })
}) })
return describe('when container.kill produces a legitimate error', function(done) { return describe('when container.kill produces a legitimate error', function (done) {
beforeEach(function() { beforeEach(function () {
this.fakeError = new Error('woops') this.fakeError = new Error('woops')
this.fakeError.statusCode = 500 this.fakeError.statusCode = 500
this.fakeError.message = 'Totally legitimate reason to throw an error' this.fakeError.message = 'Totally legitimate reason to throw an error'
@ -952,8 +952,8 @@ describe('DockerRunner', function() {
.returns(this.fakeContainer)) .returns(this.fakeContainer))
}) })
return it('should produce an error', function(done) { return it('should produce an error', function (done) {
return this.DockerRunner.kill(this.containerId, err => { return this.DockerRunner.kill(this.containerId, (err) => {
expect(err).to.not.equal(undefined) expect(err).to.not.equal(undefined)
expect(err).to.equal(this.fakeError) expect(err).to.equal(this.fakeError)
return done() return done()

View file

@ -16,8 +16,8 @@ const modulePath = require('path').join(
'../../../app/js/DraftModeManager' '../../../app/js/DraftModeManager'
) )
describe('DraftModeManager', function() { describe('DraftModeManager', function () {
beforeEach(function() { beforeEach(function () {
return (this.DraftModeManager = SandboxedModule.require(modulePath, { return (this.DraftModeManager = SandboxedModule.require(modulePath, {
requires: { requires: {
fs: (this.fs = {}), fs: (this.fs = {}),
@ -26,8 +26,8 @@ describe('DraftModeManager', function() {
})) }))
}) })
describe('_injectDraftOption', function() { describe('_injectDraftOption', function () {
it('should add draft option into documentclass with existing options', function() { it('should add draft option into documentclass with existing options', function () {
return this.DraftModeManager._injectDraftOption(`\ return this.DraftModeManager._injectDraftOption(`\
\\documentclass[a4paper,foo=bar]{article}\ \\documentclass[a4paper,foo=bar]{article}\
`).should.equal(`\ `).should.equal(`\
@ -35,7 +35,7 @@ describe('DraftModeManager', function() {
`) `)
}) })
return it('should add draft option into documentclass with no options', function() { return it('should add draft option into documentclass with no options', function () {
return this.DraftModeManager._injectDraftOption(`\ return this.DraftModeManager._injectDraftOption(`\
\\documentclass{article}\ \\documentclass{article}\
`).should.equal(`\ `).should.equal(`\
@ -44,8 +44,8 @@ describe('DraftModeManager', function() {
}) })
}) })
return describe('injectDraftMode', function() { return describe('injectDraftMode', function () {
beforeEach(function() { beforeEach(function () {
this.filename = '/mock/filename.tex' this.filename = '/mock/filename.tex'
this.callback = sinon.stub() this.callback = sinon.stub()
const content = `\ const content = `\
@ -59,13 +59,13 @@ Hello world
return this.DraftModeManager.injectDraftMode(this.filename, this.callback) return this.DraftModeManager.injectDraftMode(this.filename, this.callback)
}) })
it('should read the file', function() { it('should read the file', function () {
return this.fs.readFile return this.fs.readFile
.calledWith(this.filename, 'utf8') .calledWith(this.filename, 'utf8')
.should.equal(true) .should.equal(true)
}) })
it('should write the modified file', function() { it('should write the modified file', function () {
return this.fs.writeFile return this.fs.writeFile
.calledWith( .calledWith(
this.filename, this.filename,
@ -79,7 +79,7 @@ Hello world
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })

View file

@ -18,8 +18,8 @@ const modulePath = require('path').join(
) )
const Path = require('path') const Path = require('path')
describe('LatexRunner', function() { describe('LatexRunner', function () {
beforeEach(function() { beforeEach(function () {
let Timer let Timer
this.LatexRunner = SandboxedModule.require(modulePath, { this.LatexRunner = SandboxedModule.require(modulePath, {
requires: { requires: {
@ -54,16 +54,16 @@ describe('LatexRunner', function() {
return (this.env = { foo: '123' }) return (this.env = { foo: '123' })
}) })
return describe('runLatex', function() { return describe('runLatex', function () {
beforeEach(function() { beforeEach(function () {
return (this.CommandRunner.run = sinon.stub().callsArgWith(7, null, { return (this.CommandRunner.run = sinon.stub().callsArgWith(7, null, {
stdout: 'this is stdout', stdout: 'this is stdout',
stderr: 'this is stderr' stderr: 'this is stderr'
})) }))
}) })
describe('normally', function() { describe('normally', function () {
beforeEach(function() { beforeEach(function () {
return this.LatexRunner.runLatex( return this.LatexRunner.runLatex(
this.project_id, this.project_id,
{ {
@ -79,7 +79,7 @@ describe('LatexRunner', function() {
) )
}) })
it('should run the latex command', function() { it('should run the latex command', function () {
return this.CommandRunner.run return this.CommandRunner.run
.calledWith( .calledWith(
this.project_id, this.project_id,
@ -93,7 +93,7 @@ describe('LatexRunner', function() {
.should.equal(true) .should.equal(true)
}) })
it('should record the stdout and stderr', function() { it('should record the stdout and stderr', function () {
this.fs.writeFile this.fs.writeFile
.calledWith(this.directory + '/' + 'output.stdout', 'this is stdout') .calledWith(this.directory + '/' + 'output.stdout', 'this is stdout')
.should.equal(true) .should.equal(true)
@ -103,8 +103,8 @@ describe('LatexRunner', function() {
}) })
}) })
describe('with an .Rtex main file', function() { describe('with an .Rtex main file', function () {
beforeEach(function() { beforeEach(function () {
return this.LatexRunner.runLatex( return this.LatexRunner.runLatex(
this.project_id, this.project_id,
{ {
@ -118,15 +118,15 @@ describe('LatexRunner', function() {
) )
}) })
return it('should run the latex command on the equivalent .tex file', function() { return it('should run the latex command on the equivalent .tex file', function () {
const command = this.CommandRunner.run.args[0][1] const command = this.CommandRunner.run.args[0][1]
const mainFile = command.slice(-1)[0] const mainFile = command.slice(-1)[0]
return mainFile.should.equal('$COMPILE_DIR/main-file.tex') return mainFile.should.equal('$COMPILE_DIR/main-file.tex')
}) })
}) })
return describe('with a flags option', function() { return describe('with a flags option', function () {
beforeEach(function() { beforeEach(function () {
return this.LatexRunner.runLatex( return this.LatexRunner.runLatex(
this.project_id, this.project_id,
{ {
@ -141,10 +141,10 @@ describe('LatexRunner', function() {
) )
}) })
return it('should include the flags in the command', function() { return it('should include the flags in the command', function () {
const command = this.CommandRunner.run.args[0][1] const command = this.CommandRunner.run.args[0][1]
const flags = command.filter( const flags = command.filter(
arg => arg === '-file-line-error' || arg === '-halt-on-error' (arg) => arg === '-file-line-error' || arg === '-halt-on-error'
) )
flags.length.should.equal(2) flags.length.should.equal(2)
flags[0].should.equal('-file-line-error') flags[0].should.equal('-file-line-error')

View file

@ -19,8 +19,8 @@ const modulePath = require('path').join(
const Path = require('path') const Path = require('path')
const Errors = require('../../../app/js/Errors') const Errors = require('../../../app/js/Errors')
describe('DockerLockManager', function() { describe('DockerLockManager', function () {
beforeEach(function() { beforeEach(function () {
this.LockManager = SandboxedModule.require(modulePath, { this.LockManager = SandboxedModule.require(modulePath, {
requires: { requires: {
'settings-sharelatex': {}, 'settings-sharelatex': {},
@ -39,14 +39,14 @@ describe('DockerLockManager', function() {
return (this.lockFile = '/local/compile/directory/.project-lock') return (this.lockFile = '/local/compile/directory/.project-lock')
}) })
return describe('runWithLock', function() { return describe('runWithLock', function () {
beforeEach(function() { beforeEach(function () {
this.runner = sinon.stub().callsArgWith(0, null, 'foo', 'bar') this.runner = sinon.stub().callsArgWith(0, null, 'foo', 'bar')
return (this.callback = sinon.stub()) return (this.callback = sinon.stub())
}) })
describe('normally', function() { describe('normally', function () {
beforeEach(function() { beforeEach(function () {
this.Lockfile.lock = sinon.stub().callsArgWith(2, null) this.Lockfile.lock = sinon.stub().callsArgWith(2, null)
this.Lockfile.unlock = sinon.stub().callsArgWith(1, null) this.Lockfile.unlock = sinon.stub().callsArgWith(1, null)
return this.LockManager.runWithLock( return this.LockManager.runWithLock(
@ -56,19 +56,19 @@ describe('DockerLockManager', function() {
) )
}) })
it('should run the compile', function() { it('should run the compile', function () {
return this.runner.calledWith().should.equal(true) return this.runner.calledWith().should.equal(true)
}) })
return it('should call the callback with the response from the compile', function() { return it('should call the callback with the response from the compile', function () {
return this.callback return this.callback
.calledWithExactly(null, 'foo', 'bar') .calledWithExactly(null, 'foo', 'bar')
.should.equal(true) .should.equal(true)
}) })
}) })
return describe('when the project is locked', function() { return describe('when the project is locked', function () {
beforeEach(function() { beforeEach(function () {
this.error = new Error() this.error = new Error()
this.error.code = 'EEXIST' this.error.code = 'EEXIST'
this.Lockfile.lock = sinon.stub().callsArgWith(2, this.error) this.Lockfile.lock = sinon.stub().callsArgWith(2, this.error)
@ -80,11 +80,11 @@ describe('DockerLockManager', function() {
) )
}) })
it('should not run the compile', function() { it('should not run the compile', function () {
return this.runner.called.should.equal(false) return this.runner.called.should.equal(false)
}) })
it('should return an error', function() { it('should return an error', function () {
this.callback this.callback
.calledWithExactly(sinon.match(Errors.AlreadyCompilingError)) .calledWithExactly(sinon.match(Errors.AlreadyCompilingError))
.should.equal(true) .should.equal(true)

View file

@ -21,8 +21,8 @@ const path = require('path')
const { expect } = require('chai') const { expect } = require('chai')
const { EventEmitter } = require('events') const { EventEmitter } = require('events')
describe('OutputFileFinder', function() { describe('OutputFileFinder', function () {
beforeEach(function() { beforeEach(function () {
this.OutputFileFinder = SandboxedModule.require(modulePath, { this.OutputFileFinder = SandboxedModule.require(modulePath, {
requires: { requires: {
fs: (this.fs = {}), fs: (this.fs = {}),
@ -34,8 +34,8 @@ describe('OutputFileFinder', function() {
return (this.callback = sinon.stub()) return (this.callback = sinon.stub())
}) })
describe('findOutputFiles', function() { describe('findOutputFiles', function () {
beforeEach(function() { beforeEach(function () {
this.resource_path = 'resource/path.tex' this.resource_path = 'resource/path.tex'
this.output_paths = ['output.pdf', 'extra/file.tex'] this.output_paths = ['output.pdf', 'extra/file.tex']
this.all_paths = this.output_paths.concat([this.resource_path]) this.all_paths = this.output_paths.concat([this.resource_path])
@ -52,7 +52,7 @@ describe('OutputFileFinder', function() {
) )
}) })
return it('should only return the output files, not directories or resource paths', function() { return it('should only return the output files, not directories or resource paths', function () {
return expect(this.outputFiles).to.deep.equal([ return expect(this.outputFiles).to.deep.equal([
{ {
path: 'output.pdf', path: 'output.pdf',
@ -66,8 +66,8 @@ describe('OutputFileFinder', function() {
}) })
}) })
return describe('_getAllFiles', function() { return describe('_getAllFiles', function () {
beforeEach(function() { beforeEach(function () {
this.proc = new EventEmitter() this.proc = new EventEmitter()
this.proc.stdout = new EventEmitter() this.proc.stdout = new EventEmitter()
this.proc.stdout.setEncoding = sinon.stub().returns(this.proc.stdout) this.proc.stdout.setEncoding = sinon.stub().returns(this.proc.stdout)
@ -76,8 +76,8 @@ describe('OutputFileFinder', function() {
return this.OutputFileFinder._getAllFiles(this.directory, this.callback) return this.OutputFileFinder._getAllFiles(this.directory, this.callback)
}) })
describe('successfully', function() { describe('successfully', function () {
beforeEach(function() { beforeEach(function () {
this.proc.stdout.emit( this.proc.stdout.emit(
'data', 'data',
['/base/dir/main.tex', '/base/dir/chapters/chapter1.tex'].join('\n') + ['/base/dir/main.tex', '/base/dir/chapters/chapter1.tex'].join('\n') +
@ -86,19 +86,19 @@ describe('OutputFileFinder', function() {
return this.proc.emit('close', 0) return this.proc.emit('close', 0)
}) })
return it('should call the callback with the relative file paths', function() { return it('should call the callback with the relative file paths', function () {
return this.callback return this.callback
.calledWith(null, ['main.tex', 'chapters/chapter1.tex']) .calledWith(null, ['main.tex', 'chapters/chapter1.tex'])
.should.equal(true) .should.equal(true)
}) })
}) })
return describe("when the directory doesn't exist", function() { return describe("when the directory doesn't exist", function () {
beforeEach(function() { beforeEach(function () {
return this.proc.emit('close', 1) return this.proc.emit('close', 1)
}) })
return it('should call the callback with a blank array', function() { return it('should call the callback with a blank array', function () {
return this.callback.calledWith(null, []).should.equal(true) return this.callback.calledWith(null, []).should.equal(true)
}) })
}) })

View file

@ -21,8 +21,8 @@ const path = require('path')
const { expect } = require('chai') const { expect } = require('chai')
const { EventEmitter } = require('events') const { EventEmitter } = require('events')
describe('OutputFileOptimiser', function() { describe('OutputFileOptimiser', function () {
beforeEach(function() { beforeEach(function () {
this.OutputFileOptimiser = SandboxedModule.require(modulePath, { this.OutputFileOptimiser = SandboxedModule.require(modulePath, {
requires: { requires: {
fs: (this.fs = {}), fs: (this.fs = {}),
@ -37,14 +37,14 @@ describe('OutputFileOptimiser', function() {
return (this.callback = sinon.stub()) return (this.callback = sinon.stub())
}) })
describe('optimiseFile', function() { describe('optimiseFile', function () {
beforeEach(function() { beforeEach(function () {
this.src = './output.pdf' this.src = './output.pdf'
return (this.dst = './output.pdf') return (this.dst = './output.pdf')
}) })
describe('when the file is not a pdf file', function() { describe('when the file is not a pdf file', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.src = './output.log' this.src = './output.log'
this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon
.stub() .stub()
@ -55,21 +55,21 @@ describe('OutputFileOptimiser', function() {
return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done) return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done)
}) })
it('should not check if the file is optimised', function() { it('should not check if the file is optimised', function () {
return this.OutputFileOptimiser.checkIfPDFIsOptimised return this.OutputFileOptimiser.checkIfPDFIsOptimised
.calledWith(this.src) .calledWith(this.src)
.should.equal(false) .should.equal(false)
}) })
return it('should not optimise the file', function() { return it('should not optimise the file', function () {
return this.OutputFileOptimiser.optimisePDF return this.OutputFileOptimiser.optimisePDF
.calledWith(this.src, this.dst) .calledWith(this.src, this.dst)
.should.equal(false) .should.equal(false)
}) })
}) })
describe('when the pdf file is not optimised', function() { describe('when the pdf file is not optimised', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon
.stub() .stub()
.callsArgWith(1, null, false) .callsArgWith(1, null, false)
@ -79,21 +79,21 @@ describe('OutputFileOptimiser', function() {
return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done) return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done)
}) })
it('should check if the pdf is optimised', function() { it('should check if the pdf is optimised', function () {
return this.OutputFileOptimiser.checkIfPDFIsOptimised return this.OutputFileOptimiser.checkIfPDFIsOptimised
.calledWith(this.src) .calledWith(this.src)
.should.equal(true) .should.equal(true)
}) })
return it('should optimise the pdf', function() { return it('should optimise the pdf', function () {
return this.OutputFileOptimiser.optimisePDF return this.OutputFileOptimiser.optimisePDF
.calledWith(this.src, this.dst) .calledWith(this.src, this.dst)
.should.equal(true) .should.equal(true)
}) })
}) })
return describe('when the pdf file is optimised', function() { return describe('when the pdf file is optimised', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon
.stub() .stub()
.callsArgWith(1, null, true) .callsArgWith(1, null, true)
@ -103,13 +103,13 @@ describe('OutputFileOptimiser', function() {
return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done) return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done)
}) })
it('should check if the pdf is optimised', function() { it('should check if the pdf is optimised', function () {
return this.OutputFileOptimiser.checkIfPDFIsOptimised return this.OutputFileOptimiser.checkIfPDFIsOptimised
.calledWith(this.src) .calledWith(this.src)
.should.equal(true) .should.equal(true)
}) })
return it('should not optimise the pdf', function() { return it('should not optimise the pdf', function () {
return this.OutputFileOptimiser.optimisePDF return this.OutputFileOptimiser.optimisePDF
.calledWith(this.src, this.dst) .calledWith(this.src, this.dst)
.should.equal(false) .should.equal(false)
@ -117,8 +117,8 @@ describe('OutputFileOptimiser', function() {
}) })
}) })
return describe('checkIfPDFISOptimised', function() { return describe('checkIfPDFISOptimised', function () {
beforeEach(function() { beforeEach(function () {
this.callback = sinon.stub() this.callback = sinon.stub()
this.fd = 1234 this.fd = 1234
this.fs.open = sinon.stub().yields(null, this.fd) this.fs.open = sinon.stub().yields(null, this.fd)
@ -126,18 +126,15 @@ describe('OutputFileOptimiser', function() {
.stub() .stub()
.withArgs(this.fd) .withArgs(this.fd)
.yields(null, 100, Buffer.from('hello /Linearized 1')) .yields(null, 100, Buffer.from('hello /Linearized 1'))
this.fs.close = sinon this.fs.close = sinon.stub().withArgs(this.fd).yields(null)
.stub()
.withArgs(this.fd)
.yields(null)
return this.OutputFileOptimiser.checkIfPDFIsOptimised( return this.OutputFileOptimiser.checkIfPDFIsOptimised(
this.src, this.src,
this.callback this.callback
) )
}) })
describe('for a linearised file', function() { describe('for a linearised file', function () {
beforeEach(function() { beforeEach(function () {
this.fs.read = sinon this.fs.read = sinon
.stub() .stub()
.withArgs(this.fd) .withArgs(this.fd)
@ -148,25 +145,25 @@ describe('OutputFileOptimiser', function() {
) )
}) })
it('should open the file', function() { it('should open the file', function () {
return this.fs.open.calledWith(this.src, 'r').should.equal(true) return this.fs.open.calledWith(this.src, 'r').should.equal(true)
}) })
it('should read the header', function() { it('should read the header', function () {
return this.fs.read.calledWith(this.fd).should.equal(true) return this.fs.read.calledWith(this.fd).should.equal(true)
}) })
it('should close the file', function() { it('should close the file', function () {
return this.fs.close.calledWith(this.fd).should.equal(true) return this.fs.close.calledWith(this.fd).should.equal(true)
}) })
return it('should call the callback with a true result', function() { return it('should call the callback with a true result', function () {
return this.callback.calledWith(null, true).should.equal(true) return this.callback.calledWith(null, true).should.equal(true)
}) })
}) })
return describe('for an unlinearised file', function() { return describe('for an unlinearised file', function () {
beforeEach(function() { beforeEach(function () {
this.fs.read = sinon this.fs.read = sinon
.stub() .stub()
.withArgs(this.fd) .withArgs(this.fd)
@ -177,19 +174,19 @@ describe('OutputFileOptimiser', function() {
) )
}) })
it('should open the file', function() { it('should open the file', function () {
return this.fs.open.calledWith(this.src, 'r').should.equal(true) return this.fs.open.calledWith(this.src, 'r').should.equal(true)
}) })
it('should read the header', function() { it('should read the header', function () {
return this.fs.read.calledWith(this.fd).should.equal(true) return this.fs.read.calledWith(this.fd).should.equal(true)
}) })
it('should close the file', function() { it('should close the file', function () {
return this.fs.close.calledWith(this.fd).should.equal(true) return this.fs.close.calledWith(this.fd).should.equal(true)
}) })
return it('should call the callback with a false result', function() { return it('should call the callback with a false result', function () {
return this.callback.calledWith(null, false).should.equal(true) return this.callback.calledWith(null, false).should.equal(true)
}) })
}) })

View file

@ -21,8 +21,8 @@ const modulePath = require('path').join(
) )
const tk = require('timekeeper') const tk = require('timekeeper')
describe('ProjectPersistenceManager', function() { describe('ProjectPersistenceManager', function () {
beforeEach(function() { beforeEach(function () {
this.ProjectPersistenceManager = SandboxedModule.require(modulePath, { this.ProjectPersistenceManager = SandboxedModule.require(modulePath, {
requires: { requires: {
'./UrlCache': (this.UrlCache = {}), './UrlCache': (this.UrlCache = {}),
@ -44,8 +44,8 @@ describe('ProjectPersistenceManager', function() {
return (this.user_id = '1234') return (this.user_id = '1234')
}) })
describe('refreshExpiryTimeout', function() { describe('refreshExpiryTimeout', function () {
it('should leave expiry alone if plenty of disk', function(done) { it('should leave expiry alone if plenty of disk', function (done) {
this.diskusage.check.callsArgWith(1, null, { this.diskusage.check.callsArgWith(1, null, {
available: 40, available: 40,
total: 100 total: 100
@ -59,7 +59,7 @@ describe('ProjectPersistenceManager', function() {
}) })
}) })
it('should drop EXPIRY_TIMEOUT 10% if low disk usage', function(done) { it('should drop EXPIRY_TIMEOUT 10% if low disk usage', function (done) {
this.diskusage.check.callsArgWith(1, null, { this.diskusage.check.callsArgWith(1, null, {
available: 5, available: 5,
total: 100 total: 100
@ -71,7 +71,7 @@ describe('ProjectPersistenceManager', function() {
}) })
}) })
it('should not drop EXPIRY_TIMEOUT to below 50% of project_cache_length_ms', function(done) { it('should not drop EXPIRY_TIMEOUT to below 50% of project_cache_length_ms', function (done) {
this.diskusage.check.callsArgWith(1, null, { this.diskusage.check.callsArgWith(1, null, {
available: 5, available: 5,
total: 100 total: 100
@ -83,7 +83,7 @@ describe('ProjectPersistenceManager', function() {
}) })
}) })
it('should not modify EXPIRY_TIMEOUT if there is an error getting disk values', function(done) { it('should not modify EXPIRY_TIMEOUT if there is an error getting disk values', function (done) {
this.diskusage.check.callsArgWith(1, 'Error', { this.diskusage.check.callsArgWith(1, 'Error', {
available: 5, available: 5,
total: 100 total: 100
@ -95,8 +95,8 @@ describe('ProjectPersistenceManager', function() {
}) })
}) })
describe('clearExpiredProjects', function() { describe('clearExpiredProjects', function () {
beforeEach(function() { beforeEach(function () {
this.project_ids = ['project-id-1', 'project-id-2'] this.project_ids = ['project-id-1', 'project-id-2']
this.ProjectPersistenceManager._findExpiredProjectIds = sinon this.ProjectPersistenceManager._findExpiredProjectIds = sinon
.stub() .stub()
@ -108,21 +108,21 @@ describe('ProjectPersistenceManager', function() {
return this.ProjectPersistenceManager.clearExpiredProjects(this.callback) return this.ProjectPersistenceManager.clearExpiredProjects(this.callback)
}) })
it('should clear each expired project', function() { it('should clear each expired project', function () {
return Array.from(this.project_ids).map(project_id => return Array.from(this.project_ids).map((project_id) =>
this.ProjectPersistenceManager.clearProjectFromCache this.ProjectPersistenceManager.clearProjectFromCache
.calledWith(project_id) .calledWith(project_id)
.should.equal(true) .should.equal(true)
) )
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
return describe('clearProject', function() { return describe('clearProject', function () {
beforeEach(function() { beforeEach(function () {
this.ProjectPersistenceManager._clearProjectFromDatabase = sinon this.ProjectPersistenceManager._clearProjectFromDatabase = sinon
.stub() .stub()
.callsArg(1) .callsArg(1)
@ -135,25 +135,25 @@ describe('ProjectPersistenceManager', function() {
) )
}) })
it('should clear the project from the database', function() { it('should clear the project from the database', function () {
return this.ProjectPersistenceManager._clearProjectFromDatabase return this.ProjectPersistenceManager._clearProjectFromDatabase
.calledWith(this.project_id) .calledWith(this.project_id)
.should.equal(true) .should.equal(true)
}) })
it('should clear all the cached Urls for the project', function() { it('should clear all the cached Urls for the project', function () {
return this.UrlCache.clearProject return this.UrlCache.clearProject
.calledWith(this.project_id) .calledWith(this.project_id)
.should.equal(true) .should.equal(true)
}) })
it('should clear the project compile folder', function() { it('should clear the project compile folder', function () {
return this.CompileManager.clearProject return this.CompileManager.clearProject
.calledWith(this.project_id, this.user_id) .calledWith(this.project_id, this.user_id)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })

View file

@ -19,8 +19,8 @@ const modulePath = require('path').join(
) )
const tk = require('timekeeper') const tk = require('timekeeper')
describe('RequestParser', function() { describe('RequestParser', function () {
beforeEach(function() { beforeEach(function () {
tk.freeze() tk.freeze()
this.callback = sinon.stub() this.callback = sinon.stub()
this.validResource = { this.validResource = {
@ -46,41 +46,41 @@ describe('RequestParser', function() {
})) }))
}) })
afterEach(function() { afterEach(function () {
return tk.reset() return tk.reset()
}) })
describe('without a top level object', function() { describe('without a top level object', function () {
beforeEach(function() { beforeEach(function () {
return this.RequestParser.parse([], this.callback) return this.RequestParser.parse([], this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('top level object should have a compile attribute') .calledWith('top level object should have a compile attribute')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('without a compile attribute', function() { describe('without a compile attribute', function () {
beforeEach(function() { beforeEach(function () {
return this.RequestParser.parse({}, this.callback) return this.RequestParser.parse({}, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('top level object should have a compile attribute') .calledWith('top level object should have a compile attribute')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('without a valid compiler', function() { describe('without a valid compiler', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.options.compiler = 'not-a-compiler' this.validRequest.compile.options.compiler = 'not-a-compiler'
return this.RequestParser.parse(this.validRequest, this.callback) return this.RequestParser.parse(this.validRequest, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith( .calledWith(
'compiler attribute should be one of: pdflatex, latex, xelatex, lualatex' 'compiler attribute should be one of: pdflatex, latex, xelatex, lualatex'
@ -89,33 +89,33 @@ describe('RequestParser', function() {
}) })
}) })
describe('without a compiler specified', function() { describe('without a compiler specified', function () {
beforeEach(function() { beforeEach(function () {
delete this.validRequest.compile.options.compiler delete this.validRequest.compile.options.compiler
return this.RequestParser.parse(this.validRequest, (error, data) => { return this.RequestParser.parse(this.validRequest, (error, data) => {
this.data = data this.data = data
}) })
}) })
return it('should set the compiler to pdflatex by default', function() { return it('should set the compiler to pdflatex by default', function () {
return this.data.compiler.should.equal('pdflatex') return this.data.compiler.should.equal('pdflatex')
}) })
}) })
describe('with imageName set', function() { describe('with imageName set', function () {
beforeEach(function() { beforeEach(function () {
return this.RequestParser.parse(this.validRequest, (error, data) => { return this.RequestParser.parse(this.validRequest, (error, data) => {
this.data = data this.data = data
}) })
}) })
return it('should set the imageName', function() { return it('should set the imageName', function () {
return this.data.imageName.should.equal('basicImageName/here:2017-1') return this.data.imageName.should.equal('basicImageName/here:2017-1')
}) })
}) })
describe('when image restrictions are present', function() { describe('when image restrictions are present', function () {
beforeEach(function() { beforeEach(function () {
this.settings.clsi = { docker: {} } this.settings.clsi = { docker: {} }
this.settings.clsi.docker.allowedImages = [ this.settings.clsi.docker.allowedImages = [
'repo/name:tag1', 'repo/name:tag1',
@ -123,8 +123,8 @@ describe('RequestParser', function() {
] ]
}) })
describe('with imageName set to something invalid', function() { describe('with imageName set to something invalid', function () {
beforeEach(function() { beforeEach(function () {
const request = this.validRequest const request = this.validRequest
request.compile.options.imageName = 'something/different:latest' request.compile.options.imageName = 'something/different:latest'
this.RequestParser.parse(request, (error, data) => { this.RequestParser.parse(request, (error, data) => {
@ -133,15 +133,15 @@ describe('RequestParser', function() {
}) })
}) })
it('should throw an error for imageName', function() { it('should throw an error for imageName', function () {
expect(String(this.error)).to.include( expect(String(this.error)).to.include(
'imageName attribute should be one of' 'imageName attribute should be one of'
) )
}) })
}) })
describe('with imageName set to something valid', function() { describe('with imageName set to something valid', function () {
beforeEach(function() { beforeEach(function () {
const request = this.validRequest const request = this.validRequest
request.compile.options.imageName = 'repo/name:tag1' request.compile.options.imageName = 'repo/name:tag1'
this.RequestParser.parse(request, (error, data) => { this.RequestParser.parse(request, (error, data) => {
@ -150,54 +150,54 @@ describe('RequestParser', function() {
}) })
}) })
it('should set the imageName', function() { it('should set the imageName', function () {
this.data.imageName.should.equal('repo/name:tag1') this.data.imageName.should.equal('repo/name:tag1')
}) })
}) })
}) })
describe('with flags set', function() { describe('with flags set', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.options.flags = ['-file-line-error'] this.validRequest.compile.options.flags = ['-file-line-error']
return this.RequestParser.parse(this.validRequest, (error, data) => { return this.RequestParser.parse(this.validRequest, (error, data) => {
this.data = data this.data = data
}) })
}) })
return it('should set the flags attribute', function() { return it('should set the flags attribute', function () {
return expect(this.data.flags).to.deep.equal(['-file-line-error']) return expect(this.data.flags).to.deep.equal(['-file-line-error'])
}) })
}) })
describe('with flags not specified', function() { describe('with flags not specified', function () {
beforeEach(function() { beforeEach(function () {
return this.RequestParser.parse(this.validRequest, (error, data) => { return this.RequestParser.parse(this.validRequest, (error, data) => {
this.data = data this.data = data
}) })
}) })
return it('it should have an empty flags list', function() { return it('it should have an empty flags list', function () {
return expect(this.data.flags).to.deep.equal([]) return expect(this.data.flags).to.deep.equal([])
}) })
}) })
describe('without a timeout specified', function() { describe('without a timeout specified', function () {
beforeEach(function() { beforeEach(function () {
delete this.validRequest.compile.options.timeout delete this.validRequest.compile.options.timeout
return this.RequestParser.parse(this.validRequest, (error, data) => { return this.RequestParser.parse(this.validRequest, (error, data) => {
this.data = data this.data = data
}) })
}) })
return it('should set the timeout to MAX_TIMEOUT', function() { return it('should set the timeout to MAX_TIMEOUT', function () {
return this.data.timeout.should.equal( return this.data.timeout.should.equal(
this.RequestParser.MAX_TIMEOUT * 1000 this.RequestParser.MAX_TIMEOUT * 1000
) )
}) })
}) })
describe('with a timeout larger than the maximum', function() { describe('with a timeout larger than the maximum', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.options.timeout = this.validRequest.compile.options.timeout =
this.RequestParser.MAX_TIMEOUT + 1 this.RequestParser.MAX_TIMEOUT + 1
return this.RequestParser.parse(this.validRequest, (error, data) => { return this.RequestParser.parse(this.validRequest, (error, data) => {
@ -205,62 +205,62 @@ describe('RequestParser', function() {
}) })
}) })
return it('should set the timeout to MAX_TIMEOUT', function() { return it('should set the timeout to MAX_TIMEOUT', function () {
return this.data.timeout.should.equal( return this.data.timeout.should.equal(
this.RequestParser.MAX_TIMEOUT * 1000 this.RequestParser.MAX_TIMEOUT * 1000
) )
}) })
}) })
describe('with a timeout', function() { describe('with a timeout', function () {
beforeEach(function() { beforeEach(function () {
return this.RequestParser.parse(this.validRequest, (error, data) => { return this.RequestParser.parse(this.validRequest, (error, data) => {
this.data = data this.data = data
}) })
}) })
return it('should set the timeout (in milliseconds)', function() { return it('should set the timeout (in milliseconds)', function () {
return this.data.timeout.should.equal( return this.data.timeout.should.equal(
this.validRequest.compile.options.timeout * 1000 this.validRequest.compile.options.timeout * 1000
) )
}) })
}) })
describe('with a resource without a path', function() { describe('with a resource without a path', function () {
beforeEach(function() { beforeEach(function () {
delete this.validResource.path delete this.validResource.path
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
return this.RequestParser.parse(this.validRequest, this.callback) return this.RequestParser.parse(this.validRequest, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('all resources should have a path attribute') .calledWith('all resources should have a path attribute')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('with a resource with a path', function() { describe('with a resource with a path', function () {
beforeEach(function() { beforeEach(function () {
this.validResource.path = this.path = 'test.tex' this.validResource.path = this.path = 'test.tex'
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return the path in the parsed response', function() { return it('should return the path in the parsed response', function () {
return this.data.resources[0].path.should.equal(this.path) return this.data.resources[0].path.should.equal(this.path)
}) })
}) })
describe('with a resource with a malformed modified date', function() { describe('with a resource with a malformed modified date', function () {
beforeEach(function() { beforeEach(function () {
this.validResource.modified = 'not-a-date' this.validResource.modified = 'not-a-date'
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
return this.RequestParser.parse(this.validRequest, this.callback) return this.RequestParser.parse(this.validRequest, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith( .calledWith(
'resource modified date could not be understood: ' + 'resource modified date could not be understood: ' +
@ -270,8 +270,8 @@ describe('RequestParser', function() {
}) })
}) })
describe('with a resource with a valid date', function() { describe('with a resource with a valid date', function () {
beforeEach(function() { beforeEach(function () {
this.date = '12:00 01/02/03' this.date = '12:00 01/02/03'
this.validResource.modified = this.date this.validResource.modified = this.date
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
@ -279,7 +279,7 @@ describe('RequestParser', function() {
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return the date as a Javascript Date object', function() { return it('should return the date as a Javascript Date object', function () {
;(this.data.resources[0].modified instanceof Date).should.equal(true) ;(this.data.resources[0].modified instanceof Date).should.equal(true)
return this.data.resources[0].modified return this.data.resources[0].modified
.getTime() .getTime()
@ -287,15 +287,15 @@ describe('RequestParser', function() {
}) })
}) })
describe('with a resource without either a content or URL attribute', function() { describe('with a resource without either a content or URL attribute', function () {
beforeEach(function() { beforeEach(function () {
delete this.validResource.url delete this.validResource.url
delete this.validResource.content delete this.validResource.content
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
return this.RequestParser.parse(this.validRequest, this.callback) return this.RequestParser.parse(this.validRequest, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith( .calledWith(
'all resources should have either a url or content attribute' 'all resources should have either a url or content attribute'
@ -304,99 +304,99 @@ describe('RequestParser', function() {
}) })
}) })
describe('with a resource where the content is not a string', function() { describe('with a resource where the content is not a string', function () {
beforeEach(function() { beforeEach(function () {
this.validResource.content = [] this.validResource.content = []
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
return this.RequestParser.parse(this.validRequest, this.callback) return this.RequestParser.parse(this.validRequest, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('content attribute should be a string') .calledWith('content attribute should be a string')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('with a resource where the url is not a string', function() { describe('with a resource where the url is not a string', function () {
beforeEach(function() { beforeEach(function () {
this.validResource.url = [] this.validResource.url = []
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
return this.RequestParser.parse(this.validRequest, this.callback) return this.RequestParser.parse(this.validRequest, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('url attribute should be a string') .calledWith('url attribute should be a string')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('with a resource with a url', function() { describe('with a resource with a url', function () {
beforeEach(function() { beforeEach(function () {
this.validResource.url = this.url = 'www.example.com' this.validResource.url = this.url = 'www.example.com'
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return the url in the parsed response', function() { return it('should return the url in the parsed response', function () {
return this.data.resources[0].url.should.equal(this.url) return this.data.resources[0].url.should.equal(this.url)
}) })
}) })
describe('with a resource with a content attribute', function() { describe('with a resource with a content attribute', function () {
beforeEach(function() { beforeEach(function () {
this.validResource.content = this.content = 'Hello world' this.validResource.content = this.content = 'Hello world'
this.validRequest.compile.resources.push(this.validResource) this.validRequest.compile.resources.push(this.validResource)
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return the content in the parsed response', function() { return it('should return the content in the parsed response', function () {
return this.data.resources[0].content.should.equal(this.content) return this.data.resources[0].content.should.equal(this.content)
}) })
}) })
describe('without a root resource path', function() { describe('without a root resource path', function () {
beforeEach(function() { beforeEach(function () {
delete this.validRequest.compile.rootResourcePath delete this.validRequest.compile.rootResourcePath
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it("should set the root resource path to 'main.tex' by default", function() { return it("should set the root resource path to 'main.tex' by default", function () {
return this.data.rootResourcePath.should.equal('main.tex') return this.data.rootResourcePath.should.equal('main.tex')
}) })
}) })
describe('with a root resource path', function() { describe('with a root resource path', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.rootResourcePath = this.path = 'test.tex' this.validRequest.compile.rootResourcePath = this.path = 'test.tex'
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return the root resource path in the parsed response', function() { return it('should return the root resource path in the parsed response', function () {
return this.data.rootResourcePath.should.equal(this.path) return this.data.rootResourcePath.should.equal(this.path)
}) })
}) })
describe('with a root resource path that is not a string', function() { describe('with a root resource path that is not a string', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.rootResourcePath = [] this.validRequest.compile.rootResourcePath = []
return this.RequestParser.parse(this.validRequest, this.callback) return this.RequestParser.parse(this.validRequest, this.callback)
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('rootResourcePath attribute should be a string') .calledWith('rootResourcePath attribute should be a string')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('with a root resource path that needs escaping', function() { describe('with a root resource path that needs escaping', function () {
beforeEach(function() { beforeEach(function () {
this.badPath = '`rm -rf foo`.tex' this.badPath = '`rm -rf foo`.tex'
this.goodPath = 'rm -rf foo.tex' this.goodPath = 'rm -rf foo.tex'
this.validRequest.compile.rootResourcePath = this.badPath this.validRequest.compile.rootResourcePath = this.badPath
@ -409,51 +409,51 @@ describe('RequestParser', function() {
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
it('should return the escaped resource', function() { it('should return the escaped resource', function () {
return this.data.rootResourcePath.should.equal(this.goodPath) return this.data.rootResourcePath.should.equal(this.goodPath)
}) })
return it('should also escape the resource path', function() { return it('should also escape the resource path', function () {
return this.data.resources[0].path.should.equal(this.goodPath) return this.data.resources[0].path.should.equal(this.goodPath)
}) })
}) })
describe('with a root resource path that has a relative path', function() { describe('with a root resource path that has a relative path', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.rootResourcePath = 'foo/../../bar.tex' this.validRequest.compile.rootResourcePath = 'foo/../../bar.tex'
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('relative path in root resource') .calledWith('relative path in root resource')
.should.equal(true) .should.equal(true)
}) })
}) })
describe('with a root resource path that has unescaped + relative path', function() { describe('with a root resource path that has unescaped + relative path', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.rootResourcePath = 'foo/#../bar.tex' this.validRequest.compile.rootResourcePath = 'foo/#../bar.tex'
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('relative path in root resource') .calledWith('relative path in root resource')
.should.equal(true) .should.equal(true)
}) })
}) })
return describe('with an unknown syncType', function() { return describe('with an unknown syncType', function () {
beforeEach(function() { beforeEach(function () {
this.validRequest.compile.options.syncType = 'unexpected' this.validRequest.compile.options.syncType = 'unexpected'
this.RequestParser.parse(this.validRequest, this.callback) this.RequestParser.parse(this.validRequest, this.callback)
return (this.data = this.callback.args[0][1]) return (this.data = this.callback.args[0][1])
}) })
return it('should return an error', function() { return it('should return an error', function () {
return this.callback return this.callback
.calledWith('syncType attribute should be one of: full, incremental') .calledWith('syncType attribute should be one of: full, incremental')
.should.equal(true) .should.equal(true)

View file

@ -20,8 +20,8 @@ const modulePath = require('path').join(
const Path = require('path') const Path = require('path')
const Errors = require('../../../app/js/Errors') const Errors = require('../../../app/js/Errors')
describe('ResourceStateManager', function() { describe('ResourceStateManager', function () {
beforeEach(function() { beforeEach(function () {
this.ResourceStateManager = SandboxedModule.require(modulePath, { this.ResourceStateManager = SandboxedModule.require(modulePath, {
singleOnly: true, singleOnly: true,
requires: { requires: {
@ -42,13 +42,13 @@ describe('ResourceStateManager', function() {
return (this.callback = sinon.stub()) return (this.callback = sinon.stub())
}) })
describe('saveProjectState', function() { describe('saveProjectState', function () {
beforeEach(function() { beforeEach(function () {
return (this.fs.writeFile = sinon.stub().callsArg(2)) return (this.fs.writeFile = sinon.stub().callsArg(2))
}) })
describe('when the state is specified', function() { describe('when the state is specified', function () {
beforeEach(function() { beforeEach(function () {
return this.ResourceStateManager.saveProjectState( return this.ResourceStateManager.saveProjectState(
this.state, this.state,
this.resources, this.resources,
@ -57,19 +57,19 @@ describe('ResourceStateManager', function() {
) )
}) })
it('should write the resource list to disk', function() { it('should write the resource list to disk', function () {
return this.fs.writeFile return this.fs.writeFile
.calledWith(this.resourceFileName, this.resourceFileContents) .calledWith(this.resourceFileName, this.resourceFileContents)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
return describe('when the state is undefined', function() { return describe('when the state is undefined', function () {
beforeEach(function() { beforeEach(function () {
this.state = undefined this.state = undefined
this.fs.unlink = sinon.stub().callsArg(1) this.fs.unlink = sinon.stub().callsArg(1)
return this.ResourceStateManager.saveProjectState( return this.ResourceStateManager.saveProjectState(
@ -80,25 +80,25 @@ describe('ResourceStateManager', function() {
) )
}) })
it('should unlink the resource file', function() { it('should unlink the resource file', function () {
return this.fs.unlink return this.fs.unlink
.calledWith(this.resourceFileName) .calledWith(this.resourceFileName)
.should.equal(true) .should.equal(true)
}) })
it('should not write the resource list to disk', function() { it('should not write the resource list to disk', function () {
return this.fs.writeFile.called.should.equal(false) return this.fs.writeFile.called.should.equal(false)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
}) })
describe('checkProjectStateMatches', function() { describe('checkProjectStateMatches', function () {
describe('when the state matches', function() { describe('when the state matches', function () {
beforeEach(function() { beforeEach(function () {
this.SafeReader.readFile = sinon this.SafeReader.readFile = sinon
.stub() .stub()
.callsArgWith(3, null, this.resourceFileContents) .callsArgWith(3, null, this.resourceFileContents)
@ -109,21 +109,21 @@ describe('ResourceStateManager', function() {
) )
}) })
it('should read the resource file', function() { it('should read the resource file', function () {
return this.SafeReader.readFile return this.SafeReader.readFile
.calledWith(this.resourceFileName) .calledWith(this.resourceFileName)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with the results', function() { return it('should call the callback with the results', function () {
return this.callback return this.callback
.calledWithMatch(null, this.resources) .calledWithMatch(null, this.resources)
.should.equal(true) .should.equal(true)
}) })
}) })
return describe('when the state does not match', function() { return describe('when the state does not match', function () {
beforeEach(function() { beforeEach(function () {
this.SafeReader.readFile = sinon this.SafeReader.readFile = sinon
.stub() .stub()
.callsArgWith(3, null, this.resourceFileContents) .callsArgWith(3, null, this.resourceFileContents)
@ -134,7 +134,7 @@ describe('ResourceStateManager', function() {
) )
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
this.callback this.callback
.calledWith(sinon.match(Errors.FilesOutOfSyncError)) .calledWith(sinon.match(Errors.FilesOutOfSyncError))
.should.equal(true) .should.equal(true)
@ -145,9 +145,9 @@ describe('ResourceStateManager', function() {
}) })
}) })
return describe('checkResourceFiles', function() { return describe('checkResourceFiles', function () {
describe('when all the files are present', function() { describe('when all the files are present', function () {
beforeEach(function() { beforeEach(function () {
this.allFiles = [ this.allFiles = [
this.resources[0].path, this.resources[0].path,
this.resources[1].path, this.resources[1].path,
@ -161,13 +161,13 @@ describe('ResourceStateManager', function() {
) )
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.calledWithExactly().should.equal(true) return this.callback.calledWithExactly().should.equal(true)
}) })
}) })
describe('when there is a missing file', function() { describe('when there is a missing file', function () {
beforeEach(function() { beforeEach(function () {
this.allFiles = [this.resources[0].path, this.resources[1].path] this.allFiles = [this.resources[0].path, this.resources[1].path]
this.fs.stat = sinon.stub().callsArgWith(1, new Error()) this.fs.stat = sinon.stub().callsArgWith(1, new Error())
return this.ResourceStateManager.checkResourceFiles( return this.ResourceStateManager.checkResourceFiles(
@ -178,7 +178,7 @@ describe('ResourceStateManager', function() {
) )
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
this.callback this.callback
.calledWith(sinon.match(Errors.FilesOutOfSyncError)) .calledWith(sinon.match(Errors.FilesOutOfSyncError))
.should.equal(true) .should.equal(true)
@ -190,8 +190,8 @@ describe('ResourceStateManager', function() {
}) })
}) })
return describe('when a resource contains a relative path', function() { return describe('when a resource contains a relative path', function () {
beforeEach(function() { beforeEach(function () {
this.resources[0].path = '../foo/bar.tex' this.resources[0].path = '../foo/bar.tex'
this.allFiles = [ this.allFiles = [
this.resources[0].path, this.resources[0].path,
@ -206,7 +206,7 @@ describe('ResourceStateManager', function() {
) )
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
const message = this.callback.args[0][0].message const message = this.callback.args[0][0].message

View file

@ -20,8 +20,8 @@ const modulePath = require('path').join(
) )
const path = require('path') const path = require('path')
describe('ResourceWriter', function() { describe('ResourceWriter', function () {
beforeEach(function() { beforeEach(function () {
let Timer let Timer
this.ResourceWriter = SandboxedModule.require(modulePath, { this.ResourceWriter = SandboxedModule.require(modulePath, {
singleOnly: true, singleOnly: true,
@ -37,7 +37,7 @@ describe('ResourceWriter', function() {
'logger-sharelatex': { log: sinon.stub(), err: sinon.stub() }, 'logger-sharelatex': { log: sinon.stub(), err: sinon.stub() },
'./Metrics': (this.Metrics = { './Metrics': (this.Metrics = {
inc: sinon.stub(), inc: sinon.stub(),
Timer: (Timer = (function() { Timer: (Timer = (function () {
Timer = class Timer { Timer = class Timer {
static initClass() { static initClass() {
this.prototype.done = sinon.stub() this.prototype.done = sinon.stub()
@ -54,8 +54,8 @@ describe('ResourceWriter', function() {
return (this.callback = sinon.stub()) return (this.callback = sinon.stub())
}) })
describe('syncResourcesToDisk on a full request', function() { describe('syncResourcesToDisk on a full request', function () {
beforeEach(function() { beforeEach(function () {
this.resources = ['resource-1-mock', 'resource-2-mock', 'resource-3-mock'] this.resources = ['resource-1-mock', 'resource-2-mock', 'resource-3-mock']
this.ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3) this.ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
this.ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2) this.ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
@ -71,33 +71,33 @@ describe('ResourceWriter', function() {
) )
}) })
it('should remove old files', function() { it('should remove old files', function () {
return this.ResourceWriter._removeExtraneousFiles return this.ResourceWriter._removeExtraneousFiles
.calledWith(this.resources, this.basePath) .calledWith(this.resources, this.basePath)
.should.equal(true) .should.equal(true)
}) })
it('should write each resource to disk', function() { it('should write each resource to disk', function () {
return Array.from(this.resources).map(resource => return Array.from(this.resources).map((resource) =>
this.ResourceWriter._writeResourceToDisk this.ResourceWriter._writeResourceToDisk
.calledWith(this.project_id, resource, this.basePath) .calledWith(this.project_id, resource, this.basePath)
.should.equal(true) .should.equal(true)
) )
}) })
it('should store the sync state and resource list', function() { it('should store the sync state and resource list', function () {
return this.ResourceStateManager.saveProjectState return this.ResourceStateManager.saveProjectState
.calledWith(this.syncState, this.resources, this.basePath) .calledWith(this.syncState, this.resources, this.basePath)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
describe('syncResourcesToDisk on an incremental update', function() { describe('syncResourcesToDisk on an incremental update', function () {
beforeEach(function() { beforeEach(function () {
this.resources = ['resource-1-mock'] this.resources = ['resource-1-mock']
this.ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3) this.ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
this.ResourceWriter._removeExtraneousFiles = sinon this.ResourceWriter._removeExtraneousFiles = sinon
@ -120,39 +120,39 @@ describe('ResourceWriter', function() {
) )
}) })
it('should check the sync state matches', function() { it('should check the sync state matches', function () {
return this.ResourceStateManager.checkProjectStateMatches return this.ResourceStateManager.checkProjectStateMatches
.calledWith(this.syncState, this.basePath) .calledWith(this.syncState, this.basePath)
.should.equal(true) .should.equal(true)
}) })
it('should remove old files', function() { it('should remove old files', function () {
return this.ResourceWriter._removeExtraneousFiles return this.ResourceWriter._removeExtraneousFiles
.calledWith(this.resources, this.basePath) .calledWith(this.resources, this.basePath)
.should.equal(true) .should.equal(true)
}) })
it('should check each resource exists', function() { it('should check each resource exists', function () {
return this.ResourceStateManager.checkResourceFiles return this.ResourceStateManager.checkResourceFiles
.calledWith(this.resources, this.allFiles, this.basePath) .calledWith(this.resources, this.allFiles, this.basePath)
.should.equal(true) .should.equal(true)
}) })
it('should write each resource to disk', function() { it('should write each resource to disk', function () {
return Array.from(this.resources).map(resource => return Array.from(this.resources).map((resource) =>
this.ResourceWriter._writeResourceToDisk this.ResourceWriter._writeResourceToDisk
.calledWith(this.project_id, resource, this.basePath) .calledWith(this.project_id, resource, this.basePath)
.should.equal(true) .should.equal(true)
) )
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
describe('syncResourcesToDisk on an incremental update when the state does not match', function() { describe('syncResourcesToDisk on an incremental update when the state does not match', function () {
beforeEach(function() { beforeEach(function () {
this.resources = ['resource-1-mock'] this.resources = ['resource-1-mock']
this.ResourceStateManager.checkProjectStateMatches = sinon this.ResourceStateManager.checkProjectStateMatches = sinon
.stub() .stub()
@ -169,19 +169,19 @@ describe('ResourceWriter', function() {
) )
}) })
it('should check whether the sync state matches', function() { it('should check whether the sync state matches', function () {
return this.ResourceStateManager.checkProjectStateMatches return this.ResourceStateManager.checkProjectStateMatches
.calledWith(this.syncState, this.basePath) .calledWith(this.syncState, this.basePath)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with an error', function() { return it('should call the callback with an error', function () {
return this.callback.calledWith(this.error).should.equal(true) return this.callback.calledWith(this.error).should.equal(true)
}) })
}) })
describe('_removeExtraneousFiles', function() { describe('_removeExtraneousFiles', function () {
beforeEach(function() { beforeEach(function () {
this.output_files = [ this.output_files = [
{ {
path: 'output.pdf', path: 'output.pdf',
@ -250,49 +250,49 @@ describe('ResourceWriter', function() {
) )
}) })
it('should find the existing output files', function() { it('should find the existing output files', function () {
return this.OutputFileFinder.findOutputFiles return this.OutputFileFinder.findOutputFiles
.calledWith(this.resources, this.basePath) .calledWith(this.resources, this.basePath)
.should.equal(true) .should.equal(true)
}) })
it('should delete the output files', function() { it('should delete the output files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'output.pdf')) .calledWith(path.join(this.basePath, 'output.pdf'))
.should.equal(true) .should.equal(true)
}) })
it('should delete the stdout log file', function() { it('should delete the stdout log file', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'output.stdout')) .calledWith(path.join(this.basePath, 'output.stdout'))
.should.equal(true) .should.equal(true)
}) })
it('should delete the stderr log file', function() { it('should delete the stderr log file', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'output.stderr')) .calledWith(path.join(this.basePath, 'output.stderr'))
.should.equal(true) .should.equal(true)
}) })
it('should delete the extra files', function() { it('should delete the extra files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'extra/file.tex')) .calledWith(path.join(this.basePath, 'extra/file.tex'))
.should.equal(true) .should.equal(true)
}) })
it('should not delete the extra aux files', function() { it('should not delete the extra aux files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'extra.aux')) .calledWith(path.join(this.basePath, 'extra.aux'))
.should.equal(false) .should.equal(false)
}) })
it('should not delete the knitr cache file', function() { it('should not delete the knitr cache file', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'cache/_chunk1')) .calledWith(path.join(this.basePath, 'cache/_chunk1'))
.should.equal(false) .should.equal(false)
}) })
it('should not delete the epstopdf converted files', function() { it('should not delete the epstopdf converted files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith( .calledWith(
path.join(this.basePath, 'figures/image-eps-converted-to.pdf') path.join(this.basePath, 'figures/image-eps-converted-to.pdf')
@ -300,25 +300,25 @@ describe('ResourceWriter', function() {
.should.equal(false) .should.equal(false)
}) })
it('should not delete the tikz md5 files', function() { it('should not delete the tikz md5 files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'foo/main-figure0.md5')) .calledWith(path.join(this.basePath, 'foo/main-figure0.md5'))
.should.equal(false) .should.equal(false)
}) })
it('should not delete the tikz dpth files', function() { it('should not delete the tikz dpth files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'foo/main-figure0.dpth')) .calledWith(path.join(this.basePath, 'foo/main-figure0.dpth'))
.should.equal(false) .should.equal(false)
}) })
it('should not delete the tikz pdf files', function() { it('should not delete the tikz pdf files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, 'foo/main-figure0.pdf')) .calledWith(path.join(this.basePath, 'foo/main-figure0.pdf'))
.should.equal(false) .should.equal(false)
}) })
it('should not delete the minted pygstyle files', function() { it('should not delete the minted pygstyle files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith( .calledWith(
path.join(this.basePath, '_minted-main/default-pyg-prefix.pygstyle') path.join(this.basePath, '_minted-main/default-pyg-prefix.pygstyle')
@ -326,13 +326,13 @@ describe('ResourceWriter', function() {
.should.equal(false) .should.equal(false)
}) })
it('should not delete the minted default pygstyle files', function() { it('should not delete the minted default pygstyle files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith(path.join(this.basePath, '_minted-main/default.pygstyle')) .calledWith(path.join(this.basePath, '_minted-main/default.pygstyle'))
.should.equal(false) .should.equal(false)
}) })
it('should not delete the minted default pygtex files', function() { it('should not delete the minted default pygtex files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith( .calledWith(
path.join( path.join(
@ -343,7 +343,7 @@ describe('ResourceWriter', function() {
.should.equal(false) .should.equal(false)
}) })
it('should not delete the markdown md.tex files', function() { it('should not delete the markdown md.tex files', function () {
return this.ResourceWriter._deleteFileIfNotDirectory return this.ResourceWriter._deleteFileIfNotDirectory
.calledWith( .calledWith(
path.join( path.join(
@ -354,18 +354,18 @@ describe('ResourceWriter', function() {
.should.equal(false) .should.equal(false)
}) })
it('should call the callback', function() { it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
return it('should time the request', function() { return it('should time the request', function () {
return this.Metrics.Timer.prototype.done.called.should.equal(true) return this.Metrics.Timer.prototype.done.called.should.equal(true)
}) })
}) })
describe('_writeResourceToDisk', function() { describe('_writeResourceToDisk', function () {
describe('with a url based resource', function() { describe('with a url based resource', function () {
beforeEach(function() { beforeEach(function () {
this.fs.mkdir = sinon.stub().callsArg(2) this.fs.mkdir = sinon.stub().callsArg(2)
this.resource = { this.resource = {
path: 'main.tex', path: 'main.tex',
@ -383,7 +383,7 @@ describe('ResourceWriter', function() {
) )
}) })
it('should ensure the directory exists', function() { it('should ensure the directory exists', function () {
this.fs.mkdir this.fs.mkdir
.calledWith( .calledWith(
path.dirname(path.join(this.basePath, this.resource.path)) path.dirname(path.join(this.basePath, this.resource.path))
@ -391,7 +391,7 @@ describe('ResourceWriter', function() {
.should.equal(true) .should.equal(true)
}) })
it('should write the URL from the cache', function() { it('should write the URL from the cache', function () {
return this.UrlCache.downloadUrlToFile return this.UrlCache.downloadUrlToFile
.calledWith( .calledWith(
this.project_id, this.project_id,
@ -402,17 +402,17 @@ describe('ResourceWriter', function() {
.should.equal(true) .should.equal(true)
}) })
it('should call the callback', function() { it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
return it('should not return an error if the resource writer errored', function() { return it('should not return an error if the resource writer errored', function () {
return should.not.exist(this.callback.args[0][0]) return should.not.exist(this.callback.args[0][0])
}) })
}) })
describe('with a content based resource', function() { describe('with a content based resource', function () {
beforeEach(function() { beforeEach(function () {
this.resource = { this.resource = {
path: 'main.tex', path: 'main.tex',
content: 'Hello world' content: 'Hello world'
@ -427,7 +427,7 @@ describe('ResourceWriter', function() {
) )
}) })
it('should ensure the directory exists', function() { it('should ensure the directory exists', function () {
return this.fs.mkdir return this.fs.mkdir
.calledWith( .calledWith(
path.dirname(path.join(this.basePath, this.resource.path)) path.dirname(path.join(this.basePath, this.resource.path))
@ -435,7 +435,7 @@ describe('ResourceWriter', function() {
.should.equal(true) .should.equal(true)
}) })
it('should write the contents to disk', function() { it('should write the contents to disk', function () {
return this.fs.writeFile return this.fs.writeFile
.calledWith( .calledWith(
path.join(this.basePath, this.resource.path), path.join(this.basePath, this.resource.path),
@ -444,13 +444,13 @@ describe('ResourceWriter', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
return describe('with a file path that breaks out of the root folder', function() { return describe('with a file path that breaks out of the root folder', function () {
beforeEach(function() { beforeEach(function () {
this.resource = { this.resource = {
path: '../../main.tex', path: '../../main.tex',
content: 'Hello world' content: 'Hello world'
@ -464,11 +464,11 @@ describe('ResourceWriter', function() {
) )
}) })
it('should not write to disk', function() { it('should not write to disk', function () {
return this.fs.writeFile.called.should.equal(false) return this.fs.writeFile.called.should.equal(false)
}) })
it('should return an error', function() { it('should return an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
const message = this.callback.args[0][0].message const message = this.callback.args[0][0].message
@ -477,23 +477,23 @@ describe('ResourceWriter', function() {
}) })
}) })
return describe('checkPath', function() { return describe('checkPath', function () {
describe('with a valid path', function() { describe('with a valid path', function () {
beforeEach(function() { beforeEach(function () {
return this.ResourceWriter.checkPath('foo', 'bar', this.callback) return this.ResourceWriter.checkPath('foo', 'bar', this.callback)
}) })
return it('should return the joined path', function() { return it('should return the joined path', function () {
return this.callback.calledWith(null, 'foo/bar').should.equal(true) return this.callback.calledWith(null, 'foo/bar').should.equal(true)
}) })
}) })
describe('with an invalid path', function() { describe('with an invalid path', function () {
beforeEach(function() { beforeEach(function () {
this.ResourceWriter.checkPath('foo', 'baz/../../bar', this.callback) this.ResourceWriter.checkPath('foo', 'baz/../../bar', this.callback)
}) })
it('should return an error', function() { it('should return an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
const message = this.callback.args[0][0].message const message = this.callback.args[0][0].message
@ -501,8 +501,8 @@ describe('ResourceWriter', function() {
}) })
}) })
describe('with another invalid path matching on a prefix', function() { describe('with another invalid path matching on a prefix', function () {
beforeEach(function() { beforeEach(function () {
return this.ResourceWriter.checkPath( return this.ResourceWriter.checkPath(
'foo', 'foo',
'../foobar/baz', '../foobar/baz',
@ -510,7 +510,7 @@ describe('ResourceWriter', function() {
) )
}) })
it('should return an error', function() { it('should return an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
const message = this.callback.args[0][0].message const message = this.callback.args[0][0].message

View file

@ -20,8 +20,8 @@ const modulePath = path.join(
) )
const { expect } = require('chai') const { expect } = require('chai')
describe('StaticServerForbidSymlinks', function() { describe('StaticServerForbidSymlinks', function () {
beforeEach(function() { beforeEach(function () {
this.settings = { this.settings = {
path: { path: {
compilesDir: '/compiles/here' compilesDir: '/compiles/here'
@ -60,8 +60,8 @@ describe('StaticServerForbidSymlinks', function() {
return (this.req.url = '/12345/output.pdf') return (this.req.url = '/12345/output.pdf')
}) })
describe('sending a normal file through', function() { describe('sending a normal file through', function () {
beforeEach(function() { beforeEach(function () {
return (this.fs.realpath = sinon return (this.fs.realpath = sinon
.stub() .stub()
.callsArgWith( .callsArgWith(
@ -71,8 +71,8 @@ describe('StaticServerForbidSymlinks', function() {
)) ))
}) })
return it('should call next', function(done) { return it('should call next', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(200) resCode.should.equal(200)
return done() return done()
} }
@ -80,8 +80,8 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a missing file', function() { describe('with a missing file', function () {
beforeEach(function() { beforeEach(function () {
return (this.fs.realpath = sinon return (this.fs.realpath = sinon
.stub() .stub()
.callsArgWith( .callsArgWith(
@ -91,8 +91,8 @@ describe('StaticServerForbidSymlinks', function() {
)) ))
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -100,15 +100,15 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a symlink file', function() { describe('with a symlink file', function () {
beforeEach(function() { beforeEach(function () {
return (this.fs.realpath = sinon return (this.fs.realpath = sinon
.stub() .stub()
.callsArgWith(1, null, `/etc/${this.req.params.project_id}/output.pdf`)) .callsArgWith(1, null, `/etc/${this.req.params.project_id}/output.pdf`))
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -116,13 +116,13 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a relative file', function() { describe('with a relative file', function () {
beforeEach(function() { beforeEach(function () {
return (this.req.url = '/12345/../67890/output.pdf') return (this.req.url = '/12345/../67890/output.pdf')
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -130,13 +130,13 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a unnormalized file containing .', function() { describe('with a unnormalized file containing .', function () {
beforeEach(function() { beforeEach(function () {
return (this.req.url = '/12345/foo/./output.pdf') return (this.req.url = '/12345/foo/./output.pdf')
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -144,13 +144,13 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a file containing an empty path', function() { describe('with a file containing an empty path', function () {
beforeEach(function() { beforeEach(function () {
return (this.req.url = '/12345/foo//output.pdf') return (this.req.url = '/12345/foo//output.pdf')
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -158,13 +158,13 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a non-project file', function() { describe('with a non-project file', function () {
beforeEach(function() { beforeEach(function () {
return (this.req.url = '/.foo/output.pdf') return (this.req.url = '/.foo/output.pdf')
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -172,13 +172,13 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a file outside the compiledir', function() { describe('with a file outside the compiledir', function () {
beforeEach(function() { beforeEach(function () {
return (this.req.url = '/../bar/output.pdf') return (this.req.url = '/../bar/output.pdf')
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -186,13 +186,13 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a file with no leading /', function() { describe('with a file with no leading /', function () {
beforeEach(function() { beforeEach(function () {
return (this.req.url = './../bar/output.pdf') return (this.req.url = './../bar/output.pdf')
}) })
return it('should send a 404', function(done) { return it('should send a 404', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(404) resCode.should.equal(404)
return done() return done()
} }
@ -200,8 +200,8 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
describe('with a github style path', function() { describe('with a github style path', function () {
beforeEach(function() { beforeEach(function () {
this.req.url = '/henryoswald-latex_example/output/output.log' this.req.url = '/henryoswald-latex_example/output/output.log'
return (this.fs.realpath = sinon return (this.fs.realpath = sinon
.stub() .stub()
@ -212,8 +212,8 @@ describe('StaticServerForbidSymlinks', function() {
)) ))
}) })
return it('should call next', function(done) { return it('should call next', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(200) resCode.should.equal(200)
return done() return done()
} }
@ -221,13 +221,13 @@ describe('StaticServerForbidSymlinks', function() {
}) })
}) })
return describe('with an error from fs.realpath', function() { return describe('with an error from fs.realpath', function () {
beforeEach(function() { beforeEach(function () {
return (this.fs.realpath = sinon.stub().callsArgWith(1, 'error')) return (this.fs.realpath = sinon.stub().callsArgWith(1, 'error'))
}) })
return it('should send a 500', function(done) { return it('should send a 500', function (done) {
this.res.sendStatus = function(resCode) { this.res.sendStatus = function (resCode) {
resCode.should.equal(500) resCode.should.equal(500)
return done() return done()
} }

View file

@ -16,8 +16,8 @@ const modulePath = require('path').join(
'../../../app/js/TikzManager' '../../../app/js/TikzManager'
) )
describe('TikzManager', function() { describe('TikzManager', function () {
beforeEach(function() { beforeEach(function () {
return (this.TikzManager = SandboxedModule.require(modulePath, { return (this.TikzManager = SandboxedModule.require(modulePath, {
requires: { requires: {
'./ResourceWriter': (this.ResourceWriter = {}), './ResourceWriter': (this.ResourceWriter = {}),
@ -28,15 +28,15 @@ describe('TikzManager', function() {
})) }))
}) })
describe('checkMainFile', function() { describe('checkMainFile', function () {
beforeEach(function() { beforeEach(function () {
this.compileDir = 'compile-dir' this.compileDir = 'compile-dir'
this.mainFile = 'main.tex' this.mainFile = 'main.tex'
return (this.callback = sinon.stub()) return (this.callback = sinon.stub())
}) })
describe('if there is already an output.tex file in the resources', function() { describe('if there is already an output.tex file in the resources', function () {
beforeEach(function() { beforeEach(function () {
this.resources = [{ path: 'main.tex' }, { path: 'output.tex' }] this.resources = [{ path: 'main.tex' }, { path: 'output.tex' }]
return this.TikzManager.checkMainFile( return this.TikzManager.checkMainFile(
this.compileDir, this.compileDir,
@ -46,13 +46,13 @@ describe('TikzManager', function() {
) )
}) })
return it('should call the callback with false ', function() { return it('should call the callback with false ', function () {
return this.callback.calledWithExactly(null, false).should.equal(true) return this.callback.calledWithExactly(null, false).should.equal(true)
}) })
}) })
return describe('if there is no output.tex file in the resources', function() { return describe('if there is no output.tex file in the resources', function () {
beforeEach(function() { beforeEach(function () {
this.resources = [{ path: 'main.tex' }] this.resources = [{ path: 'main.tex' }]
return (this.ResourceWriter.checkPath = sinon return (this.ResourceWriter.checkPath = sinon
.stub() .stub()
@ -60,8 +60,8 @@ describe('TikzManager', function() {
.callsArgWith(2, null, `${this.compileDir}/${this.mainFile}`)) .callsArgWith(2, null, `${this.compileDir}/${this.mainFile}`))
}) })
describe('and the main file contains tikzexternalize', function() { describe('and the main file contains tikzexternalize', function () {
beforeEach(function() { beforeEach(function () {
this.SafeReader.readFile = sinon this.SafeReader.readFile = sinon
.stub() .stub()
.withArgs(`${this.compileDir}/${this.mainFile}`) .withArgs(`${this.compileDir}/${this.mainFile}`)
@ -74,19 +74,19 @@ describe('TikzManager', function() {
) )
}) })
it('should look at the file on disk', function() { it('should look at the file on disk', function () {
return this.SafeReader.readFile return this.SafeReader.readFile
.calledWith(`${this.compileDir}/${this.mainFile}`) .calledWith(`${this.compileDir}/${this.mainFile}`)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with true ', function() { return it('should call the callback with true ', function () {
return this.callback.calledWithExactly(null, true).should.equal(true) return this.callback.calledWithExactly(null, true).should.equal(true)
}) })
}) })
describe('and the main file does not contain tikzexternalize', function() { describe('and the main file does not contain tikzexternalize', function () {
beforeEach(function() { beforeEach(function () {
this.SafeReader.readFile = sinon this.SafeReader.readFile = sinon
.stub() .stub()
.withArgs(`${this.compileDir}/${this.mainFile}`) .withArgs(`${this.compileDir}/${this.mainFile}`)
@ -99,19 +99,19 @@ describe('TikzManager', function() {
) )
}) })
it('should look at the file on disk', function() { it('should look at the file on disk', function () {
return this.SafeReader.readFile return this.SafeReader.readFile
.calledWith(`${this.compileDir}/${this.mainFile}`) .calledWith(`${this.compileDir}/${this.mainFile}`)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with false', function() { return it('should call the callback with false', function () {
return this.callback.calledWithExactly(null, false).should.equal(true) return this.callback.calledWithExactly(null, false).should.equal(true)
}) })
}) })
return describe('and the main file contains \\usepackage{pstool}', function() { return describe('and the main file contains \\usepackage{pstool}', function () {
beforeEach(function() { beforeEach(function () {
this.SafeReader.readFile = sinon this.SafeReader.readFile = sinon
.stub() .stub()
.withArgs(`${this.compileDir}/${this.mainFile}`) .withArgs(`${this.compileDir}/${this.mainFile}`)
@ -124,21 +124,21 @@ describe('TikzManager', function() {
) )
}) })
it('should look at the file on disk', function() { it('should look at the file on disk', function () {
return this.SafeReader.readFile return this.SafeReader.readFile
.calledWith(`${this.compileDir}/${this.mainFile}`) .calledWith(`${this.compileDir}/${this.mainFile}`)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback with true ', function() { return it('should call the callback with true ', function () {
return this.callback.calledWithExactly(null, true).should.equal(true) return this.callback.calledWithExactly(null, true).should.equal(true)
}) })
}) })
}) })
}) })
return describe('injectOutputFile', function() { return describe('injectOutputFile', function () {
beforeEach(function() { beforeEach(function () {
this.rootDir = '/mock' this.rootDir = '/mock'
this.filename = 'filename.tex' this.filename = 'filename.tex'
this.callback = sinon.stub() this.callback = sinon.stub()
@ -162,25 +162,25 @@ Hello world
) )
}) })
it('sould check the path', function() { it('sould check the path', function () {
return this.ResourceWriter.checkPath return this.ResourceWriter.checkPath
.calledWith(this.rootDir, this.filename) .calledWith(this.rootDir, this.filename)
.should.equal(true) .should.equal(true)
}) })
it('should read the file', function() { it('should read the file', function () {
return this.fs.readFile return this.fs.readFile
.calledWith(`${this.rootDir}/${this.filename}`, 'utf8') .calledWith(`${this.rootDir}/${this.filename}`, 'utf8')
.should.equal(true) .should.equal(true)
}) })
it('should write out the same file as output.tex', function() { it('should write out the same file as output.tex', function () {
return this.fs.writeFile return this.fs.writeFile
.calledWith(`${this.rootDir}/output.tex`, this.content, { flag: 'wx' }) .calledWith(`${this.rootDir}/output.tex`, this.content, { flag: 'wx' })
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })

View file

@ -16,8 +16,8 @@ require('chai').should()
const modulePath = require('path').join(__dirname, '../../../app/js/UrlCache') const modulePath = require('path').join(__dirname, '../../../app/js/UrlCache')
const { EventEmitter } = require('events') const { EventEmitter } = require('events')
describe('UrlCache', function() { describe('UrlCache', function () {
beforeEach(function() { beforeEach(function () {
this.callback = sinon.stub() this.callback = sinon.stub()
this.url = 'www.example.com/file' this.url = 'www.example.com/file'
this.project_id = 'project-id-123' this.project_id = 'project-id-123'
@ -34,16 +34,16 @@ describe('UrlCache', function() {
})) }))
}) })
describe('_doesUrlNeedDownloading', function() { describe('_doesUrlNeedDownloading', function () {
beforeEach(function() { beforeEach(function () {
this.lastModified = new Date() this.lastModified = new Date()
return (this.lastModifiedRoundedToSeconds = new Date( return (this.lastModifiedRoundedToSeconds = new Date(
Math.floor(this.lastModified.getTime() / 1000) * 1000 Math.floor(this.lastModified.getTime() / 1000) * 1000
)) ))
}) })
describe('when URL does not exist in cache', function() { describe('when URL does not exist in cache', function () {
beforeEach(function() { beforeEach(function () {
this.UrlCache._findUrlDetails = sinon.stub().callsArgWith(2, null, null) this.UrlCache._findUrlDetails = sinon.stub().callsArgWith(2, null, null)
return this.UrlCache._doesUrlNeedDownloading( return this.UrlCache._doesUrlNeedDownloading(
this.project_id, this.project_id,
@ -53,21 +53,21 @@ describe('UrlCache', function() {
) )
}) })
return it('should return the callback with true', function() { return it('should return the callback with true', function () {
return this.callback.calledWith(null, true).should.equal(true) return this.callback.calledWith(null, true).should.equal(true)
}) })
}) })
return describe('when URL does exist in cache', function() { return describe('when URL does exist in cache', function () {
beforeEach(function() { beforeEach(function () {
this.urlDetails = {} this.urlDetails = {}
return (this.UrlCache._findUrlDetails = sinon return (this.UrlCache._findUrlDetails = sinon
.stub() .stub()
.callsArgWith(2, null, this.urlDetails)) .callsArgWith(2, null, this.urlDetails))
}) })
describe('when the modified date is more recent than the cached modified date', function() { describe('when the modified date is more recent than the cached modified date', function () {
beforeEach(function() { beforeEach(function () {
this.urlDetails.lastModified = new Date( this.urlDetails.lastModified = new Date(
this.lastModified.getTime() - 1000 this.lastModified.getTime() - 1000
) )
@ -79,19 +79,19 @@ describe('UrlCache', function() {
) )
}) })
it('should get the url details', function() { it('should get the url details', function () {
return this.UrlCache._findUrlDetails return this.UrlCache._findUrlDetails
.calledWith(this.project_id, this.url) .calledWith(this.project_id, this.url)
.should.equal(true) .should.equal(true)
}) })
return it('should return the callback with true', function() { return it('should return the callback with true', function () {
return this.callback.calledWith(null, true).should.equal(true) return this.callback.calledWith(null, true).should.equal(true)
}) })
}) })
describe('when the cached modified date is more recent than the modified date', function() { describe('when the cached modified date is more recent than the modified date', function () {
beforeEach(function() { beforeEach(function () {
this.urlDetails.lastModified = new Date( this.urlDetails.lastModified = new Date(
this.lastModified.getTime() + 1000 this.lastModified.getTime() + 1000
) )
@ -103,13 +103,13 @@ describe('UrlCache', function() {
) )
}) })
return it('should return the callback with false', function() { return it('should return the callback with false', function () {
return this.callback.calledWith(null, false).should.equal(true) return this.callback.calledWith(null, false).should.equal(true)
}) })
}) })
describe('when the cached modified date is equal to the modified date', function() { describe('when the cached modified date is equal to the modified date', function () {
beforeEach(function() { beforeEach(function () {
this.urlDetails.lastModified = this.lastModified this.urlDetails.lastModified = this.lastModified
return this.UrlCache._doesUrlNeedDownloading( return this.UrlCache._doesUrlNeedDownloading(
this.project_id, this.project_id,
@ -119,13 +119,13 @@ describe('UrlCache', function() {
) )
}) })
return it('should return the callback with false', function() { return it('should return the callback with false', function () {
return this.callback.calledWith(null, false).should.equal(true) return this.callback.calledWith(null, false).should.equal(true)
}) })
}) })
describe('when the provided modified date does not exist', function() { describe('when the provided modified date does not exist', function () {
beforeEach(function() { beforeEach(function () {
this.lastModified = null this.lastModified = null
return this.UrlCache._doesUrlNeedDownloading( return this.UrlCache._doesUrlNeedDownloading(
this.project_id, this.project_id,
@ -135,13 +135,13 @@ describe('UrlCache', function() {
) )
}) })
return it('should return the callback with true', function() { return it('should return the callback with true', function () {
return this.callback.calledWith(null, true).should.equal(true) return this.callback.calledWith(null, true).should.equal(true)
}) })
}) })
return describe('when the URL does not have a modified date', function() { return describe('when the URL does not have a modified date', function () {
beforeEach(function() { beforeEach(function () {
this.urlDetails.lastModified = null this.urlDetails.lastModified = null
return this.UrlCache._doesUrlNeedDownloading( return this.UrlCache._doesUrlNeedDownloading(
this.project_id, this.project_id,
@ -151,23 +151,23 @@ describe('UrlCache', function() {
) )
}) })
return it('should return the callback with true', function() { return it('should return the callback with true', function () {
return this.callback.calledWith(null, true).should.equal(true) return this.callback.calledWith(null, true).should.equal(true)
}) })
}) })
}) })
}) })
describe('_ensureUrlIsInCache', function() { describe('_ensureUrlIsInCache', function () {
beforeEach(function() { beforeEach(function () {
this.UrlFetcher.pipeUrlToFileWithRetry = sinon.stub().callsArg(2) this.UrlFetcher.pipeUrlToFileWithRetry = sinon.stub().callsArg(2)
return (this.UrlCache._updateOrCreateUrlDetails = sinon return (this.UrlCache._updateOrCreateUrlDetails = sinon
.stub() .stub()
.callsArg(3)) .callsArg(3))
}) })
describe('when the URL needs updating', function() { describe('when the URL needs updating', function () {
beforeEach(function() { beforeEach(function () {
this.UrlCache._doesUrlNeedDownloading = sinon this.UrlCache._doesUrlNeedDownloading = sinon
.stub() .stub()
.callsArgWith(3, null, true) .callsArgWith(3, null, true)
@ -179,7 +179,7 @@ describe('UrlCache', function() {
) )
}) })
it('should check that the url needs downloading', function() { it('should check that the url needs downloading', function () {
return this.UrlCache._doesUrlNeedDownloading return this.UrlCache._doesUrlNeedDownloading
.calledWith( .calledWith(
this.project_id, this.project_id,
@ -189,7 +189,7 @@ describe('UrlCache', function() {
.should.equal(true) .should.equal(true)
}) })
it('should download the URL to the cache file', function() { it('should download the URL to the cache file', function () {
return this.UrlFetcher.pipeUrlToFileWithRetry return this.UrlFetcher.pipeUrlToFileWithRetry
.calledWith( .calledWith(
this.url, this.url,
@ -198,7 +198,7 @@ describe('UrlCache', function() {
.should.equal(true) .should.equal(true)
}) })
it('should update the database entry', function() { it('should update the database entry', function () {
return this.UrlCache._updateOrCreateUrlDetails return this.UrlCache._updateOrCreateUrlDetails
.calledWith( .calledWith(
this.project_id, this.project_id,
@ -208,7 +208,7 @@ describe('UrlCache', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should return the callback with the cache file path', function() { return it('should return the callback with the cache file path', function () {
return this.callback return this.callback
.calledWith( .calledWith(
null, null,
@ -218,8 +218,8 @@ describe('UrlCache', function() {
}) })
}) })
return describe('when the URL does not need updating', function() { return describe('when the URL does not need updating', function () {
beforeEach(function() { beforeEach(function () {
this.UrlCache._doesUrlNeedDownloading = sinon this.UrlCache._doesUrlNeedDownloading = sinon
.stub() .stub()
.callsArgWith(3, null, false) .callsArgWith(3, null, false)
@ -231,11 +231,11 @@ describe('UrlCache', function() {
) )
}) })
it('should not download the URL to the cache file', function() { it('should not download the URL to the cache file', function () {
return this.UrlFetcher.pipeUrlToFileWithRetry.called.should.equal(false) return this.UrlFetcher.pipeUrlToFileWithRetry.called.should.equal(false)
}) })
return it('should return the callback with the cache file path', function() { return it('should return the callback with the cache file path', function () {
return this.callback return this.callback
.calledWith( .calledWith(
null, null,
@ -246,8 +246,8 @@ describe('UrlCache', function() {
}) })
}) })
describe('downloadUrlToFile', function() { describe('downloadUrlToFile', function () {
beforeEach(function() { beforeEach(function () {
this.cachePath = 'path/to/cached/url' this.cachePath = 'path/to/cached/url'
this.destPath = 'path/to/destination' this.destPath = 'path/to/destination'
this.UrlCache._copyFile = sinon.stub().callsArg(2) this.UrlCache._copyFile = sinon.stub().callsArg(2)
@ -263,25 +263,25 @@ describe('UrlCache', function() {
) )
}) })
it('should ensure the URL is downloaded and updated in the cache', function() { it('should ensure the URL is downloaded and updated in the cache', function () {
return this.UrlCache._ensureUrlIsInCache return this.UrlCache._ensureUrlIsInCache
.calledWith(this.project_id, this.url, this.lastModified) .calledWith(this.project_id, this.url, this.lastModified)
.should.equal(true) .should.equal(true)
}) })
it('should copy the file to the new location', function() { it('should copy the file to the new location', function () {
return this.UrlCache._copyFile return this.UrlCache._copyFile
.calledWith(this.cachePath, this.destPath) .calledWith(this.cachePath, this.destPath)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
describe('_deleteUrlCacheFromDisk', function() { describe('_deleteUrlCacheFromDisk', function () {
beforeEach(function() { beforeEach(function () {
this.fs.unlink = sinon.stub().callsArg(1) this.fs.unlink = sinon.stub().callsArg(1)
return this.UrlCache._deleteUrlCacheFromDisk( return this.UrlCache._deleteUrlCacheFromDisk(
this.project_id, this.project_id,
@ -290,7 +290,7 @@ describe('UrlCache', function() {
) )
}) })
it('should delete the cache file', function() { it('should delete the cache file', function () {
return this.fs.unlink return this.fs.unlink
.calledWith( .calledWith(
this.UrlCache._cacheFilePathForUrl(this.project_id, this.url) this.UrlCache._cacheFilePathForUrl(this.project_id, this.url)
@ -298,13 +298,13 @@ describe('UrlCache', function() {
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
describe('_clearUrlFromCache', function() { describe('_clearUrlFromCache', function () {
beforeEach(function() { beforeEach(function () {
this.UrlCache._deleteUrlCacheFromDisk = sinon.stub().callsArg(2) this.UrlCache._deleteUrlCacheFromDisk = sinon.stub().callsArg(2)
this.UrlCache._clearUrlDetails = sinon.stub().callsArg(2) this.UrlCache._clearUrlDetails = sinon.stub().callsArg(2)
return this.UrlCache._clearUrlFromCache( return this.UrlCache._clearUrlFromCache(
@ -314,25 +314,25 @@ describe('UrlCache', function() {
) )
}) })
it('should delete the file on disk', function() { it('should delete the file on disk', function () {
return this.UrlCache._deleteUrlCacheFromDisk return this.UrlCache._deleteUrlCacheFromDisk
.calledWith(this.project_id, this.url) .calledWith(this.project_id, this.url)
.should.equal(true) .should.equal(true)
}) })
it('should clear the entry in the database', function() { it('should clear the entry in the database', function () {
return this.UrlCache._clearUrlDetails return this.UrlCache._clearUrlDetails
.calledWith(this.project_id, this.url) .calledWith(this.project_id, this.url)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
return describe('clearProject', function() { return describe('clearProject', function () {
beforeEach(function() { beforeEach(function () {
this.urls = ['www.example.com/file1', 'www.example.com/file2'] this.urls = ['www.example.com/file1', 'www.example.com/file2']
this.UrlCache._findAllUrlsInProject = sinon this.UrlCache._findAllUrlsInProject = sinon
.stub() .stub()
@ -341,15 +341,15 @@ describe('UrlCache', function() {
return this.UrlCache.clearProject(this.project_id, this.callback) return this.UrlCache.clearProject(this.project_id, this.callback)
}) })
it('should clear the cache for each url in the project', function() { it('should clear the cache for each url in the project', function () {
return Array.from(this.urls).map(url => return Array.from(this.urls).map((url) =>
this.UrlCache._clearUrlFromCache this.UrlCache._clearUrlFromCache
.calledWith(this.project_id, url) .calledWith(this.project_id, url)
.should.equal(true) .should.equal(true)
) )
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })

View file

@ -15,8 +15,8 @@ require('chai').should()
const modulePath = require('path').join(__dirname, '../../../app/js/UrlFetcher') const modulePath = require('path').join(__dirname, '../../../app/js/UrlFetcher')
const { EventEmitter } = require('events') const { EventEmitter } = require('events')
describe('UrlFetcher', function() { describe('UrlFetcher', function () {
beforeEach(function() { beforeEach(function () {
this.callback = sinon.stub() this.callback = sinon.stub()
this.url = 'https://www.example.com/file/here?query=string' this.url = 'https://www.example.com/file/here?query=string'
return (this.UrlFetcher = SandboxedModule.require(modulePath, { return (this.UrlFetcher = SandboxedModule.require(modulePath, {
@ -33,34 +33,34 @@ describe('UrlFetcher', function() {
} }
})) }))
}) })
describe('pipeUrlToFileWithRetry', function() { describe('pipeUrlToFileWithRetry', function () {
this.beforeEach(function() { this.beforeEach(function () {
this.UrlFetcher.pipeUrlToFile = sinon.stub() this.UrlFetcher.pipeUrlToFile = sinon.stub()
}) })
it('should call pipeUrlToFile', function(done) { it('should call pipeUrlToFile', function (done) {
this.UrlFetcher.pipeUrlToFile.callsArgWith(2) this.UrlFetcher.pipeUrlToFile.callsArgWith(2)
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, err => { this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, (err) => {
expect(err).to.equal(undefined) expect(err).to.equal(undefined)
this.UrlFetcher.pipeUrlToFile.called.should.equal(true) this.UrlFetcher.pipeUrlToFile.called.should.equal(true)
done() done()
}) })
}) })
it('should call pipeUrlToFile multiple times on error', function(done) { it('should call pipeUrlToFile multiple times on error', function (done) {
const error = new Error("couldn't download file") const error = new Error("couldn't download file")
this.UrlFetcher.pipeUrlToFile.callsArgWith(2, error) this.UrlFetcher.pipeUrlToFile.callsArgWith(2, error)
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, err => { this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, (err) => {
expect(err).to.equal(error) expect(err).to.equal(error)
this.UrlFetcher.pipeUrlToFile.callCount.should.equal(3) this.UrlFetcher.pipeUrlToFile.callCount.should.equal(3)
done() done()
}) })
}) })
it('should call pipeUrlToFile twice if only 1 error', function(done) { it('should call pipeUrlToFile twice if only 1 error', function (done) {
this.UrlFetcher.pipeUrlToFile.onCall(0).callsArgWith(2, 'error') this.UrlFetcher.pipeUrlToFile.onCall(0).callsArgWith(2, 'error')
this.UrlFetcher.pipeUrlToFile.onCall(1).callsArgWith(2) this.UrlFetcher.pipeUrlToFile.onCall(1).callsArgWith(2)
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, err => { this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, (err) => {
expect(err).to.equal(undefined) expect(err).to.equal(undefined)
this.UrlFetcher.pipeUrlToFile.callCount.should.equal(2) this.UrlFetcher.pipeUrlToFile.callCount.should.equal(2)
done() done()
@ -68,13 +68,13 @@ describe('UrlFetcher', function() {
}) })
}) })
describe('pipeUrlToFile', function() { describe('pipeUrlToFile', function () {
it('should turn off the cookie jar in request', function() { it('should turn off the cookie jar in request', function () {
return this.defaults.calledWith({ jar: false }).should.equal(true) return this.defaults.calledWith({ jar: false }).should.equal(true)
}) })
describe('rewrite url domain if filestoreDomainOveride is set', function() { describe('rewrite url domain if filestoreDomainOveride is set', function () {
beforeEach(function() { beforeEach(function () {
this.path = '/path/to/file/on/disk' this.path = '/path/to/file/on/disk'
this.request.get = sinon this.request.get = sinon
.stub() .stub()
@ -88,7 +88,7 @@ describe('UrlFetcher', function() {
return (this.fs.unlink = (file, callback) => callback()) return (this.fs.unlink = (file, callback) => callback())
}) })
it('should use the normal domain when override not set', function(done) { it('should use the normal domain when override not set', function (done) {
this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => { this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => {
this.request.get.args[0][0].url.should.equal(this.url) this.request.get.args[0][0].url.should.equal(this.url)
return done() return done()
@ -99,7 +99,7 @@ describe('UrlFetcher', function() {
return this.fileStream.emit('finish') return this.fileStream.emit('finish')
}) })
return it('should use override domain when filestoreDomainOveride is set', function(done) { return it('should use override domain when filestoreDomainOveride is set', function (done) {
this.settings.filestoreDomainOveride = '192.11.11.11' this.settings.filestoreDomainOveride = '192.11.11.11'
this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => { this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => {
this.request.get.args[0][0].url.should.equal( this.request.get.args[0][0].url.should.equal(
@ -114,8 +114,8 @@ describe('UrlFetcher', function() {
}) })
}) })
return describe('pipeUrlToFile', function() { return describe('pipeUrlToFile', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.path = '/path/to/file/on/disk' this.path = '/path/to/file/on/disk'
this.request.get = sinon this.request.get = sinon
.stub() .stub()
@ -130,8 +130,8 @@ describe('UrlFetcher', function() {
return done() return done()
}) })
describe('successfully', function() { describe('successfully', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => { this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => {
this.callback() this.callback()
return done() return done()
@ -142,32 +142,32 @@ describe('UrlFetcher', function() {
return this.fileStream.emit('finish') return this.fileStream.emit('finish')
}) })
it('should request the URL', function() { it('should request the URL', function () {
return this.request.get return this.request.get
.calledWith(sinon.match({ url: this.url })) .calledWith(sinon.match({ url: this.url }))
.should.equal(true) .should.equal(true)
}) })
it('should open the file for writing', function() { it('should open the file for writing', function () {
return this.fs.createWriteStream return this.fs.createWriteStream
.calledWith(this.path) .calledWith(this.path)
.should.equal(true) .should.equal(true)
}) })
it('should pipe the URL to the file', function() { it('should pipe the URL to the file', function () {
return this.urlStream.pipe return this.urlStream.pipe
.calledWith(this.fileStream) .calledWith(this.fileStream)
.should.equal(true) .should.equal(true)
}) })
return it('should call the callback', function() { return it('should call the callback', function () {
return this.callback.called.should.equal(true) return this.callback.called.should.equal(true)
}) })
}) })
describe('with non success status code', function() { describe('with non success status code', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.UrlFetcher.pipeUrlToFile(this.url, this.path, err => { this.UrlFetcher.pipeUrlToFile(this.url, this.path, (err) => {
this.callback(err) this.callback(err)
return done() return done()
}) })
@ -176,7 +176,7 @@ describe('UrlFetcher', function() {
return this.urlStream.emit('end') return this.urlStream.emit('end')
}) })
it('should call the callback with an error', function() { it('should call the callback with an error', function () {
this.callback.calledWith(sinon.match(Error)).should.equal(true) this.callback.calledWith(sinon.match(Error)).should.equal(true)
const message = this.callback.args[0][0].message const message = this.callback.args[0][0].message
@ -186,9 +186,9 @@ describe('UrlFetcher', function() {
}) })
}) })
return describe('with error', function() { return describe('with error', function () {
beforeEach(function(done) { beforeEach(function (done) {
this.UrlFetcher.pipeUrlToFile(this.url, this.path, err => { this.UrlFetcher.pipeUrlToFile(this.url, this.path, (err) => {
this.callback(err) this.callback(err)
return done() return done()
}) })
@ -198,11 +198,11 @@ describe('UrlFetcher', function() {
) )
}) })
it('should call the callback with the error', function() { it('should call the callback with the error', function () {
return this.callback.calledWith(this.error).should.equal(true) return this.callback.calledWith(this.error).should.equal(true)
}) })
return it('should only call the callback once, even if end is called', function() { return it('should only call the callback once, even if end is called', function () {
this.urlStream.emit('end') this.urlStream.emit('end')
return this.callback.calledOnce.should.equal(true) return this.callback.calledOnce.should.equal(true)
}) })