| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946 |
- const sinon = require('sinon')
- const { expect } = require('chai')
- const modulePath = '../../../../app/src/Features/Compile/CompileController.js'
- const SandboxedModule = require('sandboxed-module')
- const MockRequest = require('../helpers/MockRequest')
- const MockResponse = require('../helpers/MockResponse')
- const { Headers } = require('node-fetch')
- const { ReadableString } = require('@overleaf/stream-utils')
- describe('CompileController', function () {
- beforeEach(function () {
- this.user_id = 'wat'
- this.user = {
- _id: this.user_id,
- email: 'user@example.com',
- features: {
- compileGroup: 'premium',
- compileTimeout: 100,
- },
- }
- this.CompileManager = {
- promises: {
- compile: sinon.stub(),
- getProjectCompileLimits: sinon.stub(),
- },
- }
- this.ClsiManager = {
- promises: {},
- }
- this.UserGetter = { getUser: sinon.stub() }
- this.rateLimiter = {
- consume: sinon.stub().resolves(),
- }
- this.RateLimiter = {
- RateLimiter: sinon.stub().returns(this.rateLimiter),
- }
- this.settings = {
- apis: {
- clsi: {
- url: 'http://clsi.example.com',
- submissionBackendClass: 'n2d',
- },
- clsi_priority: {
- url: 'http://clsi-priority.example.com',
- },
- },
- defaultFeatures: {
- compileGroup: 'standard',
- compileTimeout: 60,
- },
- clsiCookie: {
- key: 'cookie-key',
- },
- }
- this.ClsiCookieManager = {
- promises: {
- getServerId: sinon.stub().resolves('clsi-server-id-from-redis'),
- },
- }
- this.SessionManager = {
- getLoggedInUserId: sinon.stub().returns(this.user_id),
- getSessionUser: sinon.stub().returns(this.user),
- isUserLoggedIn: sinon.stub().returns(true),
- }
- this.pipeline = sinon.stub().callsFake(async (stream, res) => {
- if (res.callback) res.callback()
- })
- this.clsiStream = new ReadableString('{}')
- this.clsiResponse = {
- headers: new Headers({
- 'Content-Length': '2',
- 'Content-Type': 'application/json',
- }),
- }
- this.fetchUtils = {
- fetchStreamWithResponse: sinon.stub().resolves({
- stream: this.clsiStream,
- response: this.clsiResponse,
- }),
- }
- this.CompileController = SandboxedModule.require(modulePath, {
- requires: {
- 'stream/promises': { pipeline: this.pipeline },
- '@overleaf/settings': this.settings,
- '@overleaf/fetch-utils': this.fetchUtils,
- '../Project/ProjectGetter': (this.ProjectGetter = {
- promises: {},
- }),
- '@overleaf/metrics': (this.Metrics = {
- inc: sinon.stub(),
- Timer: class {
- constructor() {
- this.labels = {}
- }
- done() {}
- },
- }),
- './CompileManager': this.CompileManager,
- '../User/UserGetter': this.UserGetter,
- './ClsiManager': this.ClsiManager,
- '../Authentication/SessionManager': this.SessionManager,
- '../../infrastructure/RateLimiter': this.RateLimiter,
- './ClsiCookieManager': () => this.ClsiCookieManager,
- '../SplitTests/SplitTestHandler': {
- getAssignment: (this.getAssignment = sinon.stub().yields(null, {
- variant: 'default',
- })),
- promises: {
- getAssignment: sinon.stub().resolves({
- variant: 'default',
- }),
- },
- },
- '../Analytics/AnalyticsManager': {
- recordEventForSession: sinon.stub(),
- },
- },
- })
- this.projectId = 'project-id'
- this.build_id = '18fbe9e7564-30dcb2f71250c690'
- this.next = sinon.stub()
- this.req = new MockRequest()
- this.res = new MockResponse()
- this.res = new MockResponse()
- })
- describe('compile', function () {
- beforeEach(function () {
- this.req.params = { Project_id: this.projectId }
- this.req.session = {}
- this.CompileManager.promises.compile = sinon.stub().resolves({
- status: (this.status = 'success'),
- outputFiles: (this.outputFiles = [
- {
- path: 'output.pdf',
- url: `/project/${this.projectId}/user/${this.user_id}/build/id/output.pdf`,
- type: 'pdf',
- },
- ]),
- clsiServerId: undefined,
- limits: undefined,
- validationProblems: undefined,
- stats: undefined,
- timings: undefined,
- outputUrlPrefix: undefined,
- buildId: this.build_id,
- })
- })
- describe('pdfDownloadDomain', function () {
- beforeEach(function () {
- this.settings.pdfDownloadDomain = 'https://compiles.overleaf.test'
- })
- describe('when clsi does not emit zone prefix', function () {
- beforeEach(async function () {
- await this.CompileController.compile(this.req, this.res, this.next)
- })
- it('should add domain verbatim', function () {
- this.res.statusCode.should.equal(200)
- this.res.body.should.equal(
- JSON.stringify({
- status: this.status,
- outputFiles: [
- {
- path: 'output.pdf',
- url: `/project/${this.projectId}/user/${this.user_id}/build/id/output.pdf`,
- type: 'pdf',
- },
- ],
- outputFilesArchive: {
- path: 'output.zip',
- url: `/project/${this.projectId}/user/wat/build/${this.build_id}/output/output.zip`,
- type: 'zip',
- },
- pdfDownloadDomain: 'https://compiles.overleaf.test',
- })
- )
- })
- })
- describe('when clsi emits a zone prefix', function () {
- beforeEach(async function () {
- this.CompileManager.promises.compile = sinon.stub().resolves({
- status: (this.status = 'success'),
- outputFiles: (this.outputFiles = [
- {
- path: 'output.pdf',
- url: `/project/${this.projectId}/user/${this.user_id}/build/id/output.pdf`,
- type: 'pdf',
- },
- ]),
- clsiServerId: undefined,
- limits: undefined,
- validationProblems: undefined,
- stats: undefined,
- timings: undefined,
- outputUrlPrefix: '/zone/b',
- buildId: this.build_id,
- })
- await this.CompileController.compile(this.req, this.res, this.next)
- })
- it('should add the zone prefix', function () {
- this.res.statusCode.should.equal(200)
- this.res.body.should.equal(
- JSON.stringify({
- status: this.status,
- outputFiles: [
- {
- path: 'output.pdf',
- url: `/project/${this.projectId}/user/${this.user_id}/build/id/output.pdf`,
- type: 'pdf',
- },
- ],
- outputFilesArchive: {
- path: 'output.zip',
- url: `/project/${this.projectId}/user/wat/build/${this.build_id}/output/output.zip`,
- type: 'zip',
- },
- outputUrlPrefix: '/zone/b',
- pdfDownloadDomain: 'https://compiles.overleaf.test/zone/b',
- })
- )
- })
- })
- })
- describe('when not an auto compile', function () {
- beforeEach(async function () {
- await this.CompileController.compile(this.req, this.res, this.next)
- })
- it('should look up the user id', function () {
- this.SessionManager.getLoggedInUserId
- .calledWith(this.req.session)
- .should.equal(true)
- })
- it('should do the compile without the auto compile flag', function () {
- this.CompileManager.promises.compile.should.have.been.calledWith(
- this.projectId,
- this.user_id,
- {
- isAutoCompile: false,
- compileFromClsiCache: false,
- populateClsiCache: false,
- enablePdfCaching: false,
- fileLineErrors: false,
- stopOnFirstError: false,
- editorId: undefined,
- }
- )
- })
- it('should set the content-type of the response to application/json', function () {
- this.res.type.should.equal('application/json')
- })
- it('should send a successful response reporting the status and files', function () {
- this.res.statusCode.should.equal(200)
- this.res.body.should.equal(
- JSON.stringify({
- status: this.status,
- outputFiles: this.outputFiles,
- outputFilesArchive: {
- path: 'output.zip',
- url: `/project/${this.projectId}/user/wat/build/${this.build_id}/output/output.zip`,
- type: 'zip',
- },
- })
- )
- })
- })
- describe('when an auto compile', function () {
- beforeEach(async function () {
- this.req.query = { auto_compile: 'true' }
- await this.CompileController.compile(this.req, this.res, this.next)
- })
- it('should do the compile with the auto compile flag', function () {
- this.CompileManager.promises.compile.should.have.been.calledWith(
- this.projectId,
- this.user_id,
- {
- isAutoCompile: true,
- compileFromClsiCache: false,
- populateClsiCache: false,
- enablePdfCaching: false,
- fileLineErrors: false,
- stopOnFirstError: false,
- editorId: undefined,
- }
- )
- })
- })
- describe('with the draft attribute', function () {
- beforeEach(async function () {
- this.req.body = { draft: true }
- await this.CompileController.compile(this.req, this.res, this.next)
- })
- it('should do the compile without the draft compile flag', function () {
- this.CompileManager.promises.compile.should.have.been.calledWith(
- this.projectId,
- this.user_id,
- {
- isAutoCompile: false,
- compileFromClsiCache: false,
- populateClsiCache: false,
- enablePdfCaching: false,
- draft: true,
- fileLineErrors: false,
- stopOnFirstError: false,
- editorId: undefined,
- }
- )
- })
- })
- describe('with an editor id', function () {
- beforeEach(async function () {
- this.req.body = { editorId: 'the-editor-id' }
- await this.CompileController.compile(this.req, this.res, this.next)
- })
- it('should pass the editor id to the compiler', function () {
- this.CompileManager.promises.compile.should.have.been.calledWith(
- this.projectId,
- this.user_id,
- {
- isAutoCompile: false,
- compileFromClsiCache: false,
- populateClsiCache: false,
- enablePdfCaching: false,
- fileLineErrors: false,
- stopOnFirstError: false,
- editorId: 'the-editor-id',
- }
- )
- })
- })
- })
- describe('compileSubmission', function () {
- beforeEach(function () {
- this.submission_id = 'sub-1234'
- this.req.params = { submission_id: this.submission_id }
- this.req.body = {}
- this.ClsiManager.promises.sendExternalRequest = sinon.stub().resolves({
- status: (this.status = 'success'),
- outputFiles: (this.outputFiles = ['mock-output-files']),
- clsiServerId: 'mock-server-id',
- validationProblems: null,
- })
- })
- it('should set the content-type of the response to application/json', async function () {
- await this.CompileController.compileSubmission(
- this.req,
- this.res,
- this.next
- )
- this.res.contentType.calledWith('application/json').should.equal(true)
- })
- it('should send a successful response reporting the status and files', async function () {
- await this.CompileController.compileSubmission(
- this.req,
- this.res,
- this.next
- )
- this.res.statusCode.should.equal(200)
- this.res.body.should.equal(
- JSON.stringify({
- status: this.status,
- outputFiles: this.outputFiles,
- clsiServerId: 'mock-server-id',
- validationProblems: null,
- })
- )
- })
- describe('with compileGroup and timeout', function () {
- beforeEach(function () {
- this.req.body = {
- compileGroup: 'special',
- timeout: 600,
- }
- this.CompileController.compileSubmission(this.req, this.res, this.next)
- })
- it('should use the supplied values', function () {
- this.ClsiManager.promises.sendExternalRequest.should.have.been.calledWith(
- this.submission_id,
- { compileGroup: 'special', timeout: 600 },
- { compileGroup: 'special', compileBackendClass: 'n2d', timeout: 600 }
- )
- })
- })
- describe('with other supported options but not compileGroup and timeout', function () {
- beforeEach(function () {
- this.req.body = {
- rootResourcePath: 'main.tex',
- compiler: 'lualatex',
- draft: true,
- check: 'validate',
- }
- this.CompileController.compileSubmission(this.req, this.res, this.next)
- })
- it('should use the other options but default values for compileGroup and timeout', function () {
- this.ClsiManager.promises.sendExternalRequest.should.have.been.calledWith(
- this.submission_id,
- {
- rootResourcePath: 'main.tex',
- compiler: 'lualatex',
- draft: true,
- check: 'validate',
- },
- {
- rootResourcePath: 'main.tex',
- compiler: 'lualatex',
- draft: true,
- check: 'validate',
- compileGroup: 'standard',
- compileBackendClass: 'n2d',
- timeout: 60,
- }
- )
- })
- })
- })
- describe('downloadPdf', function () {
- beforeEach(function () {
- this.CompileController._proxyToClsi = sinon.stub().resolves()
- this.req.params = { Project_id: this.projectId }
- this.project = { name: 'test namè; 1' }
- this.ProjectGetter.promises.getProject = sinon
- .stub()
- .resolves(this.project)
- })
- describe('when downloading for embedding', function () {
- beforeEach(async function () {
- await this.CompileController.downloadPdf(this.req, this.res, this.next)
- })
- it('should look up the project', function () {
- this.ProjectGetter.promises.getProject
- .calledWith(this.projectId, { name: 1 })
- .should.equal(true)
- })
- it('should set the content-type of the response to application/pdf', function () {
- this.res.contentType.calledWith('application/pdf').should.equal(true)
- })
- it('should set the content-disposition header with a safe version of the project name', function () {
- this.res.setContentDisposition.should.be.calledWith('inline', {
- filename: 'test_namè__1.pdf',
- })
- })
- it('should increment the pdf-downloads metric', function () {
- this.Metrics.inc.calledWith('pdf-downloads').should.equal(true)
- })
- it('should proxy the PDF from the CLSI', function () {
- this.CompileController._proxyToClsi
- .calledWith(
- this.projectId,
- 'output-file',
- `/project/${this.projectId}/user/${this.user_id}/output/output.pdf`,
- {},
- this.req,
- this.res
- )
- .should.equal(true)
- })
- })
- describe('when a build-id is provided', function () {
- beforeEach(async function () {
- this.req.params.build_id = this.build_id
- await this.CompileController.downloadPdf(this.req, this.res, this.next)
- })
- it('should proxy the PDF from the CLSI, with a build-id', function () {
- this.CompileController._proxyToClsi
- .calledWith(
- this.projectId,
- 'output-file',
- `/project/${this.projectId}/user/${this.user_id}/build/${this.build_id}/output/output.pdf`,
- {},
- this.req,
- this.res
- )
- .should.equal(true)
- })
- })
- describe('when rate-limited', function () {
- beforeEach(async function () {
- this.rateLimiter.consume.rejects({
- msBeforeNext: 250,
- remainingPoints: 0,
- consumedPoints: 5,
- isFirstInDuration: false,
- })
- })
- it('should return 500', async function () {
- await this.CompileController.downloadPdf(this.req, this.res, this.next)
- // should it be 429 instead?
- this.res.sendStatus.calledWith(500).should.equal(true)
- this.CompileController._proxyToClsi.should.not.have.been.called
- })
- })
- describe('when rate-limit errors', function () {
- beforeEach(async function () {
- this.rateLimiter.consume.rejects(new Error('uh oh'))
- })
- it('should return 500', async function () {
- await this.CompileController.downloadPdf(this.req, this.res, this.next)
- this.res.sendStatus.calledWith(500).should.equal(true)
- this.CompileController._proxyToClsi.should.not.have.been.called
- })
- })
- })
- describe('getFileFromClsiWithoutUser', function () {
- beforeEach(function () {
- this.submission_id = 'sub-1234'
- this.file = 'project.pdf'
- this.req.params = {
- submission_id: this.submission_id,
- build_id: this.build_id,
- file: this.file,
- }
- this.req.body = {}
- this.expected_url = `/project/${this.submission_id}/build/${this.build_id}/output/${this.file}`
- this.CompileController._proxyToClsiWithLimits = sinon.stub()
- })
- describe('without limits specified', function () {
- beforeEach(async function () {
- await this.CompileController.getFileFromClsiWithoutUser(
- this.req,
- this.res,
- this.next
- )
- })
- it('should proxy to CLSI with correct URL and default limits', function () {
- this.CompileController._proxyToClsiWithLimits.should.have.been.calledWith(
- this.submission_id,
- 'output-file',
- this.expected_url,
- {},
- { compileGroup: 'standard', compileBackendClass: 'n2d' }
- )
- })
- })
- describe('with limits specified', function () {
- beforeEach(function () {
- this.req.body = { compileTimeout: 600, compileGroup: 'special' }
- this.CompileController.getFileFromClsiWithoutUser(
- this.req,
- this.res,
- this.next
- )
- })
- it('should proxy to CLSI with correct URL and specified limits', function () {
- this.CompileController._proxyToClsiWithLimits.should.have.been.calledWith(
- this.submission_id,
- 'output-file',
- this.expected_url,
- {},
- {
- compileGroup: 'special',
- compileBackendClass: 'n2d',
- }
- )
- })
- })
- })
- describe('proxySyncCode', function () {
- let file, line, column, imageName, editorId, buildId
- beforeEach(async function () {
- this.req.params = { Project_id: this.projectId }
- file = 'main.tex'
- line = String(Date.now())
- column = String(Date.now() + 1)
- editorId = '172977cb-361e-4854-a4dc-a71cf11512e5'
- buildId = '195b4a3f9e7-03e5be430a9e7796'
- this.req.query = { file, line, column, editorId, buildId }
- imageName = 'foo/bar:tag-0'
- this.ProjectGetter.promises.getProject = sinon
- .stub()
- .resolves({ imageName })
- this.CompileController._proxyToClsi = sinon.stub().resolves()
- await this.CompileController.proxySyncCode(this.req, this.res, this.next)
- })
- it('should proxy the request with an imageName', function () {
- expect(this.CompileController._proxyToClsi).to.have.been.calledWith(
- this.projectId,
- 'sync-to-code',
- `/project/${this.projectId}/user/${this.user_id}/sync/code`,
- {
- file,
- line,
- column,
- imageName,
- editorId,
- buildId,
- compileFromClsiCache: false,
- },
- this.req,
- this.res
- )
- })
- })
- describe('proxySyncPdf', function () {
- let page, h, v, imageName, editorId, buildId
- beforeEach(async function () {
- this.req.params = { Project_id: this.projectId }
- page = String(Date.now())
- h = String(Math.random())
- v = String(Math.random())
- editorId = '172977cb-361e-4854-a4dc-a71cf11512e5'
- buildId = '195b4a3f9e7-03e5be430a9e7796'
- this.req.query = { page, h, v, editorId, buildId }
- imageName = 'foo/bar:tag-1'
- this.ProjectGetter.promises.getProject = sinon
- .stub()
- .resolves({ imageName })
- this.CompileController._proxyToClsi = sinon.stub()
- await this.CompileController.proxySyncPdf(this.req, this.res, this.next)
- })
- it('should proxy the request with an imageName', function () {
- expect(this.CompileController._proxyToClsi).to.have.been.calledWith(
- this.projectId,
- 'sync-to-pdf',
- `/project/${this.projectId}/user/${this.user_id}/sync/pdf`,
- {
- page,
- h,
- v,
- imageName,
- editorId,
- buildId,
- compileFromClsiCache: false,
- },
- this.req,
- this.res
- )
- })
- })
- describe('_proxyToClsi', function () {
- beforeEach(function () {
- this.req.method = 'mock-method'
- this.req.headers = {
- Mock: 'Headers',
- Range: '123-456',
- 'If-Range': 'abcdef',
- 'If-Modified-Since': 'Mon, 15 Dec 2014 15:23:56 GMT',
- }
- })
- describe('old pdf viewer', function () {
- describe('user with standard priority', function () {
- beforeEach(async function () {
- this.CompileManager.promises.getProjectCompileLimits = sinon
- .stub()
- .resolves({
- compileGroup: 'standard',
- compileBackendClass: 'e2',
- })
- await this.CompileController._proxyToClsi(
- this.projectId,
- 'output-file',
- (this.url = '/test'),
- { query: 'foo' },
- this.req,
- this.res,
- this.next
- )
- })
- it('should open a request to the CLSI', function () {
- this.fetchUtils.fetchStreamWithResponse.should.have.been.calledWith(
- `${this.settings.apis.clsi.url}${this.url}?compileGroup=standard&compileBackendClass=e2&query=foo`
- )
- })
- it('should pass the request on to the client', function () {
- this.pipeline.should.have.been.calledWith(this.clsiStream, this.res)
- })
- })
- describe('user with priority compile', function () {
- beforeEach(async function () {
- this.CompileManager.promises.getProjectCompileLimits = sinon
- .stub()
- .resolves({
- compileGroup: 'priority',
- compileBackendClass: 'c2d',
- })
- await this.CompileController._proxyToClsi(
- this.projectId,
- 'output-file',
- (this.url = '/test'),
- {},
- this.req,
- this.res,
- this.next
- )
- })
- it('should open a request to the CLSI', function () {
- this.fetchUtils.fetchStreamWithResponse.should.have.been.calledWith(
- `${this.settings.apis.clsi.url}${this.url}?compileGroup=priority&compileBackendClass=c2d`
- )
- })
- })
- describe('user with standard priority via query string', function () {
- beforeEach(async function () {
- this.req.query = { compileGroup: 'standard' }
- this.CompileManager.promises.getProjectCompileLimits = sinon
- .stub()
- .resolves({
- compileGroup: 'standard',
- compileBackendClass: 'e2',
- })
- await this.CompileController._proxyToClsi(
- this.projectId,
- 'output-file',
- (this.url = '/test'),
- {},
- this.req,
- this.res,
- this.next
- )
- })
- it('should open a request to the CLSI', function () {
- this.fetchUtils.fetchStreamWithResponse.should.have.been.calledWith(
- `${this.settings.apis.clsi.url}${this.url}?compileGroup=standard&compileBackendClass=e2`
- )
- })
- it('should pass the request on to the client', function () {
- this.pipeline.should.have.been.calledWith(this.clsiStream, this.res)
- })
- })
- describe('user with non-existent priority via query string', function () {
- beforeEach(async function () {
- this.req.query = { compileGroup: 'foobar' }
- this.CompileManager.promises.getProjectCompileLimits = sinon
- .stub()
- .resolves({
- compileGroup: 'standard',
- compileBackendClass: 'e2',
- })
- await this.CompileController._proxyToClsi(
- this.projectId,
- 'output-file',
- (this.url = '/test'),
- {},
- this.req,
- this.res,
- this.next
- )
- })
- it('should proxy to the standard url', function () {
- this.fetchUtils.fetchStreamWithResponse.should.have.been.calledWith(
- `${this.settings.apis.clsi.url}${this.url}?compileGroup=standard&compileBackendClass=e2`
- )
- })
- })
- describe('user with build parameter via query string', function () {
- beforeEach(async function () {
- this.CompileManager.promises.getProjectCompileLimits = sinon
- .stub()
- .resolves({
- compileGroup: 'standard',
- compileBackendClass: 'e2',
- })
- this.req.query = { build: 1234 }
- await this.CompileController._proxyToClsi(
- this.projectId,
- 'output-file',
- (this.url = '/test'),
- {},
- this.req,
- this.res,
- this.next
- )
- })
- it('should proxy to the standard url without the build parameter', function () {
- this.fetchUtils.fetchStreamWithResponse.should.have.been.calledWith(
- `${this.settings.apis.clsi.url}${this.url}?compileGroup=standard&compileBackendClass=e2`
- )
- })
- })
- })
- })
- describe('deleteAuxFiles', function () {
- beforeEach(async function () {
- this.CompileManager.promises.deleteAuxFiles = sinon.stub().resolves()
- this.req.params = { Project_id: this.projectId }
- this.req.query = { clsiserverid: 'node-1' }
- this.res.sendStatus = sinon.stub()
- await this.CompileController.deleteAuxFiles(this.req, this.res, this.next)
- })
- it('should proxy to the CLSI', function () {
- this.CompileManager.promises.deleteAuxFiles
- .calledWith(this.projectId, this.user_id, 'node-1')
- .should.equal(true)
- })
- it('should return a 200', function () {
- this.res.sendStatus.calledWith(200).should.equal(true)
- })
- })
- describe('compileAndDownloadPdf', function () {
- beforeEach(function () {
- this.req = {
- params: {
- project_id: this.projectId,
- },
- }
- this.downloadPath = `/project/${this.projectId}/build/123/output/output.pdf`
- this.CompileManager.promises.compile.resolves({
- status: 'success',
- outputFiles: [{ path: 'output.pdf', url: this.downloadPath }],
- })
- this.CompileController._proxyToClsi = sinon.stub()
- this.res = { send: () => {}, sendStatus: sinon.stub() }
- })
- it('should call compile in the compile manager', async function () {
- await this.CompileController.compileAndDownloadPdf(this.req, this.res)
- this.CompileManager.promises.compile
- .calledWith(this.projectId)
- .should.equal(true)
- })
- it('should proxy the res to the clsi with correct url', async function () {
- await this.CompileController.compileAndDownloadPdf(this.req, this.res)
- sinon.assert.calledWith(
- this.CompileController._proxyToClsi,
- this.projectId,
- 'output-file',
- this.downloadPath,
- {},
- this.req,
- this.res
- )
- this.CompileController._proxyToClsi
- .calledWith(
- this.projectId,
- 'output-file',
- this.downloadPath,
- {},
- this.req,
- this.res
- )
- .should.equal(true)
- })
- it('should not download anything on compilation failures', async function () {
- this.CompileManager.promises.compile.rejects(new Error('failed'))
- await this.CompileController.compileAndDownloadPdf(
- this.req,
- this.res,
- this.next
- )
- this.res.sendStatus.should.have.been.calledWith(500)
- this.CompileController._proxyToClsi.should.not.have.been.called
- })
- it('should not download anything on missing pdf', async function () {
- this.CompileManager.promises.compile.resolves({
- status: 'success',
- outputFiles: [],
- })
- await this.CompileController.compileAndDownloadPdf(this.req, this.res)
- this.res.sendStatus.should.have.been.calledWith(500)
- this.CompileController._proxyToClsi.should.not.have.been.called
- })
- })
- describe('wordCount', function () {
- beforeEach(async function () {
- this.CompileManager.promises.wordCount = sinon
- .stub()
- .resolves({ content: 'body' })
- this.req.params = { Project_id: this.projectId }
- this.req.query = { clsiserverid: 'node-42' }
- this.res.json = sinon.stub()
- this.res.contentType = sinon.stub()
- await this.CompileController.wordCount(this.req, this.res, this.next)
- })
- it('should proxy to the CLSI', function () {
- this.CompileManager.promises.wordCount
- .calledWith(this.projectId, this.user_id, false, 'node-42')
- .should.equal(true)
- })
- it('should return a 200 and body', function () {
- this.res.json.calledWith({ content: 'body' }).should.equal(true)
- })
- })
- })
|