add initial compileGroup support
This commit is contained in:
@@ -199,7 +199,8 @@ module.exports = CompileManager = {
|
|||||||
timeout: request.timeout,
|
timeout: request.timeout,
|
||||||
image: request.imageName,
|
image: request.imageName,
|
||||||
flags: request.flags,
|
flags: request.flags,
|
||||||
environment: env
|
environment: env,
|
||||||
|
compileGroup: request.compileGroup
|
||||||
},
|
},
|
||||||
function(error, output, stats, timings) {
|
function(error, output, stats, timings) {
|
||||||
// request was for validation only
|
// request was for validation only
|
||||||
@@ -536,6 +537,7 @@ module.exports = CompileManager = {
|
|||||||
const directory = getCompileDir(project_id, user_id)
|
const directory = getCompileDir(project_id, user_id)
|
||||||
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'
|
||||||
return CommandRunner.run(
|
return CommandRunner.run(
|
||||||
compileName,
|
compileName,
|
||||||
command,
|
command,
|
||||||
@@ -543,6 +545,7 @@ module.exports = CompileManager = {
|
|||||||
Settings.clsi != null ? Settings.clsi.docker.image : undefined,
|
Settings.clsi != null ? Settings.clsi.docker.image : undefined,
|
||||||
timeout,
|
timeout,
|
||||||
{},
|
{},
|
||||||
|
compileGroup,
|
||||||
function(error, output) {
|
function(error, output) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
logger.err(
|
logger.err(
|
||||||
@@ -606,6 +609,7 @@ module.exports = CompileManager = {
|
|||||||
const compileDir = getCompileDir(project_id, user_id)
|
const compileDir = getCompileDir(project_id, user_id)
|
||||||
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'
|
||||||
return fse.ensureDir(compileDir, function(error) {
|
return fse.ensureDir(compileDir, function(error) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
logger.err(
|
logger.err(
|
||||||
@@ -621,6 +625,7 @@ module.exports = CompileManager = {
|
|||||||
image,
|
image,
|
||||||
timeout,
|
timeout,
|
||||||
{},
|
{},
|
||||||
|
compileGroup,
|
||||||
function(error) {
|
function(error) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return callback(error)
|
return callback(error)
|
||||||
|
|||||||
@@ -45,7 +45,16 @@ module.exports = DockerRunner = {
|
|||||||
ERR_EXITED: new Error('exited'),
|
ERR_EXITED: new Error('exited'),
|
||||||
ERR_TIMED_OUT: new Error('container timed out'),
|
ERR_TIMED_OUT: new Error('container timed out'),
|
||||||
|
|
||||||
run(project_id, command, directory, image, timeout, environment, callback) {
|
run(
|
||||||
|
project_id,
|
||||||
|
command,
|
||||||
|
directory,
|
||||||
|
image,
|
||||||
|
timeout,
|
||||||
|
environment,
|
||||||
|
compileGroup,
|
||||||
|
callback
|
||||||
|
) {
|
||||||
let name
|
let name
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
callback = function(error, output) {}
|
callback = function(error, output) {}
|
||||||
@@ -88,7 +97,8 @@ module.exports = DockerRunner = {
|
|||||||
image,
|
image,
|
||||||
volumes,
|
volumes,
|
||||||
timeout,
|
timeout,
|
||||||
environment
|
environment,
|
||||||
|
compileGroup
|
||||||
)
|
)
|
||||||
const fingerprint = DockerRunner._fingerprintContainer(options)
|
const fingerprint = DockerRunner._fingerprintContainer(options)
|
||||||
options.name = name = `project-${project_id}-${fingerprint}`
|
options.name = name = `project-${project_id}-${fingerprint}`
|
||||||
@@ -224,7 +234,14 @@ module.exports = DockerRunner = {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
_getContainerOptions(command, image, volumes, timeout, environment) {
|
_getContainerOptions(
|
||||||
|
command,
|
||||||
|
image,
|
||||||
|
volumes,
|
||||||
|
timeout,
|
||||||
|
environment,
|
||||||
|
compileGroup
|
||||||
|
) {
|
||||||
let m, year
|
let m, year
|
||||||
let key, value, hostVol, dockerVol
|
let key, value, hostVol, dockerVol
|
||||||
const timeoutInSeconds = timeout / 1000
|
const timeoutInSeconds = timeout / 1000
|
||||||
@@ -311,6 +328,23 @@ module.exports = DockerRunner = {
|
|||||||
options.HostConfig.Runtime = Settings.clsi.docker.runtime
|
options.HostConfig.Runtime = Settings.clsi.docker.runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings.clsi.docker.Readonly) {
|
||||||
|
options.HostConfig.ReadonlyRootfs = true
|
||||||
|
options.HostConfig.Tmpfs = { '/tmp': 'rw,noexec,nosuid,size=65536k' }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow per-compile group overriding of individual settings
|
||||||
|
if (
|
||||||
|
Settings.clsi.docker.compileGroupConfig &&
|
||||||
|
Settings.clsi.docker.compileGroupConfig[compileGroup]
|
||||||
|
) {
|
||||||
|
const override = Settings.clsi.docker.compileGroupConfig[compileGroup]
|
||||||
|
let key
|
||||||
|
for (key in override) {
|
||||||
|
_.set(options, key, override[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return options
|
return options
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ module.exports = LatexRunner = {
|
|||||||
timeout,
|
timeout,
|
||||||
image,
|
image,
|
||||||
environment,
|
environment,
|
||||||
flags
|
flags,
|
||||||
|
compileGroup
|
||||||
} = options
|
} = options
|
||||||
if (!compiler) {
|
if (!compiler) {
|
||||||
compiler = 'pdflatex'
|
compiler = 'pdflatex'
|
||||||
@@ -46,7 +47,15 @@ module.exports = LatexRunner = {
|
|||||||
} // milliseconds
|
} // milliseconds
|
||||||
|
|
||||||
logger.log(
|
logger.log(
|
||||||
{ directory, compiler, timeout, mainFile, environment, flags },
|
{
|
||||||
|
directory,
|
||||||
|
compiler,
|
||||||
|
timeout,
|
||||||
|
mainFile,
|
||||||
|
environment,
|
||||||
|
flags,
|
||||||
|
compileGroup
|
||||||
|
},
|
||||||
'starting compile'
|
'starting compile'
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -79,6 +88,7 @@ module.exports = LatexRunner = {
|
|||||||
image,
|
image,
|
||||||
timeout,
|
timeout,
|
||||||
environment,
|
environment,
|
||||||
|
compileGroup,
|
||||||
function(error, output) {
|
function(error, output) {
|
||||||
delete ProcessTable[id]
|
delete ProcessTable[id]
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
|||||||
@@ -20,7 +20,16 @@ const logger = require('logger-sharelatex')
|
|||||||
logger.info('using standard command runner')
|
logger.info('using standard command runner')
|
||||||
|
|
||||||
module.exports = CommandRunner = {
|
module.exports = CommandRunner = {
|
||||||
run(project_id, command, directory, image, timeout, environment, callback) {
|
run(
|
||||||
|
project_id,
|
||||||
|
command,
|
||||||
|
directory,
|
||||||
|
image,
|
||||||
|
timeout,
|
||||||
|
environment,
|
||||||
|
compileGroup,
|
||||||
|
callback
|
||||||
|
) {
|
||||||
let key, value
|
let key, value
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
callback = function(error) {}
|
callback = function(error) {}
|
||||||
|
|||||||
@@ -74,7 +74,17 @@ module.exports = RequestParser = {
|
|||||||
default: [],
|
default: [],
|
||||||
type: 'object'
|
type: 'object'
|
||||||
})
|
})
|
||||||
|
if (settings.allowedCompileGroups) {
|
||||||
|
response.compileGroup = this._parseAttribute(
|
||||||
|
'compileGroup',
|
||||||
|
compile.options.compileGroup,
|
||||||
|
{
|
||||||
|
validValues: settings.allowedCompileGroups,
|
||||||
|
default: '',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
// The syncType specifies whether the request contains all
|
// The syncType specifies whether the request contains all
|
||||||
// resources (full) or only those resources to be updated
|
// resources (full) or only those resources to be updated
|
||||||
// in-place (incremental).
|
// in-place (incremental).
|
||||||
|
|||||||
@@ -63,6 +63,17 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.ALLOWED_COMPILE_GROUPS) {
|
||||||
|
try {
|
||||||
|
module.exports.allowedCompileGroups = process.env.ALLOWED_COMPILE_GROUPS.split(
|
||||||
|
' '
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error, 'could not apply allowed compile group setting')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (process.env.DOCKER_RUNNER) {
|
if (process.env.DOCKER_RUNNER) {
|
||||||
let seccompProfilePath
|
let seccompProfilePath
|
||||||
module.exports.clsi = {
|
module.exports.clsi = {
|
||||||
@@ -82,6 +93,21 @@ if (process.env.DOCKER_RUNNER) {
|
|||||||
checkProjectsIntervalMs: 10 * 60 * 1000
|
checkProjectsIntervalMs: 10 * 60 * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Override individual docker settings using path-based keys, e.g.:
|
||||||
|
// compileGroupDockerConfigs = {
|
||||||
|
// priority: { 'HostConfig.CpuShares': 100 }
|
||||||
|
// beta: { 'dotted.path.here', 'value'}
|
||||||
|
// }
|
||||||
|
const compileGroupConfig = JSON.parse(
|
||||||
|
process.env.COMPILE_GROUP_DOCKER_CONFIGS || '{}'
|
||||||
|
)
|
||||||
|
module.exports.clsi.docker.compileGroupConfig = compileGroupConfig
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error, 'could not apply compile group docker configs')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
seccompProfilePath = Path.resolve(__dirname, '../seccomp/clsi-profile.json')
|
seccompProfilePath = Path.resolve(__dirname, '../seccomp/clsi-profile.json')
|
||||||
module.exports.clsi.docker.seccomp_profile = JSON.stringify(
|
module.exports.clsi.docker.seccomp_profile = JSON.stringify(
|
||||||
|
|||||||
@@ -160,7 +160,8 @@ describe('CompileManager', function() {
|
|||||||
compiler: (this.compiler = 'pdflatex'),
|
compiler: (this.compiler = 'pdflatex'),
|
||||||
timeout: (this.timeout = 42000),
|
timeout: (this.timeout = 42000),
|
||||||
imageName: (this.image = 'example.com/image'),
|
imageName: (this.image = 'example.com/image'),
|
||||||
flags: (this.flags = ['-file-line-error'])
|
flags: (this.flags = ['-file-line-error']),
|
||||||
|
compileGroup: (this.compileGroup = 'compile-group')
|
||||||
}
|
}
|
||||||
this.env = {}
|
this.env = {}
|
||||||
this.Settings.compileDir = 'compiles'
|
this.Settings.compileDir = 'compiles'
|
||||||
@@ -199,7 +200,8 @@ describe('CompileManager', function() {
|
|||||||
timeout: this.timeout,
|
timeout: this.timeout,
|
||||||
image: this.image,
|
image: this.image,
|
||||||
flags: this.flags,
|
flags: this.flags,
|
||||||
environment: this.env
|
environment: this.env,
|
||||||
|
compileGroup: this.compileGroup
|
||||||
})
|
})
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
@@ -253,7 +255,8 @@ describe('CompileManager', function() {
|
|||||||
CHKTEX_OPTIONS: '-nall -e9 -e10 -w15 -w16',
|
CHKTEX_OPTIONS: '-nall -e9 -e10 -w15 -w16',
|
||||||
CHKTEX_EXIT_ON_ERROR: 1,
|
CHKTEX_EXIT_ON_ERROR: 1,
|
||||||
CHKTEX_ULIMIT_OPTIONS: '-t 5 -v 64000'
|
CHKTEX_ULIMIT_OPTIONS: '-t 5 -v 64000'
|
||||||
}
|
},
|
||||||
|
compileGroup: this.compileGroup
|
||||||
})
|
})
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
@@ -275,7 +278,8 @@ describe('CompileManager', function() {
|
|||||||
timeout: this.timeout,
|
timeout: this.timeout,
|
||||||
image: this.image,
|
image: this.image,
|
||||||
flags: this.flags,
|
flags: this.flags,
|
||||||
environment: this.env
|
environment: this.env,
|
||||||
|
compileGroup: this.compileGroup
|
||||||
})
|
})
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
@@ -384,7 +388,7 @@ describe('CompileManager', function() {
|
|||||||
this.stdout = `NODE\t${this.page}\t${this.h}\t${this.v}\t${this.width}\t${this.height}\n`
|
this.stdout = `NODE\t${this.page}\t${this.h}\t${this.v}\t${this.width}\t${this.height}\n`
|
||||||
this.CommandRunner.run = sinon
|
this.CommandRunner.run = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(6, null, { stdout: this.stdout })
|
.callsArgWith(7, null, { stdout: this.stdout })
|
||||||
return this.CompileManager.syncFromCode(
|
return this.CompileManager.syncFromCode(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.user_id,
|
this.user_id,
|
||||||
@@ -443,7 +447,7 @@ describe('CompileManager', function() {
|
|||||||
this.stdout = `NODE\t${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/${this.file_name}\t${this.line}\t${this.column}\n`
|
this.stdout = `NODE\t${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/${this.file_name}\t${this.line}\t${this.column}\n`
|
||||||
this.CommandRunner.run = sinon
|
this.CommandRunner.run = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(6, null, { stdout: this.stdout })
|
.callsArgWith(7, null, { stdout: this.stdout })
|
||||||
return this.CompileManager.syncFromPdf(
|
return this.CompileManager.syncFromPdf(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.user_id,
|
this.user_id,
|
||||||
@@ -485,7 +489,7 @@ describe('CompileManager', function() {
|
|||||||
|
|
||||||
return describe('wordcount', function() {
|
return describe('wordcount', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.CommandRunner.run = sinon.stub().callsArg(6)
|
this.CommandRunner.run = sinon.stub().callsArg(7)
|
||||||
this.fs.readFile = sinon
|
this.fs.readFile = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(
|
.callsArgWith(
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ describe('DockerRunner', function() {
|
|||||||
this.project_id = 'project-id-123'
|
this.project_id = 'project-id-123'
|
||||||
this.volumes = { '/local/compile/directory': '/compile' }
|
this.volumes = { '/local/compile/directory': '/compile' }
|
||||||
this.Settings.clsi.docker.image = this.defaultImage = 'default-image'
|
this.Settings.clsi.docker.image = this.defaultImage = 'default-image'
|
||||||
|
this.compileGroup = 'compile-group'
|
||||||
return (this.Settings.clsi.docker.env = { PATH: 'mock-path' })
|
return (this.Settings.clsi.docker.env = { PATH: 'mock-path' })
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ describe('DockerRunner', function() {
|
|||||||
this.image,
|
this.image,
|
||||||
this.timeout,
|
this.timeout,
|
||||||
this.env,
|
this.env,
|
||||||
|
this.compileGroup,
|
||||||
(err, output) => {
|
(err, output) => {
|
||||||
this.callback(err, output)
|
this.callback(err, output)
|
||||||
return done()
|
return done()
|
||||||
@@ -172,6 +174,7 @@ describe('DockerRunner', function() {
|
|||||||
this.image,
|
this.image,
|
||||||
this.timeout,
|
this.timeout,
|
||||||
this.env,
|
this.env,
|
||||||
|
this.compileGroup,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -220,6 +223,7 @@ describe('DockerRunner', function() {
|
|||||||
this.image,
|
this.image,
|
||||||
this.timeout,
|
this.timeout,
|
||||||
this.env,
|
this.env,
|
||||||
|
this.compileGroup,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -253,6 +257,7 @@ describe('DockerRunner', function() {
|
|||||||
null,
|
null,
|
||||||
this.timeout,
|
this.timeout,
|
||||||
this.env,
|
this.env,
|
||||||
|
this.compileGroup,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -282,6 +287,7 @@ describe('DockerRunner', function() {
|
|||||||
this.image,
|
this.image,
|
||||||
this.timeout,
|
this.timeout,
|
||||||
this.env,
|
this.env,
|
||||||
|
this.compileGroup,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -293,6 +299,64 @@ describe('DockerRunner', function() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('run with _getOptions', function() {
|
||||||
|
beforeEach(function(done) {
|
||||||
|
// this.DockerRunner._getContainerOptions = sinon
|
||||||
|
// .stub()
|
||||||
|
// .returns((this.options = { mockoptions: 'foo' }))
|
||||||
|
this.DockerRunner._fingerprintContainer = sinon
|
||||||
|
.stub()
|
||||||
|
.returns((this.fingerprint = 'fingerprint'))
|
||||||
|
|
||||||
|
this.name = `project-${this.project_id}-${this.fingerprint}`
|
||||||
|
|
||||||
|
this.command = ['mock', 'command', '--outdir=$COMPILE_DIR']
|
||||||
|
this.command_with_dir = ['mock', 'command', '--outdir=/compile']
|
||||||
|
this.timeout = 42000
|
||||||
|
return done()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when a compile group config is set', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.Settings.clsi.docker.compileGroupConfig = {
|
||||||
|
'compile-group': {
|
||||||
|
'HostConfig.newProperty': 'new-property'
|
||||||
|
},
|
||||||
|
'other-group': { otherProperty: 'other-property' }
|
||||||
|
}
|
||||||
|
this.DockerRunner._runAndWaitForContainer = sinon
|
||||||
|
.stub()
|
||||||
|
.callsArgWith(3, null, (this.output = 'mock-output'))
|
||||||
|
return this.DockerRunner.run(
|
||||||
|
this.project_id,
|
||||||
|
this.command,
|
||||||
|
this.directory,
|
||||||
|
this.image,
|
||||||
|
this.timeout,
|
||||||
|
this.env,
|
||||||
|
this.compileGroup,
|
||||||
|
this.callback
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should set the docker options for the compile group', function() {
|
||||||
|
const options = this.DockerRunner._runAndWaitForContainer.lastCall
|
||||||
|
.args[0]
|
||||||
|
return expect(options.HostConfig).to.deep.include({
|
||||||
|
Binds: ['/local/compile/directory:/compile:rw'],
|
||||||
|
LogConfig: { Type: 'none', Config: {} },
|
||||||
|
CapDrop: 'ALL',
|
||||||
|
SecurityOpt: ['no-new-privileges'],
|
||||||
|
newProperty: 'new-property'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return it('should call the callback', function() {
|
||||||
|
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') }
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ describe('LatexRunner', function() {
|
|||||||
this.mainFile = 'main-file.tex'
|
this.mainFile = 'main-file.tex'
|
||||||
this.compiler = 'pdflatex'
|
this.compiler = 'pdflatex'
|
||||||
this.image = 'example.com/image'
|
this.image = 'example.com/image'
|
||||||
|
this.compileGroup = 'compile-group'
|
||||||
this.callback = sinon.stub()
|
this.callback = sinon.stub()
|
||||||
this.project_id = 'project-id-123'
|
this.project_id = 'project-id-123'
|
||||||
return (this.env = { foo: '123' })
|
return (this.env = { foo: '123' })
|
||||||
@@ -55,7 +56,7 @@ describe('LatexRunner', function() {
|
|||||||
|
|
||||||
return describe('runLatex', function() {
|
return describe('runLatex', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
return (this.CommandRunner.run = sinon.stub().callsArgWith(6, 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'
|
||||||
}))
|
}))
|
||||||
@@ -71,7 +72,8 @@ describe('LatexRunner', function() {
|
|||||||
compiler: this.compiler,
|
compiler: this.compiler,
|
||||||
timeout: (this.timeout = 42000),
|
timeout: (this.timeout = 42000),
|
||||||
image: this.image,
|
image: this.image,
|
||||||
environment: this.env
|
environment: this.env,
|
||||||
|
compileGroup: this.compileGroup
|
||||||
},
|
},
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
@@ -85,7 +87,8 @@ describe('LatexRunner', function() {
|
|||||||
this.directory,
|
this.directory,
|
||||||
this.image,
|
this.image,
|
||||||
this.timeout,
|
this.timeout,
|
||||||
this.env
|
this.env,
|
||||||
|
this.compileGroup
|
||||||
)
|
)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user