LatexRunnerTests.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. const SandboxedModule = require('sandboxed-module')
  2. const sinon = require('sinon')
  3. const { expect } = require('chai')
  4. const MODULE_PATH = require('path').join(
  5. __dirname,
  6. '../../../app/js/LatexRunner'
  7. )
  8. describe('LatexRunner', function () {
  9. beforeEach(function () {
  10. this.Settings = {
  11. docker: {
  12. socketPath: '/var/run/docker.sock',
  13. },
  14. }
  15. this.commandRunnerOutput = {
  16. stdout: 'this is stdout',
  17. stderr: 'this is stderr',
  18. }
  19. this.CommandRunner = {
  20. run: sinon.stub().yields(null, this.commandRunnerOutput),
  21. }
  22. this.fs = {
  23. writeFile: sinon.stub().yields(),
  24. }
  25. this.LatexRunner = SandboxedModule.require(MODULE_PATH, {
  26. requires: {
  27. '@overleaf/settings': this.Settings,
  28. './CommandRunner': this.CommandRunner,
  29. fs: this.fs,
  30. },
  31. })
  32. this.directory = '/local/compile/directory'
  33. this.mainFile = 'main-file.tex'
  34. this.compiler = 'pdflatex'
  35. this.image = 'example.com/image'
  36. this.compileGroup = 'compile-group'
  37. this.callback = sinon.stub()
  38. this.project_id = 'project-id-123'
  39. this.env = { foo: '123' }
  40. this.timeout = 42000
  41. this.flags = []
  42. this.stopOnFirstError = false
  43. this.call = function (callback) {
  44. this.LatexRunner.runLatex(
  45. this.project_id,
  46. {
  47. directory: this.directory,
  48. mainFile: this.mainFile,
  49. compiler: this.compiler,
  50. timeout: this.timeout,
  51. image: this.image,
  52. environment: this.env,
  53. compileGroup: this.compileGroup,
  54. flags: this.flags,
  55. stopOnFirstError: this.stopOnFirstError,
  56. },
  57. (error, output, stats, timings) => {
  58. this.timings = timings
  59. callback(error)
  60. }
  61. )
  62. }
  63. })
  64. describe('runLatex', function () {
  65. describe('normally', function () {
  66. beforeEach(function (done) {
  67. this.call(done)
  68. })
  69. it('should run the latex command', function () {
  70. this.CommandRunner.run.should.have.been.calledWith(
  71. this.project_id,
  72. [
  73. 'latexmk',
  74. '-cd',
  75. '-jobname=output',
  76. '-auxdir=$COMPILE_DIR',
  77. '-outdir=$COMPILE_DIR',
  78. '-synctex=1',
  79. '-interaction=batchmode',
  80. '-f',
  81. '-pdf',
  82. '$COMPILE_DIR/main-file.tex',
  83. ],
  84. this.directory,
  85. this.image,
  86. this.timeout,
  87. this.env,
  88. this.compileGroup
  89. )
  90. })
  91. it('should record the stdout and stderr', function () {
  92. this.fs.writeFile.should.have.been.calledWith(
  93. this.directory + '/' + 'output.stdout',
  94. 'this is stdout'
  95. )
  96. this.fs.writeFile.should.have.been.calledWith(
  97. this.directory + '/' + 'output.stderr',
  98. 'this is stderr'
  99. )
  100. })
  101. it('should not record cpu metrics', function () {
  102. expect(this.timings['cpu-percent']).to.not.exist
  103. expect(this.timings['cpu-time']).to.not.exist
  104. expect(this.timings['sys-time']).to.not.exist
  105. })
  106. })
  107. describe('with a different compiler', function () {
  108. beforeEach(function (done) {
  109. this.compiler = 'lualatex'
  110. this.call(done)
  111. })
  112. it('should set the appropriate latexmk flag', function () {
  113. this.CommandRunner.run.should.have.been.calledWith(this.project_id, [
  114. 'latexmk',
  115. '-cd',
  116. '-jobname=output',
  117. '-auxdir=$COMPILE_DIR',
  118. '-outdir=$COMPILE_DIR',
  119. '-synctex=1',
  120. '-interaction=batchmode',
  121. '-f',
  122. '-lualatex',
  123. '$COMPILE_DIR/main-file.tex',
  124. ])
  125. })
  126. })
  127. describe('with time -v', function () {
  128. beforeEach(function (done) {
  129. this.commandRunnerOutput.stderr =
  130. '\tCommand being timed: "sh -c timeout 1 yes > /dev/null"\n' +
  131. '\tUser time (seconds): 0.28\n' +
  132. '\tSystem time (seconds): 0.70\n' +
  133. '\tPercent of CPU this job got: 98%\n'
  134. this.call(done)
  135. })
  136. it('should record cpu metrics', function () {
  137. expect(this.timings['cpu-percent']).to.equal(98)
  138. expect(this.timings['cpu-time']).to.equal(0.28)
  139. expect(this.timings['sys-time']).to.equal(0.7)
  140. })
  141. })
  142. describe('with an .Rtex main file', function () {
  143. beforeEach(function (done) {
  144. this.mainFile = 'main-file.Rtex'
  145. this.call(done)
  146. })
  147. it('should run the latex command on the equivalent .tex file', function () {
  148. const command = this.CommandRunner.run.args[0][1]
  149. const mainFile = command.slice(-1)[0]
  150. mainFile.should.equal('$COMPILE_DIR/main-file.tex')
  151. })
  152. })
  153. describe('with a flags option', function () {
  154. beforeEach(function (done) {
  155. this.flags = ['-shell-restricted', '-halt-on-error']
  156. this.call(done)
  157. })
  158. it('should include the flags in the command', function () {
  159. const command = this.CommandRunner.run.args[0][1]
  160. const flags = command.filter(
  161. arg => arg === '-shell-restricted' || arg === '-halt-on-error'
  162. )
  163. flags.length.should.equal(2)
  164. flags[0].should.equal('-shell-restricted')
  165. flags[1].should.equal('-halt-on-error')
  166. })
  167. })
  168. describe('with the stopOnFirstError option', function () {
  169. beforeEach(function (done) {
  170. this.stopOnFirstError = true
  171. this.call(done)
  172. })
  173. it('should set the appropriate flags', function () {
  174. this.CommandRunner.run.should.have.been.calledWith(this.project_id, [
  175. 'latexmk',
  176. '-cd',
  177. '-jobname=output',
  178. '-auxdir=$COMPILE_DIR',
  179. '-outdir=$COMPILE_DIR',
  180. '-synctex=1',
  181. '-interaction=batchmode',
  182. '-halt-on-error',
  183. '-pdf',
  184. '$COMPILE_DIR/main-file.tex',
  185. ])
  186. })
  187. })
  188. })
  189. })