From 79a0891feeacbaaa8f63fb07d56a99f34569183c Mon Sep 17 00:00:00 2001 From: decaffeinate Date: Wed, 19 Feb 2020 12:15:08 +0100 Subject: [PATCH] decaffeinate: Convert CompileControllerTests.coffee and 17 other files to JS --- test/unit/coffee/CompileControllerTests.js | 418 ++++---- test/unit/coffee/CompileManagerTests.js | 646 ++++++------ test/unit/coffee/ContentTypeMapperTests.js | 100 +- test/unit/coffee/DockerLockManagerTests.js | 303 +++--- test/unit/coffee/DockerRunnerTests.js | 947 ++++++++++-------- test/unit/coffee/DraftModeManagerTests.js | 124 ++- test/unit/coffee/LatexRunnerTests.js | 162 +-- test/unit/coffee/LockManagerTests.js | 108 +- test/unit/coffee/OutputFileFinderTests.js | 122 ++- test/unit/coffee/OutputFileOptimiserTests.js | 198 ++-- .../coffee/ProjectPersistenceManagerTests.js | 120 ++- test/unit/coffee/RequestParserTests.js | 535 ++++++---- test/unit/coffee/ResourceStateManagerTests.js | 210 ++-- test/unit/coffee/ResourceWriterTests.js | 567 ++++++----- .../coffee/StaticServerForbidSymlinksTests.js | 295 +++--- test/unit/coffee/TikzManager.js | 229 +++-- test/unit/coffee/UrlCacheTests.js | 374 ++++--- test/unit/coffee/UrlFetcherTests.js | 234 +++-- 18 files changed, 3291 insertions(+), 2401 deletions(-) diff --git a/test/unit/coffee/CompileControllerTests.js b/test/unit/coffee/CompileControllerTests.js index 034adfc..1defed7 100644 --- a/test/unit/coffee/CompileControllerTests.js +++ b/test/unit/coffee/CompileControllerTests.js @@ -1,217 +1,269 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/CompileController' -tk = require("timekeeper") +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/CompileController'); +const tk = require("timekeeper"); -describe "CompileController", -> - beforeEach -> - @CompileController = SandboxedModule.require modulePath, requires: - "./CompileManager": @CompileManager = {} - "./RequestParser": @RequestParser = {} - "settings-sharelatex": @Settings = - apis: - clsi: +describe("CompileController", function() { + beforeEach(function() { + this.CompileController = SandboxedModule.require(modulePath, { requires: { + "./CompileManager": (this.CompileManager = {}), + "./RequestParser": (this.RequestParser = {}), + "settings-sharelatex": (this.Settings = { + apis: { + clsi: { url: "http://clsi.example.com" - "./ProjectPersistenceManager": @ProjectPersistenceManager = {} - "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub(), err:sinon.stub(), warn: sinon.stub()} - @Settings.externalUrl = "http://www.example.com" - @req = {} - @res = {} - @next = sinon.stub() + } + } + }), + "./ProjectPersistenceManager": (this.ProjectPersistenceManager = {}), + "logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub(), err:sinon.stub(), warn: sinon.stub()}) + } + }); + this.Settings.externalUrl = "http://www.example.com"; + this.req = {}; + this.res = {}; + return this.next = sinon.stub(); + }); - describe "compile", -> - beforeEach -> - @req.body = { + describe("compile", function() { + beforeEach(function() { + this.req.body = { compile: "mock-body" - } - @req.params = - project_id: @project_id = "project-id-123" - @request = { + }; + this.req.params = + {project_id: (this.project_id = "project-id-123")}; + this.request = { compile: "mock-parsed-request" - } - @request_with_project_id = - compile: @request.compile - project_id: @project_id - @output_files = [{ - path: "output.pdf" - type: "pdf" + }; + this.request_with_project_id = { + compile: this.request.compile, + project_id: this.project_id + }; + this.output_files = [{ + path: "output.pdf", + type: "pdf", build: 1234 }, { - path: "output.log" - type: "log" + path: "output.log", + type: "log", build: 1234 - }] - @RequestParser.parse = sinon.stub().callsArgWith(1, null, @request) - @ProjectPersistenceManager.markProjectAsJustAccessed = sinon.stub().callsArg(1) - @res.status = sinon.stub().returnsThis() - @res.send = sinon.stub() + }]; + this.RequestParser.parse = sinon.stub().callsArgWith(1, null, this.request); + this.ProjectPersistenceManager.markProjectAsJustAccessed = sinon.stub().callsArg(1); + this.res.status = sinon.stub().returnsThis(); + return this.res.send = sinon.stub(); + }); - describe "successfully", -> - beforeEach -> - @CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, null, @output_files) - @CompileController.compile @req, @res + describe("successfully", function() { + beforeEach(function() { + this.CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, null, this.output_files); + return this.CompileController.compile(this.req, this.res); + }); - it "should parse the request", -> - @RequestParser.parse - .calledWith(@req.body) - .should.equal true + it("should parse the request", function() { + return this.RequestParser.parse + .calledWith(this.req.body) + .should.equal(true); + }); - it "should run the compile for the specified project", -> - @CompileManager.doCompileWithLock - .calledWith(@request_with_project_id) - .should.equal true + it("should run the compile for the specified project", function() { + return this.CompileManager.doCompileWithLock + .calledWith(this.request_with_project_id) + .should.equal(true); + }); - it "should mark the project as accessed", -> - @ProjectPersistenceManager.markProjectAsJustAccessed - .calledWith(@project_id) - .should.equal true + it("should mark the project as accessed", function() { + return this.ProjectPersistenceManager.markProjectAsJustAccessed + .calledWith(this.project_id) + .should.equal(true); + }); - it "should return the JSON response", -> - @res.status.calledWith(200).should.equal true - @res.send - .calledWith( - compile: - status: "success" - error: null - outputFiles: @output_files.map (file) => - url: "#{@Settings.apis.clsi.url}/project/#{@project_id}/build/#{file.build}/output/#{file.path}" - path: file.path - type: file.type - build: file.build - ) - .should.equal true + return it("should return the JSON response", function() { + this.res.status.calledWith(200).should.equal(true); + return this.res.send + .calledWith({ + compile: { + status: "success", + error: null, + outputFiles: this.output_files.map(file => { + return { + url: `${this.Settings.apis.clsi.url}/project/${this.project_id}/build/${file.build}/output/${file.path}`, + path: file.path, + type: file.type, + build: file.build + }; + }) + } + }) + .should.equal(true); + }); + }); - describe "with an error", -> - beforeEach -> - @CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, new Error(@message = "error message"), null) - @CompileController.compile @req, @res + describe("with an error", function() { + beforeEach(function() { + this.CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, new Error(this.message = "error message"), null); + return this.CompileController.compile(this.req, this.res); + }); - it "should return the JSON response with the error", -> - @res.status.calledWith(500).should.equal true - @res.send - .calledWith( - compile: - status: "error" - error: @message + return it("should return the JSON response with the error", function() { + this.res.status.calledWith(500).should.equal(true); + return this.res.send + .calledWith({ + compile: { + status: "error", + error: this.message, outputFiles: [] - ) - .should.equal true + } + }) + .should.equal(true); + }); + }); - describe "when the request times out", -> - beforeEach -> - @error = new Error(@message = "container timed out") - @error.timedout = true - @CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, @error, null) - @CompileController.compile @req, @res + describe("when the request times out", function() { + beforeEach(function() { + this.error = new Error(this.message = "container timed out"); + this.error.timedout = true; + this.CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, this.error, null); + return this.CompileController.compile(this.req, this.res); + }); - it "should return the JSON response with the timeout status", -> - @res.status.calledWith(200).should.equal true - @res.send - .calledWith( - compile: - status: "timedout" - error: @message + return it("should return the JSON response with the timeout status", function() { + this.res.status.calledWith(200).should.equal(true); + return this.res.send + .calledWith({ + compile: { + status: "timedout", + error: this.message, outputFiles: [] - ) - .should.equal true + } + }) + .should.equal(true); + }); + }); - describe "when the request returns no output files", -> - beforeEach -> - @CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, null, []) - @CompileController.compile @req, @res + return describe("when the request returns no output files", function() { + beforeEach(function() { + this.CompileManager.doCompileWithLock = sinon.stub().callsArgWith(1, null, []); + return this.CompileController.compile(this.req, this.res); + }); - it "should return the JSON response with the failure status", -> - @res.status.calledWith(200).should.equal true - @res.send - .calledWith( - compile: - error: null - status: "failure" + return it("should return the JSON response with the failure status", function() { + this.res.status.calledWith(200).should.equal(true); + return this.res.send + .calledWith({ + compile: { + error: null, + status: "failure", outputFiles: [] - ) - .should.equal true + } + }) + .should.equal(true); + }); + }); + }); - describe "syncFromCode", -> - beforeEach -> - @file = "main.tex" - @line = 42 - @column = 5 - @project_id = "mock-project-id" - @req.params = - project_id: @project_id - @req.query = - file: @file - line: @line.toString() - column: @column.toString() - @res.json = sinon.stub() + describe("syncFromCode", function() { + beforeEach(function() { + this.file = "main.tex"; + this.line = 42; + this.column = 5; + this.project_id = "mock-project-id"; + this.req.params = + {project_id: this.project_id}; + this.req.query = { + file: this.file, + line: this.line.toString(), + column: this.column.toString() + }; + this.res.json = sinon.stub(); - @CompileManager.syncFromCode = sinon.stub().callsArgWith(5, null, @pdfPositions = ["mock-positions"]) - @CompileController.syncFromCode @req, @res, @next + this.CompileManager.syncFromCode = sinon.stub().callsArgWith(5, null, (this.pdfPositions = ["mock-positions"])); + return this.CompileController.syncFromCode(this.req, this.res, this.next); + }); - it "should find the corresponding location in the PDF", -> - @CompileManager.syncFromCode - .calledWith(@project_id, undefined, @file, @line, @column) - .should.equal true + it("should find the corresponding location in the PDF", function() { + return this.CompileManager.syncFromCode + .calledWith(this.project_id, undefined, this.file, this.line, this.column) + .should.equal(true); + }); - it "should return the positions", -> - @res.json - .calledWith( - pdf: @pdfPositions - ) - .should.equal true + return it("should return the positions", function() { + return this.res.json + .calledWith({ + pdf: this.pdfPositions + }) + .should.equal(true); + }); + }); - describe "syncFromPdf", -> - beforeEach -> - @page = 5 - @h = 100.23 - @v = 45.67 - @project_id = "mock-project-id" - @req.params = - project_id: @project_id - @req.query = - page: @page.toString() - h: @h.toString() - v: @v.toString() - @res.json = sinon.stub() + describe("syncFromPdf", function() { + beforeEach(function() { + this.page = 5; + this.h = 100.23; + this.v = 45.67; + this.project_id = "mock-project-id"; + this.req.params = + {project_id: this.project_id}; + this.req.query = { + page: this.page.toString(), + h: this.h.toString(), + v: this.v.toString() + }; + this.res.json = sinon.stub(); - @CompileManager.syncFromPdf = sinon.stub().callsArgWith(5, null, @codePositions = ["mock-positions"]) - @CompileController.syncFromPdf @req, @res, @next + this.CompileManager.syncFromPdf = sinon.stub().callsArgWith(5, null, (this.codePositions = ["mock-positions"])); + return this.CompileController.syncFromPdf(this.req, this.res, this.next); + }); - it "should find the corresponding location in the code", -> - @CompileManager.syncFromPdf - .calledWith(@project_id, undefined, @page, @h, @v) - .should.equal true + it("should find the corresponding location in the code", function() { + return this.CompileManager.syncFromPdf + .calledWith(this.project_id, undefined, this.page, this.h, this.v) + .should.equal(true); + }); - it "should return the positions", -> - @res.json - .calledWith( - code: @codePositions - ) - .should.equal true + return it("should return the positions", function() { + return this.res.json + .calledWith({ + code: this.codePositions + }) + .should.equal(true); + }); + }); - describe "wordcount", -> - beforeEach -> - @file = "main.tex" - @project_id = "mock-project-id" - @req.params = - project_id: @project_id - @req.query = - file: @file - image: @image = "example.com/image" - @res.json = sinon.stub() + return describe("wordcount", function() { + beforeEach(function() { + this.file = "main.tex"; + this.project_id = "mock-project-id"; + this.req.params = + {project_id: this.project_id}; + this.req.query = { + file: this.file, + image: (this.image = "example.com/image") + }; + this.res.json = sinon.stub(); - @CompileManager.wordcount = sinon.stub().callsArgWith(4, null, @texcount = ["mock-texcount"]) - @CompileController.wordcount @req, @res, @next + this.CompileManager.wordcount = sinon.stub().callsArgWith(4, null, (this.texcount = ["mock-texcount"])); + return this.CompileController.wordcount(this.req, this.res, this.next); + }); - it "should return the word count of a file", -> - @CompileManager.wordcount - .calledWith(@project_id, undefined, @file, @image) - .should.equal true + it("should return the word count of a file", function() { + return this.CompileManager.wordcount + .calledWith(this.project_id, undefined, this.file, this.image) + .should.equal(true); + }); - it "should return the texcount info", -> - @res.json - .calledWith( - texcount: @texcount - ) - .should.equal true + return it("should return the texcount info", function() { + return this.res.json + .calledWith({ + texcount: this.texcount + }) + .should.equal(true); + }); + }); +}); diff --git a/test/unit/coffee/CompileManagerTests.js b/test/unit/coffee/CompileManagerTests.js index c4b0f85..5675ac1 100644 --- a/test/unit/coffee/CompileManagerTests.js +++ b/test/unit/coffee/CompileManagerTests.js @@ -1,356 +1,426 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/CompileManager' -tk = require("timekeeper") -EventEmitter = require("events").EventEmitter -Path = require "path" +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/CompileManager'); +const tk = require("timekeeper"); +const { EventEmitter } = require("events"); +const Path = require("path"); -describe "CompileManager", -> - beforeEach -> - @CompileManager = SandboxedModule.require modulePath, requires: - "./LatexRunner": @LatexRunner = {} - "./ResourceWriter": @ResourceWriter = {} - "./OutputFileFinder": @OutputFileFinder = {} - "./OutputCacheManager": @OutputCacheManager = {} - "settings-sharelatex": @Settings = - path: +describe("CompileManager", function() { + beforeEach(function() { + this.CompileManager = SandboxedModule.require(modulePath, { requires: { + "./LatexRunner": (this.LatexRunner = {}), + "./ResourceWriter": (this.ResourceWriter = {}), + "./OutputFileFinder": (this.OutputFileFinder = {}), + "./OutputCacheManager": (this.OutputCacheManager = {}), + "settings-sharelatex": (this.Settings = { + path: { compilesDir: "/compiles/dir" - synctexBaseDir: -> "/compile" - clsi: - docker: + }, + synctexBaseDir() { return "/compile"; }, + clsi: { + docker: { image: "SOMEIMAGE" + } + } + }), - "logger-sharelatex": @logger = { log: sinon.stub() , info:->} - "child_process": @child_process = {} - "./CommandRunner": @CommandRunner = {} - "./DraftModeManager": @DraftModeManager = {} - "./TikzManager": @TikzManager = {} - "./LockManager": @LockManager = {} - "fs": @fs = {} - "fs-extra": @fse = { ensureDir: sinon.stub().callsArg(1) } - @callback = sinon.stub() - @project_id = "project-id-123" - @user_id = "1234" - describe "doCompileWithLock", -> - beforeEach -> - @request = - resources: @resources = "mock-resources" - project_id: @project_id - user_id: @user_id - @output_files = ["foo", "bar"] - @Settings.compileDir = "compiles" - @compileDir = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}" - @CompileManager.doCompile = sinon.stub().callsArgWith(1, null, @output_files) - @LockManager.runWithLock = (lockFile, runner, callback) -> - runner (err, result...) -> - callback(err, result...) + "logger-sharelatex": (this.logger = { log: sinon.stub() , info() {}}), + "child_process": (this.child_process = {}), + "./CommandRunner": (this.CommandRunner = {}), + "./DraftModeManager": (this.DraftModeManager = {}), + "./TikzManager": (this.TikzManager = {}), + "./LockManager": (this.LockManager = {}), + "fs": (this.fs = {}), + "fs-extra": (this.fse = { ensureDir: sinon.stub().callsArg(1) }) + } + }); + this.callback = sinon.stub(); + this.project_id = "project-id-123"; + return this.user_id = "1234"; + }); + describe("doCompileWithLock", function() { + beforeEach(function() { + this.request = { + resources: (this.resources = "mock-resources"), + project_id: this.project_id, + user_id: this.user_id + }; + this.output_files = ["foo", "bar"]; + this.Settings.compileDir = "compiles"; + this.compileDir = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`; + this.CompileManager.doCompile = sinon.stub().callsArgWith(1, null, this.output_files); + return this.LockManager.runWithLock = (lockFile, runner, callback) => + runner((err, ...result) => callback(err, ...Array.from(result))) + ; + }); - describe "when the project is not locked", -> - beforeEach -> - @CompileManager.doCompileWithLock @request, @callback + describe("when the project is not locked", function() { + beforeEach(function() { + return this.CompileManager.doCompileWithLock(this.request, this.callback); + }); - it "should ensure that the compile directory exists", -> - @fse.ensureDir.calledWith(@compileDir) - .should.equal true + it("should ensure that the compile directory exists", function() { + return this.fse.ensureDir.calledWith(this.compileDir) + .should.equal(true); + }); - it "should call doCompile with the request", -> - @CompileManager.doCompile - .calledWith(@request) - .should.equal true + it("should call doCompile with the request", function() { + return this.CompileManager.doCompile + .calledWith(this.request) + .should.equal(true); + }); - it "should call the callback with the output files", -> - @callback.calledWithExactly(null, @output_files) - .should.equal true + return it("should call the callback with the output files", function() { + return this.callback.calledWithExactly(null, this.output_files) + .should.equal(true); + }); + }); - describe "when the project is locked", -> - beforeEach -> - @error = new Error("locked") - @LockManager.runWithLock = (lockFile, runner, callback) => - callback(@error) - @CompileManager.doCompileWithLock @request, @callback + return describe("when the project is locked", function() { + beforeEach(function() { + this.error = new Error("locked"); + this.LockManager.runWithLock = (lockFile, runner, callback) => { + return callback(this.error); + }; + return this.CompileManager.doCompileWithLock(this.request, this.callback); + }); - it "should ensure that the compile directory exists", -> - @fse.ensureDir.calledWith(@compileDir) - .should.equal true + it("should ensure that the compile directory exists", function() { + return this.fse.ensureDir.calledWith(this.compileDir) + .should.equal(true); + }); - it "should not call doCompile with the request", -> - @CompileManager.doCompile - .called.should.equal false + it("should not call doCompile with the request", function() { + return this.CompileManager.doCompile + .called.should.equal(false); + }); - it "should call the callback with the error", -> - @callback.calledWithExactly(@error) - .should.equal true + return it("should call the callback with the error", function() { + return this.callback.calledWithExactly(this.error) + .should.equal(true); + }); + }); + }); - describe "doCompile", -> - beforeEach -> - @output_files = [{ - path: "output.log" + describe("doCompile", function() { + beforeEach(function() { + this.output_files = [{ + path: "output.log", type: "log" }, { - path: "output.pdf" + path: "output.pdf", type: "pdf" - }] - @build_files = [{ - path: "output.log" - type: "log" + }]; + this.build_files = [{ + path: "output.log", + type: "log", build: 1234 }, { - path: "output.pdf" - type: "pdf" + path: "output.pdf", + type: "pdf", build: 1234 - }] - @request = - resources: @resources = "mock-resources" - rootResourcePath: @rootResourcePath = "main.tex" - project_id: @project_id - user_id: @user_id - compiler: @compiler = "pdflatex" - timeout: @timeout = 42000 - imageName: @image = "example.com/image" - flags: @flags = ["-file-line-error"] - @env = {} - @Settings.compileDir = "compiles" - @compileDir = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}" - @ResourceWriter.syncResourcesToDisk = sinon.stub().callsArgWith(2, null, @resources) - @LatexRunner.runLatex = sinon.stub().callsArg(2) - @OutputFileFinder.findOutputFiles = sinon.stub().callsArgWith(2, null, @output_files) - @OutputCacheManager.saveOutputFiles = sinon.stub().callsArgWith(2, null, @build_files) - @DraftModeManager.injectDraftMode = sinon.stub().callsArg(1) - @TikzManager.checkMainFile = sinon.stub().callsArg(3, false) + }]; + this.request = { + resources: (this.resources = "mock-resources"), + rootResourcePath: (this.rootResourcePath = "main.tex"), + project_id: this.project_id, + user_id: this.user_id, + compiler: (this.compiler = "pdflatex"), + timeout: (this.timeout = 42000), + imageName: (this.image = "example.com/image"), + flags: (this.flags = ["-file-line-error"]) + }; + this.env = {}; + this.Settings.compileDir = "compiles"; + this.compileDir = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`; + this.ResourceWriter.syncResourcesToDisk = sinon.stub().callsArgWith(2, null, this.resources); + this.LatexRunner.runLatex = sinon.stub().callsArg(2); + this.OutputFileFinder.findOutputFiles = sinon.stub().callsArgWith(2, null, this.output_files); + this.OutputCacheManager.saveOutputFiles = sinon.stub().callsArgWith(2, null, this.build_files); + this.DraftModeManager.injectDraftMode = sinon.stub().callsArg(1); + return this.TikzManager.checkMainFile = sinon.stub().callsArg(3, false); + }); - describe "normally", -> - beforeEach -> - @CompileManager.doCompile @request, @callback + describe("normally", function() { + beforeEach(function() { + return this.CompileManager.doCompile(this.request, this.callback); + }); - it "should write the resources to disk", -> - @ResourceWriter.syncResourcesToDisk - .calledWith(@request, @compileDir) - .should.equal true + it("should write the resources to disk", function() { + return this.ResourceWriter.syncResourcesToDisk + .calledWith(this.request, this.compileDir) + .should.equal(true); + }); - it "should run LaTeX", -> - @LatexRunner.runLatex - .calledWith("#{@project_id}-#{@user_id}", { - directory: @compileDir - mainFile: @rootResourcePath - compiler: @compiler - timeout: @timeout - image: @image - flags: @flags - environment: @env + it("should run LaTeX", function() { + return this.LatexRunner.runLatex + .calledWith(`${this.project_id}-${this.user_id}`, { + directory: this.compileDir, + mainFile: this.rootResourcePath, + compiler: this.compiler, + timeout: this.timeout, + image: this.image, + flags: this.flags, + environment: this.env }) - .should.equal true + .should.equal(true); + }); - it "should find the output files", -> - @OutputFileFinder.findOutputFiles - .calledWith(@resources, @compileDir) - .should.equal true + it("should find the output files", function() { + return this.OutputFileFinder.findOutputFiles + .calledWith(this.resources, this.compileDir) + .should.equal(true); + }); - it "should return the output files", -> - @callback.calledWith(null, @build_files).should.equal true + it("should return the output files", function() { + return this.callback.calledWith(null, this.build_files).should.equal(true); + }); - it "should not inject draft mode by default", -> - @DraftModeManager.injectDraftMode.called.should.equal false + return it("should not inject draft mode by default", function() { + return this.DraftModeManager.injectDraftMode.called.should.equal(false); + }); + }); - describe "with draft mode", -> - beforeEach -> - @request.draft = true - @CompileManager.doCompile @request, @callback + describe("with draft mode", function() { + beforeEach(function() { + this.request.draft = true; + return this.CompileManager.doCompile(this.request, this.callback); + }); - it "should inject the draft mode header", -> - @DraftModeManager.injectDraftMode - .calledWith(@compileDir + "/" + @rootResourcePath) - .should.equal true + return it("should inject the draft mode header", function() { + return this.DraftModeManager.injectDraftMode + .calledWith(this.compileDir + "/" + this.rootResourcePath) + .should.equal(true); + }); + }); - describe "with a check option", -> - beforeEach -> - @request.check = "error" - @CompileManager.doCompile @request, @callback + describe("with a check option", function() { + beforeEach(function() { + this.request.check = "error"; + return this.CompileManager.doCompile(this.request, this.callback); + }); - it "should run chktex", -> - @LatexRunner.runLatex - .calledWith("#{@project_id}-#{@user_id}", { - directory: @compileDir - mainFile: @rootResourcePath - compiler: @compiler - timeout: @timeout - image: @image - flags: @flags + return it("should run chktex", function() { + return this.LatexRunner.runLatex + .calledWith(`${this.project_id}-${this.user_id}`, { + directory: this.compileDir, + mainFile: this.rootResourcePath, + compiler: this.compiler, + timeout: this.timeout, + image: this.image, + flags: this.flags, environment: {'CHKTEX_OPTIONS': '-nall -e9 -e10 -w15 -w16', 'CHKTEX_EXIT_ON_ERROR':1, 'CHKTEX_ULIMIT_OPTIONS': '-t 5 -v 64000'} }) - .should.equal true + .should.equal(true); + }); + }); - describe "with a knitr file and check options", -> - beforeEach -> - @request.rootResourcePath = "main.Rtex" - @request.check = "error" - @CompileManager.doCompile @request, @callback + return describe("with a knitr file and check options", function() { + beforeEach(function() { + this.request.rootResourcePath = "main.Rtex"; + this.request.check = "error"; + return this.CompileManager.doCompile(this.request, this.callback); + }); - it "should not run chktex", -> - @LatexRunner.runLatex - .calledWith("#{@project_id}-#{@user_id}", { - directory: @compileDir - mainFile: "main.Rtex" - compiler: @compiler - timeout: @timeout - image: @image - flags: @flags - environment: @env + return it("should not run chktex", function() { + return this.LatexRunner.runLatex + .calledWith(`${this.project_id}-${this.user_id}`, { + directory: this.compileDir, + mainFile: "main.Rtex", + compiler: this.compiler, + timeout: this.timeout, + image: this.image, + flags: this.flags, + environment: this.env }) - .should.equal true + .should.equal(true); + }); + }); + }); - describe "clearProject", -> - describe "succesfully", -> - beforeEach -> - @Settings.compileDir = "compiles" - @fs.lstat = sinon.stub().callsArgWith(1, null,{isDirectory: ()->true}) - @proc = new EventEmitter() - @proc.stdout = new EventEmitter() - @proc.stderr = new EventEmitter() - @child_process.spawn = sinon.stub().returns(@proc) - @CompileManager.clearProject @project_id, @user_id, @callback - @proc.emit "close", 0 + describe("clearProject", function() { + describe("succesfully", function() { + beforeEach(function() { + this.Settings.compileDir = "compiles"; + this.fs.lstat = sinon.stub().callsArgWith(1, null,{isDirectory(){ return true; }}); + this.proc = new EventEmitter(); + this.proc.stdout = new EventEmitter(); + this.proc.stderr = new EventEmitter(); + this.child_process.spawn = sinon.stub().returns(this.proc); + this.CompileManager.clearProject(this.project_id, this.user_id, this.callback); + return this.proc.emit("close", 0); + }); - it "should remove the project directory", -> - @child_process.spawn - .calledWith("rm", ["-r", "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}"]) - .should.equal true + it("should remove the project directory", function() { + return this.child_process.spawn + .calledWith("rm", ["-r", `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`]) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "with a non-success status code", -> - beforeEach -> - @Settings.compileDir = "compiles" - @fs.lstat = sinon.stub().callsArgWith(1, null,{isDirectory: ()->true}) - @proc = new EventEmitter() - @proc.stdout = new EventEmitter() - @proc.stderr = new EventEmitter() - @child_process.spawn = sinon.stub().returns(@proc) - @CompileManager.clearProject @project_id, @user_id, @callback - @proc.stderr.emit "data", @error = "oops" - @proc.emit "close", 1 + return describe("with a non-success status code", function() { + beforeEach(function() { + this.Settings.compileDir = "compiles"; + this.fs.lstat = sinon.stub().callsArgWith(1, null,{isDirectory(){ return true; }}); + this.proc = new EventEmitter(); + this.proc.stdout = new EventEmitter(); + this.proc.stderr = new EventEmitter(); + this.child_process.spawn = sinon.stub().returns(this.proc); + this.CompileManager.clearProject(this.project_id, this.user_id, this.callback); + this.proc.stderr.emit("data", (this.error = "oops")); + return this.proc.emit("close", 1); + }); - it "should remove the project directory", -> - @child_process.spawn - .calledWith("rm", ["-r", "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}"]) - .should.equal true + it("should remove the project directory", function() { + return this.child_process.spawn + .calledWith("rm", ["-r", `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`]) + .should.equal(true); + }); - it "should call the callback with an error from the stderr", -> - @callback + return it("should call the callback with an error from the stderr", function() { + this.callback .calledWith(new Error()) - .should.equal true + .should.equal(true); - @callback.args[0][0].message.should.equal "rm -r #{@Settings.path.compilesDir}/#{@project_id}-#{@user_id} failed: #{@error}" + return this.callback.args[0][0].message.should.equal(`rm -r ${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id} failed: ${this.error}`); + }); + }); + }); - describe "syncing", -> - beforeEach -> - @page = 1 - @h = 42.23 - @v = 87.56 - @width = 100.01 - @height = 234.56 - @line = 5 - @column = 3 - @file_name = "main.tex" - @child_process.execFile = sinon.stub() - @Settings.path.synctexBaseDir = (project_id) => "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}" + describe("syncing", function() { + beforeEach(function() { + this.page = 1; + this.h = 42.23; + this.v = 87.56; + this.width = 100.01; + this.height = 234.56; + this.line = 5; + this.column = 3; + this.file_name = "main.tex"; + this.child_process.execFile = sinon.stub(); + return this.Settings.path.synctexBaseDir = project_id => `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`; + }); - describe "syncFromCode", -> - beforeEach -> - @fs.stat = sinon.stub().callsArgWith(1, null,{isFile: ()->true}) - @stdout = "NODE\t#{@page}\t#{@h}\t#{@v}\t#{@width}\t#{@height}\n" - @CommandRunner.run = sinon.stub().callsArgWith(6, null, {stdout:@stdout}) - @CompileManager.syncFromCode @project_id, @user_id, @file_name, @line, @column, @callback + describe("syncFromCode", function() { + beforeEach(function() { + this.fs.stat = sinon.stub().callsArgWith(1, null,{isFile(){ return true; }}); + this.stdout = `NODE\t${this.page}\t${this.h}\t${this.v}\t${this.width}\t${this.height}\n`; + this.CommandRunner.run = sinon.stub().callsArgWith(6, null, {stdout:this.stdout}); + return this.CompileManager.syncFromCode(this.project_id, this.user_id, this.file_name, this.line, this.column, this.callback); + }); - it "should execute the synctex binary", -> - bin_path = Path.resolve(__dirname + "/../../../bin/synctex") - synctex_path = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}/output.pdf" - file_path = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}/#{@file_name}" - @CommandRunner.run + it("should execute the synctex binary", function() { + const bin_path = Path.resolve(__dirname + "/../../../bin/synctex"); + 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}`; + return this.CommandRunner.run .calledWith( - "#{@project_id}-#{@user_id}", - ['/opt/synctex', 'code', synctex_path, file_path, @line, @column], - "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}", - @Settings.clsi.docker.image, + `${this.project_id}-${this.user_id}`, + ['/opt/synctex', 'code', synctex_path, file_path, this.line, this.column], + `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`, + this.Settings.clsi.docker.image, 60000, {} - ).should.equal true + ).should.equal(true); + }); - it "should call the callback with the parsed output", -> - @callback + return it("should call the callback with the parsed output", function() { + return this.callback .calledWith(null, [{ - page: @page - h: @h - v: @v - height: @height - width: @width + page: this.page, + h: this.h, + v: this.v, + height: this.height, + width: this.width }]) - .should.equal true + .should.equal(true); + }); + }); - describe "syncFromPdf", -> - beforeEach -> - @fs.stat = sinon.stub().callsArgWith(1, null,{isFile: ()->true}) - @stdout = "NODE\t#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}/#{@file_name}\t#{@line}\t#{@column}\n" - @CommandRunner.run = sinon.stub().callsArgWith(6, null, {stdout:@stdout}) - @CompileManager.syncFromPdf @project_id, @user_id, @page, @h, @v, @callback + return describe("syncFromPdf", function() { + beforeEach(function() { + this.fs.stat = sinon.stub().callsArgWith(1, null,{isFile(){ return true; }}); + 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.stub().callsArgWith(6, null, {stdout:this.stdout}); + return this.CompileManager.syncFromPdf(this.project_id, this.user_id, this.page, this.h, this.v, this.callback); + }); - it "should execute the synctex binary", -> - bin_path = Path.resolve(__dirname + "/../../../bin/synctex") - synctex_path = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}/output.pdf" - @CommandRunner.run + it("should execute the synctex binary", function() { + const bin_path = Path.resolve(__dirname + "/../../../bin/synctex"); + const synctex_path = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}/output.pdf`; + return this.CommandRunner.run .calledWith( - "#{@project_id}-#{@user_id}", - ['/opt/synctex', "pdf", synctex_path, @page, @h, @v], - "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}", - @Settings.clsi.docker.image, + `${this.project_id}-${this.user_id}`, + ['/opt/synctex', "pdf", synctex_path, this.page, this.h, this.v], + `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`, + this.Settings.clsi.docker.image, 60000, - {}).should.equal true + {}).should.equal(true); + }); - it "should call the callback with the parsed output", -> - @callback + return it("should call the callback with the parsed output", function() { + return this.callback .calledWith(null, [{ - file: @file_name - line: @line - column: @column + file: this.file_name, + line: this.line, + column: this.column }]) - .should.equal true + .should.equal(true); + }); + }); + }); - describe "wordcount", -> - beforeEach -> - @CommandRunner.run = sinon.stub().callsArg(6) - @fs.readFile = sinon.stub().callsArgWith(2, null, @stdout = "Encoding: ascii\nWords in text: 2") - @callback = sinon.stub() + return describe("wordcount", function() { + beforeEach(function() { + this.CommandRunner.run = sinon.stub().callsArg(6); + this.fs.readFile = sinon.stub().callsArgWith(2, null, (this.stdout = "Encoding: ascii\nWords in text: 2")); + this.callback = sinon.stub(); - @project_id - @timeout = 60 * 1000 - @file_name = "main.tex" - @Settings.path.compilesDir = "/local/compile/directory" - @image = "example.com/image" + this.project_id; + this.timeout = 60 * 1000; + this.file_name = "main.tex"; + this.Settings.path.compilesDir = "/local/compile/directory"; + this.image = "example.com/image"; - @CompileManager.wordcount @project_id, @user_id, @file_name, @image, @callback + return this.CompileManager.wordcount(this.project_id, this.user_id, this.file_name, this.image, this.callback); + }); - it "should run the texcount command", -> - @directory = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}" - @file_path = "$COMPILE_DIR/#{@file_name}" - @command =[ "texcount", "-nocol", "-inc", @file_path, "-out=" + @file_path + ".wc"] + it("should run the texcount command", function() { + this.directory = `${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`; + this.file_path = `$COMPILE_DIR/${this.file_name}`; + this.command =[ "texcount", "-nocol", "-inc", this.file_path, `-out=${this.file_path}.wc`]; - @CommandRunner.run - .calledWith("#{@project_id}-#{@user_id}", @command, @directory, @image, @timeout, {}) - .should.equal true + return this.CommandRunner.run + .calledWith(`${this.project_id}-${this.user_id}`, this.command, this.directory, this.image, this.timeout, {}) + .should.equal(true); + }); - it "should call the callback with the parsed output", -> - @callback + return it("should call the callback with the parsed output", function() { + return this.callback .calledWith(null, { - encode: "ascii" - textWords: 2 - headWords: 0 - outside: 0 - headers: 0 - elements: 0 - mathInline: 0 - mathDisplay: 0 - errors: 0 + encode: "ascii", + textWords: 2, + headWords: 0, + outside: 0, + headers: 0, + elements: 0, + mathInline: 0, + mathDisplay: 0, + errors: 0, messages: "" }) - .should.equal true + .should.equal(true); + }); + }); +}); diff --git a/test/unit/coffee/ContentTypeMapperTests.js b/test/unit/coffee/ContentTypeMapperTests.js index 2439120..64a6091 100644 --- a/test/unit/coffee/ContentTypeMapperTests.js +++ b/test/unit/coffee/ContentTypeMapperTests.js @@ -1,55 +1,75 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/ContentTypeMapper' +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/ContentTypeMapper'); -describe 'ContentTypeMapper', -> +describe('ContentTypeMapper', function() { - beforeEach -> - @ContentTypeMapper = SandboxedModule.require modulePath + beforeEach(function() { + return this.ContentTypeMapper = SandboxedModule.require(modulePath); + }); - describe 'map', -> + return describe('map', function() { - it 'should map .txt to text/plain', -> - content_type = @ContentTypeMapper.map('example.txt') - content_type.should.equal 'text/plain' + it('should map .txt to text/plain', function() { + const content_type = this.ContentTypeMapper.map('example.txt'); + return content_type.should.equal('text/plain'); + }); - it 'should map .csv to text/csv', -> - content_type = @ContentTypeMapper.map('example.csv') - content_type.should.equal 'text/csv' + it('should map .csv to text/csv', function() { + const content_type = this.ContentTypeMapper.map('example.csv'); + return content_type.should.equal('text/csv'); + }); - it 'should map .pdf to application/pdf', -> - content_type = @ContentTypeMapper.map('example.pdf') - content_type.should.equal 'application/pdf' + it('should map .pdf to application/pdf', function() { + const content_type = this.ContentTypeMapper.map('example.pdf'); + return content_type.should.equal('application/pdf'); + }); - it 'should fall back to octet-stream', -> - content_type = @ContentTypeMapper.map('example.unknown') - content_type.should.equal 'application/octet-stream' + it('should fall back to octet-stream', function() { + const content_type = this.ContentTypeMapper.map('example.unknown'); + return content_type.should.equal('application/octet-stream'); + }); - describe 'coercing web files to plain text', -> + describe('coercing web files to plain text', function() { - it 'should map .js to plain text', -> - content_type = @ContentTypeMapper.map('example.js') - content_type.should.equal 'text/plain' + it('should map .js to plain text', function() { + const content_type = this.ContentTypeMapper.map('example.js'); + return content_type.should.equal('text/plain'); + }); - it 'should map .html to plain text', -> - content_type = @ContentTypeMapper.map('example.html') - content_type.should.equal 'text/plain' + it('should map .html to plain text', function() { + const content_type = this.ContentTypeMapper.map('example.html'); + return content_type.should.equal('text/plain'); + }); - it 'should map .css to plain text', -> - content_type = @ContentTypeMapper.map('example.css') - content_type.should.equal 'text/plain' + return it('should map .css to plain text', function() { + const content_type = this.ContentTypeMapper.map('example.css'); + return content_type.should.equal('text/plain'); + }); + }); - describe 'image files', -> + return describe('image files', function() { - it 'should map .png to image/png', -> - content_type = @ContentTypeMapper.map('example.png') - content_type.should.equal 'image/png' + it('should map .png to image/png', function() { + const content_type = this.ContentTypeMapper.map('example.png'); + return content_type.should.equal('image/png'); + }); - it 'should map .jpeg to image/jpeg', -> - content_type = @ContentTypeMapper.map('example.jpeg') - content_type.should.equal 'image/jpeg' + it('should map .jpeg to image/jpeg', function() { + const content_type = this.ContentTypeMapper.map('example.jpeg'); + return content_type.should.equal('image/jpeg'); + }); - it 'should map .svg to text/plain to protect against XSS (SVG can execute JS)', -> - content_type = @ContentTypeMapper.map('example.svg') - content_type.should.equal 'text/plain' + 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'); + return content_type.should.equal('text/plain'); + }); + }); + }); +}); diff --git a/test/unit/coffee/DockerLockManagerTests.js b/test/unit/coffee/DockerLockManagerTests.js index 6161bec..5ef3ca2 100644 --- a/test/unit/coffee/DockerLockManagerTests.js +++ b/test/unit/coffee/DockerLockManagerTests.js @@ -1,145 +1,188 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -require "coffee-script" -modulePath = require('path').join __dirname, '../../../app/coffee/DockerLockManager' +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +require("coffee-script"); +const modulePath = require('path').join(__dirname, '../../../app/coffee/DockerLockManager'); -describe "LockManager", -> - beforeEach -> - @LockManager = SandboxedModule.require modulePath, requires: - "settings-sharelatex": @Settings = - clsi: docker: {} - "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() } +describe("LockManager", function() { + beforeEach(function() { + return this.LockManager = SandboxedModule.require(modulePath, { requires: { + "settings-sharelatex": (this.Settings = + {clsi: {docker: {}}}), + "logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }) + } + });}); - describe "runWithLock", -> - describe "with a single lock", -> - beforeEach (done) -> - @callback = sinon.stub() - @LockManager.runWithLock "lock-one", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world") - , 100 - , (err, args...) => - @callback(err,args...) - done() + return describe("runWithLock", function() { + describe("with a single lock", function() { + beforeEach(function(done) { + this.callback = sinon.stub(); + return this.LockManager.runWithLock("lock-one", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world") + , 100) + + , (err, ...args) => { + this.callback(err,...Array.from(args)); + return done(); + }); + }); - it "should call the callback", -> - @callback.calledWith(null,"hello","world").should.equal true + return it("should call the callback", function() { + return this.callback.calledWith(null,"hello","world").should.equal(true); + }); + }); - describe "with two locks", -> - beforeEach (done) -> - @callback1 = sinon.stub() - @callback2 = sinon.stub() - @LockManager.runWithLock "lock-one", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","one") - , 100 - , (err, args...) => - @callback1(err,args...) - @LockManager.runWithLock "lock-two", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","two") - , 200 - , (err, args...) => - @callback2(err,args...) - done() + describe("with two locks", function() { + beforeEach(function(done) { + this.callback1 = sinon.stub(); + this.callback2 = sinon.stub(); + this.LockManager.runWithLock("lock-one", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","one") + , 100) + + , (err, ...args) => { + return this.callback1(err,...Array.from(args)); + }); + return this.LockManager.runWithLock("lock-two", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","two") + , 200) + + , (err, ...args) => { + this.callback2(err,...Array.from(args)); + return done(); + }); + }); - it "should call the first callback", -> - @callback1.calledWith(null,"hello","world","one").should.equal true + it("should call the first callback", function() { + return this.callback1.calledWith(null,"hello","world","one").should.equal(true); + }); - it "should call the second callback", -> - @callback2.calledWith(null,"hello","world","two").should.equal true + return it("should call the second callback", function() { + return this.callback2.calledWith(null,"hello","world","two").should.equal(true); + }); + }); - describe "with lock contention", -> - describe "where the first lock is released quickly", -> - beforeEach (done) -> - @LockManager.MAX_LOCK_WAIT_TIME = 1000 - @LockManager.LOCK_TEST_INTERVAL = 100 - @callback1 = sinon.stub() - @callback2 = sinon.stub() - @LockManager.runWithLock "lock", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","one") - , 100 - , (err, args...) => - @callback1(err,args...) - @LockManager.runWithLock "lock", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","two") - , 200 - , (err, args...) => - @callback2(err,args...) - done() + return describe("with lock contention", function() { + describe("where the first lock is released quickly", function() { + beforeEach(function(done) { + this.LockManager.MAX_LOCK_WAIT_TIME = 1000; + this.LockManager.LOCK_TEST_INTERVAL = 100; + this.callback1 = sinon.stub(); + this.callback2 = sinon.stub(); + this.LockManager.runWithLock("lock", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","one") + , 100) + + , (err, ...args) => { + return this.callback1(err,...Array.from(args)); + }); + return this.LockManager.runWithLock("lock", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","two") + , 200) + + , (err, ...args) => { + this.callback2(err,...Array.from(args)); + return done(); + }); + }); - it "should call the first callback", -> - @callback1.calledWith(null,"hello","world","one").should.equal true + it("should call the first callback", function() { + return this.callback1.calledWith(null,"hello","world","one").should.equal(true); + }); - it "should call the second callback", -> - @callback2.calledWith(null,"hello","world","two").should.equal true + return it("should call the second callback", function() { + return this.callback2.calledWith(null,"hello","world","two").should.equal(true); + }); + }); - describe "where the first lock is held longer than the waiting time", -> - beforeEach (done) -> - @LockManager.MAX_LOCK_HOLD_TIME = 10000 - @LockManager.MAX_LOCK_WAIT_TIME = 1000 - @LockManager.LOCK_TEST_INTERVAL = 100 - @callback1 = sinon.stub() - @callback2 = sinon.stub() - doneOne = doneTwo = false - finish = (key) -> - doneOne = true if key is 1 - doneTwo = true if key is 2 - done() if doneOne and doneTwo - @LockManager.runWithLock "lock", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","one") - , 1100 - , (err, args...) => - @callback1(err,args...) - finish(1) - @LockManager.runWithLock "lock", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","two") - , 100 - , (err, args...) => - @callback2(err,args...) - finish(2) + describe("where the first lock is held longer than the waiting time", function() { + beforeEach(function(done) { + let doneTwo; + this.LockManager.MAX_LOCK_HOLD_TIME = 10000; + this.LockManager.MAX_LOCK_WAIT_TIME = 1000; + this.LockManager.LOCK_TEST_INTERVAL = 100; + this.callback1 = sinon.stub(); + this.callback2 = sinon.stub(); + let doneOne = (doneTwo = false); + const finish = function(key) { + if (key === 1) { doneOne = true; } + if (key === 2) { doneTwo = true; } + if (doneOne && doneTwo) { return done(); } + }; + this.LockManager.runWithLock("lock", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","one") + , 1100) + + , (err, ...args) => { + this.callback1(err,...Array.from(args)); + return finish(1); + }); + return this.LockManager.runWithLock("lock", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","two") + , 100) + + , (err, ...args) => { + this.callback2(err,...Array.from(args)); + return finish(2); + }); + }); - it "should call the first callback", -> - @callback1.calledWith(null,"hello","world","one").should.equal true + it("should call the first callback", function() { + return this.callback1.calledWith(null,"hello","world","one").should.equal(true); + }); - it "should call the second callback with an error", -> - error = sinon.match.instanceOf Error - @callback2.calledWith(error).should.equal true + return it("should call the second callback with an error", function() { + const error = sinon.match.instanceOf(Error); + return this.callback2.calledWith(error).should.equal(true); + }); + }); - describe "where the first lock is held longer than the max holding time", -> - beforeEach (done) -> - @LockManager.MAX_LOCK_HOLD_TIME = 1000 - @LockManager.MAX_LOCK_WAIT_TIME = 2000 - @LockManager.LOCK_TEST_INTERVAL = 100 - @callback1 = sinon.stub() - @callback2 = sinon.stub() - doneOne = doneTwo = false - finish = (key) -> - doneOne = true if key is 1 - doneTwo = true if key is 2 - done() if doneOne and doneTwo - @LockManager.runWithLock "lock", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","one") - , 1500 - , (err, args...) => - @callback1(err,args...) - finish(1) - @LockManager.runWithLock "lock", (releaseLock) -> - setTimeout () -> - releaseLock(null, "hello", "world","two") - , 100 - , (err, args...) => - @callback2(err,args...) - finish(2) + return describe("where the first lock is held longer than the max holding time", function() { + beforeEach(function(done) { + let doneTwo; + this.LockManager.MAX_LOCK_HOLD_TIME = 1000; + this.LockManager.MAX_LOCK_WAIT_TIME = 2000; + this.LockManager.LOCK_TEST_INTERVAL = 100; + this.callback1 = sinon.stub(); + this.callback2 = sinon.stub(); + let doneOne = (doneTwo = false); + const finish = function(key) { + if (key === 1) { doneOne = true; } + if (key === 2) { doneTwo = true; } + if (doneOne && doneTwo) { return done(); } + }; + this.LockManager.runWithLock("lock", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","one") + , 1500) + + , (err, ...args) => { + this.callback1(err,...Array.from(args)); + return finish(1); + }); + return this.LockManager.runWithLock("lock", releaseLock => + setTimeout(() => releaseLock(null, "hello", "world","two") + , 100) + + , (err, ...args) => { + this.callback2(err,...Array.from(args)); + return finish(2); + }); + }); - it "should call the first callback", -> - @callback1.calledWith(null,"hello","world","one").should.equal true + it("should call the first callback", function() { + return this.callback1.calledWith(null,"hello","world","one").should.equal(true); + }); - it "should call the second callback", -> - @callback2.calledWith(null,"hello","world","two").should.equal true + return it("should call the second callback", function() { + return this.callback2.calledWith(null,"hello","world","two").should.equal(true); + }); + }); + }); + }); +}); diff --git a/test/unit/coffee/DockerRunnerTests.js b/test/unit/coffee/DockerRunnerTests.js index 307ffde..79ac5df 100644 --- a/test/unit/coffee/DockerRunnerTests.js +++ b/test/unit/coffee/DockerRunnerTests.js @@ -1,509 +1,656 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -expect = require('chai').expect -require "coffee-script" -modulePath = require('path').join __dirname, '../../../app/coffee/DockerRunner' -Path = require "path" +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS206: Consider reworking classes to avoid initClass + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const { expect } = require('chai'); +require("coffee-script"); +const modulePath = require('path').join(__dirname, '../../../app/coffee/DockerRunner'); +const Path = require("path"); -describe "DockerRunner", -> - beforeEach -> - @container = container = {} - @DockerRunner = SandboxedModule.require modulePath, requires: - "settings-sharelatex": @Settings = - clsi: docker: {} +describe("DockerRunner", function() { + beforeEach(function() { + let container, Docker, Timer; + this.container = (container = {}); + this.DockerRunner = SandboxedModule.require(modulePath, { requires: { + "settings-sharelatex": (this.Settings = { + clsi: { docker: {} + }, path: {} - "logger-sharelatex": @logger = { + }), + "logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub(), info: sinon.stub(), warn: sinon.stub() + }), + "dockerode": (Docker = (function() { + Docker = class Docker { + static initClass() { + this.prototype.getContainer = sinon.stub().returns(container); + this.prototype.createContainer = sinon.stub().yields(null, container); + this.prototype.listContainers = sinon.stub(); + } + }; + Docker.initClass(); + return Docker; + })()), + "fs": (this.fs = { stat: sinon.stub().yields(null,{isDirectory(){ return true; }}) }), + "./Metrics": { + Timer: (Timer = class Timer { + done() {} + }) + }, + "./LockManager": { + runWithLock(key, runner, callback) { return runner(callback); } } - "dockerode": class Docker - getContainer: sinon.stub().returns(container) - createContainer: sinon.stub().yields(null, container) - listContainers: sinon.stub() - "fs": @fs = { stat: sinon.stub().yields(null,{isDirectory:()->true}) } - "./Metrics": - Timer: class Timer - done: () -> - "./LockManager": - runWithLock: (key, runner, callback) -> runner(callback) - @Docker = Docker - @getContainer = Docker::getContainer - @createContainer = Docker::createContainer - @listContainers = Docker::listContainers + } + } + ); + this.Docker = Docker; + this.getContainer = Docker.prototype.getContainer; + this.createContainer = Docker.prototype.createContainer; + this.listContainers = Docker.prototype.listContainers; - @directory = "/local/compile/directory" - @mainFile = "main-file.tex" - @compiler = "pdflatex" - @image = "example.com/sharelatex/image:2016.2" - @env = {} - @callback = sinon.stub() - @project_id = "project-id-123" - @volumes = - "/local/compile/directory": "/compile" - @Settings.clsi.docker.image = @defaultImage = "default-image" - @Settings.clsi.docker.env = PATH: "mock-path" + this.directory = "/local/compile/directory"; + this.mainFile = "main-file.tex"; + this.compiler = "pdflatex"; + this.image = "example.com/sharelatex/image:2016.2"; + this.env = {}; + this.callback = sinon.stub(); + this.project_id = "project-id-123"; + this.volumes = + {"/local/compile/directory": "/compile"}; + this.Settings.clsi.docker.image = (this.defaultImage = "default-image"); + return this.Settings.clsi.docker.env = {PATH: "mock-path"}; + }); - describe "run", -> - beforeEach (done)-> - @DockerRunner._getContainerOptions = sinon.stub().returns(@options = {mockoptions: "foo"}) - @DockerRunner._fingerprintContainer = sinon.stub().returns(@fingerprint = "fingerprint") + describe("run", function() { + beforeEach(function(done){ + this.DockerRunner._getContainerOptions = sinon.stub().returns(this.options = {mockoptions: "foo"}); + this.DockerRunner._fingerprintContainer = sinon.stub().returns(this.fingerprint = "fingerprint"); - @name = "project-#{@project_id}-#{@fingerprint}" + this.name = `project-${this.project_id}-${this.fingerprint}`; - @command = ["mock", "command", "--outdir=$COMPILE_DIR"] - @command_with_dir = ["mock", "command", "--outdir=/compile"] - @timeout = 42000 - done() + this.command = ["mock", "command", "--outdir=$COMPILE_DIR"]; + this.command_with_dir = ["mock", "command", "--outdir=/compile"]; + this.timeout = 42000; + return done(); + }); - describe "successfully", -> - beforeEach (done)-> - @DockerRunner._runAndWaitForContainer = sinon.stub().callsArgWith(3, null, @output = "mock-output") - @DockerRunner.run @project_id, @command, @directory, @image, @timeout, @env, (err, output)=> - @callback(err, output) - done() + describe("successfully", function() { + beforeEach(function(done){ + 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, (err, output)=> { + this.callback(err, output); + return done(); + }); + }); - it "should generate the options for the container", -> - @DockerRunner._getContainerOptions - .calledWith(@command_with_dir, @image, @volumes, @timeout) - .should.equal true + it("should generate the options for the container", function() { + return this.DockerRunner._getContainerOptions + .calledWith(this.command_with_dir, this.image, this.volumes, this.timeout) + .should.equal(true); + }); - it "should generate the fingerprint from the returned options", -> - @DockerRunner._fingerprintContainer - .calledWith(@options) - .should.equal true + it("should generate the fingerprint from the returned options", function() { + return this.DockerRunner._fingerprintContainer + .calledWith(this.options) + .should.equal(true); + }); - it "should do the run", -> - @DockerRunner._runAndWaitForContainer - .calledWith(@options, @volumes, @timeout) - .should.equal true + it("should do the run", function() { + return this.DockerRunner._runAndWaitForContainer + .calledWith(this.options, this.volumes, this.timeout) + .should.equal(true); + }); - it "should call the callback", -> - @callback.calledWith(null, @output).should.equal true + return it("should call the callback", function() { + return this.callback.calledWith(null, this.output).should.equal(true); + }); + }); - describe 'when path.sandboxedCompilesHostDir is set', -> + describe('when path.sandboxedCompilesHostDir is set', function() { - beforeEach -> - @Settings.path.sandboxedCompilesHostDir = '/some/host/dir/compiles' - @directory = '/var/lib/sharelatex/data/compiles/xyz' - @DockerRunner._runAndWaitForContainer = sinon.stub().callsArgWith(3, null, @output = "mock-output") - @DockerRunner.run @project_id, @command, @directory, @image, @timeout, @env, @callback + beforeEach(function() { + this.Settings.path.sandboxedCompilesHostDir = '/some/host/dir/compiles'; + this.directory = '/var/lib/sharelatex/data/compiles/xyz'; + 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.callback); + }); - it 'should re-write the bind directory', -> - volumes = @DockerRunner._runAndWaitForContainer.lastCall.args[1] - expect(volumes).to.deep.equal { + it('should re-write the bind directory', function() { + const volumes = this.DockerRunner._runAndWaitForContainer.lastCall.args[1]; + return expect(volumes).to.deep.equal({ '/some/host/dir/compiles/xyz': '/compile' - } + }); + }); - it "should call the callback", -> - @callback.calledWith(null, @output).should.equal true + return it("should call the callback", function() { + return this.callback.calledWith(null, this.output).should.equal(true); + }); + }); - describe "when the run throws an error", -> - beforeEach -> - firstTime = true - @output = "mock-output" - @DockerRunner._runAndWaitForContainer = (options, volumes, timeout, callback = (error, output)->) => - if firstTime - firstTime = false - callback new Error("HTTP code is 500 which indicates error: server error") - else - callback(null, @output) - sinon.spy @DockerRunner, "_runAndWaitForContainer" - @DockerRunner.destroyContainer = sinon.stub().callsArg(3) - @DockerRunner.run @project_id, @command, @directory, @image, @timeout, @env, @callback + describe("when the run throws an error", function() { + beforeEach(function() { + let firstTime = true; + this.output = "mock-output"; + this.DockerRunner._runAndWaitForContainer = (options, volumes, timeout, callback) => { + if (callback == null) { callback = function(error, output){}; } + if (firstTime) { + firstTime = false; + return callback(new Error("HTTP code is 500 which indicates error: server error")); + } else { + return callback(null, this.output); + } + }; + sinon.spy(this.DockerRunner, "_runAndWaitForContainer"); + this.DockerRunner.destroyContainer = sinon.stub().callsArg(3); + return this.DockerRunner.run(this.project_id, this.command, this.directory, this.image, this.timeout, this.env, this.callback); + }); - it "should do the run twice", -> - @DockerRunner._runAndWaitForContainer - .calledTwice.should.equal true + it("should do the run twice", function() { + return this.DockerRunner._runAndWaitForContainer + .calledTwice.should.equal(true); + }); - it "should destroy the container in between", -> - @DockerRunner.destroyContainer - .calledWith(@name, null) - .should.equal true + it("should destroy the container in between", function() { + return this.DockerRunner.destroyContainer + .calledWith(this.name, null) + .should.equal(true); + }); - it "should call the callback", -> - @callback.calledWith(null, @output).should.equal true + return it("should call the callback", function() { + return this.callback.calledWith(null, this.output).should.equal(true); + }); + }); - describe "with no image", -> - beforeEach -> - @DockerRunner._runAndWaitForContainer = sinon.stub().callsArgWith(3, null, @output = "mock-output") - @DockerRunner.run @project_id, @command, @directory, null, @timeout, @env, @callback + describe("with no image", function() { + beforeEach(function() { + this.DockerRunner._runAndWaitForContainer = sinon.stub().callsArgWith(3, null, (this.output = "mock-output")); + return this.DockerRunner.run(this.project_id, this.command, this.directory, null, this.timeout, this.env, this.callback); + }); - it "should use the default image", -> - @DockerRunner._getContainerOptions - .calledWith(@command_with_dir, @defaultImage, @volumes, @timeout) - .should.equal true + return it("should use the default image", function() { + return this.DockerRunner._getContainerOptions + .calledWith(this.command_with_dir, this.defaultImage, this.volumes, this.timeout) + .should.equal(true); + }); + }); - describe "with image override", -> - beforeEach -> - @Settings.texliveImageNameOveride = "overrideimage.com/something" - @DockerRunner._runAndWaitForContainer = sinon.stub().callsArgWith(3, null, @output = "mock-output") - @DockerRunner.run @project_id, @command, @directory, @image, @timeout, @env, @callback + return describe("with image override", function() { + beforeEach(function() { + this.Settings.texliveImageNameOveride = "overrideimage.com/something"; + 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.callback); + }); - it "should use the override and keep the tag", -> - image = @DockerRunner._getContainerOptions.args[0][1] - image.should.equal "overrideimage.com/something/image:2016.2" + return it("should use the override and keep the tag", function() { + const image = this.DockerRunner._getContainerOptions.args[0][1]; + return image.should.equal("overrideimage.com/something/image:2016.2"); + }); + }); + }); - describe "_runAndWaitForContainer", -> - beforeEach -> - @options = {mockoptions: "foo", name: @name = "mock-name"} - @DockerRunner.startContainer = (options, volumes, attachStreamHandler, callback) => - attachStreamHandler(null, @output = "mock-output") - callback(null, @containerId = "container-id") - sinon.spy @DockerRunner, "startContainer" - @DockerRunner.waitForContainer = sinon.stub().callsArgWith(2, null, @exitCode = 42) - @DockerRunner._runAndWaitForContainer @options, @volumes, @timeout, @callback + describe("_runAndWaitForContainer", function() { + beforeEach(function() { + this.options = {mockoptions: "foo", name: (this.name = "mock-name")}; + this.DockerRunner.startContainer = (options, volumes, attachStreamHandler, callback) => { + attachStreamHandler(null, (this.output = "mock-output")); + return callback(null, (this.containerId = "container-id")); + }; + sinon.spy(this.DockerRunner, "startContainer"); + this.DockerRunner.waitForContainer = sinon.stub().callsArgWith(2, null, (this.exitCode = 42)); + return this.DockerRunner._runAndWaitForContainer(this.options, this.volumes, this.timeout, this.callback); + }); - it "should create/start the container", -> - @DockerRunner.startContainer - .calledWith(@options, @volumes) - .should.equal true + it("should create/start the container", function() { + return this.DockerRunner.startContainer + .calledWith(this.options, this.volumes) + .should.equal(true); + }); - it "should wait for the container to finish", -> - @DockerRunner.waitForContainer - .calledWith(@name, @timeout) - .should.equal true + it("should wait for the container to finish", function() { + return this.DockerRunner.waitForContainer + .calledWith(this.name, this.timeout) + .should.equal(true); + }); - it "should call the callback with the output", -> - @callback.calledWith(null, @output).should.equal true + return it("should call the callback with the output", function() { + return this.callback.calledWith(null, this.output).should.equal(true); + }); + }); - describe "startContainer", -> - beforeEach -> - @attachStreamHandler = sinon.stub() - @attachStreamHandler.cock = true - @options = {mockoptions: "foo", name: "mock-name"} - @container.inspect = sinon.stub().callsArgWith(0) - @DockerRunner.attachToContainer = (containerId, attachStreamHandler, cb)=> - attachStreamHandler() - cb() - sinon.spy @DockerRunner, "attachToContainer" + describe("startContainer", function() { + beforeEach(function() { + this.attachStreamHandler = sinon.stub(); + this.attachStreamHandler.cock = true; + this.options = {mockoptions: "foo", name: "mock-name"}; + this.container.inspect = sinon.stub().callsArgWith(0); + this.DockerRunner.attachToContainer = (containerId, attachStreamHandler, cb)=> { + attachStreamHandler(); + return cb(); + }; + return sinon.spy(this.DockerRunner, "attachToContainer"); + }); - describe "when the container exists", -> - beforeEach -> - @container.inspect = sinon.stub().callsArgWith(0) - @container.start = sinon.stub().yields() + describe("when the container exists", function() { + beforeEach(function() { + this.container.inspect = sinon.stub().callsArgWith(0); + this.container.start = sinon.stub().yields(); - @DockerRunner.startContainer @options, @volumes, @callback, -> + return this.DockerRunner.startContainer(this.options, this.volumes, this.callback, function() {}); + }); - it "should start the container with the given name", -> - @getContainer - .calledWith(@options.name) - .should.equal true - @container.start + it("should start the container with the given name", function() { + this.getContainer + .calledWith(this.options.name) + .should.equal(true); + return this.container.start .called - .should.equal true + .should.equal(true); + }); - it "should not try to create the container", -> - @createContainer.called.should.equal false + it("should not try to create the container", function() { + return this.createContainer.called.should.equal(false); + }); - it "should attach to the container", -> - @DockerRunner.attachToContainer.called.should.equal true + it("should attach to the container", function() { + return this.DockerRunner.attachToContainer.called.should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); - it "should attach before the container starts", -> - sinon.assert.callOrder(@DockerRunner.attachToContainer, @container.start) + return it("should attach before the container starts", function() { + return sinon.assert.callOrder(this.DockerRunner.attachToContainer, this.container.start); + }); + }); - describe "when the container does not exist", -> - beforeEach ()-> - exists = false - @container.start = sinon.stub().yields() - @container.inspect = sinon.stub().callsArgWith(0, {statusCode:404}) - @DockerRunner.startContainer @options, @volumes, @attachStreamHandler, @callback + describe("when the container does not exist", function() { + beforeEach(function(){ + const exists = false; + this.container.start = sinon.stub().yields(); + this.container.inspect = sinon.stub().callsArgWith(0, {statusCode:404}); + return this.DockerRunner.startContainer(this.options, this.volumes, this.attachStreamHandler, this.callback); + }); - it "should create the container", -> - @createContainer - .calledWith(@options) - .should.equal true + it("should create the container", function() { + return this.createContainer + .calledWith(this.options) + .should.equal(true); + }); - it "should call the callback and stream handler", -> - @attachStreamHandler.called.should.equal true - @callback.called.should.equal true + it("should call the callback and stream handler", function() { + this.attachStreamHandler.called.should.equal(true); + return this.callback.called.should.equal(true); + }); - it "should attach to the container", -> - @DockerRunner.attachToContainer.called.should.equal true + it("should attach to the container", function() { + return this.DockerRunner.attachToContainer.called.should.equal(true); + }); - it "should attach before the container starts", -> - sinon.assert.callOrder(@DockerRunner.attachToContainer, @container.start) + return it("should attach before the container starts", function() { + return sinon.assert.callOrder(this.DockerRunner.attachToContainer, this.container.start); + }); + }); - describe "when the container is already running", -> - beforeEach -> - error = new Error("HTTP code is 304 which indicates error: server error - start: Cannot start container #{@name}: The container MOCKID is already running.") - error.statusCode = 304 - @container.start = sinon.stub().yields(error) - @container.inspect = sinon.stub().callsArgWith(0) - @DockerRunner.startContainer @options, @volumes, @attachStreamHandler, @callback + describe("when the container is already running", function() { + beforeEach(function() { + 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.`); + error.statusCode = 304; + this.container.start = sinon.stub().yields(error); + this.container.inspect = sinon.stub().callsArgWith(0); + return this.DockerRunner.startContainer(this.options, this.volumes, this.attachStreamHandler, this.callback); + }); - it "should not try to create the container", -> - @createContainer.called.should.equal false + it("should not try to create the container", function() { + return this.createContainer.called.should.equal(false); + }); - it "should call the callback and stream handler without an error", -> - @attachStreamHandler.called.should.equal true - @callback.called.should.equal true + return it("should call the callback and stream handler without an error", function() { + this.attachStreamHandler.called.should.equal(true); + return this.callback.called.should.equal(true); + }); + }); - describe "when a volume does not exist", -> - beforeEach ()-> - @fs.stat = sinon.stub().yields(new Error("no such path")) - @DockerRunner.startContainer @options, @volumes, @attachStreamHandler, @callback + describe("when a volume does not exist", function() { + beforeEach(function(){ + this.fs.stat = sinon.stub().yields(new Error("no such path")); + return this.DockerRunner.startContainer(this.options, this.volumes, this.attachStreamHandler, this.callback); + }); - it "should not try to create the container", -> - @createContainer.called.should.equal false + it("should not try to create the container", function() { + return this.createContainer.called.should.equal(false); + }); - it "should call the callback with an error", -> - @callback.calledWith(new Error()).should.equal true + return it("should call the callback with an error", function() { + return this.callback.calledWith(new Error()).should.equal(true); + }); + }); - describe "when a volume exists but is not a directory", -> - beforeEach -> - @fs.stat = sinon.stub().yields(null, {isDirectory: () -> return false}) - @DockerRunner.startContainer @options, @volumes, @attachStreamHandler, @callback + describe("when a volume exists but is not a directory", function() { + beforeEach(function() { + this.fs.stat = sinon.stub().yields(null, {isDirectory() { return false; }}); + return this.DockerRunner.startContainer(this.options, this.volumes, this.attachStreamHandler, this.callback); + }); - it "should not try to create the container", -> - @createContainer.called.should.equal false + it("should not try to create the container", function() { + return this.createContainer.called.should.equal(false); + }); - it "should call the callback with an error", -> - @callback.calledWith(new Error()).should.equal true + return it("should call the callback with an error", function() { + return this.callback.calledWith(new Error()).should.equal(true); + }); + }); - describe "when a volume does not exist, but sibling-containers are used", -> - beforeEach -> - @fs.stat = sinon.stub().yields(new Error("no such path")) - @Settings.path.sandboxedCompilesHostDir = '/some/path' - @container.start = sinon.stub().yields() - @DockerRunner.startContainer @options, @volumes, @callback + describe("when a volume does not exist, but sibling-containers are used", function() { + beforeEach(function() { + this.fs.stat = sinon.stub().yields(new Error("no such path")); + this.Settings.path.sandboxedCompilesHostDir = '/some/path'; + this.container.start = sinon.stub().yields(); + return this.DockerRunner.startContainer(this.options, this.volumes, this.callback); + }); - afterEach -> - delete @Settings.path.sandboxedCompilesHostDir + afterEach(function() { + return delete this.Settings.path.sandboxedCompilesHostDir; + }); - it "should start the container with the given name", -> - @getContainer - .calledWith(@options.name) - .should.equal true - @container.start + it("should start the container with the given name", function() { + this.getContainer + .calledWith(this.options.name) + .should.equal(true); + return this.container.start .called - .should.equal true + .should.equal(true); + }); - it "should not try to create the container", -> - @createContainer.called.should.equal false + it("should not try to create the container", function() { + return this.createContainer.called.should.equal(false); + }); - it "should call the callback", -> - @callback.called.should.equal true - @callback.calledWith(new Error()).should.equal false + return it("should call the callback", function() { + this.callback.called.should.equal(true); + return this.callback.calledWith(new Error()).should.equal(false); + }); + }); - describe "when the container tries to be created, but already has been (race condition)", -> + return describe("when the container tries to be created, but already has been (race condition)", function() {}); + }); - describe "waitForContainer", -> - beforeEach -> - @containerId = "container-id" - @timeout = 5000 - @container.wait = sinon.stub().yields(null, StatusCode: @statusCode = 42) - @container.kill = sinon.stub().yields() + describe("waitForContainer", function() { + beforeEach(function() { + this.containerId = "container-id"; + this.timeout = 5000; + this.container.wait = sinon.stub().yields(null, {StatusCode: (this.statusCode = 42)}); + return this.container.kill = sinon.stub().yields(); + }); - describe "when the container returns in time", -> - beforeEach -> - @DockerRunner.waitForContainer @containerId, @timeout, @callback + describe("when the container returns in time", function() { + beforeEach(function() { + return this.DockerRunner.waitForContainer(this.containerId, this.timeout, this.callback); + }); - it "should wait for the container", -> - @getContainer - .calledWith(@containerId) - .should.equal true - @container.wait + it("should wait for the container", function() { + this.getContainer + .calledWith(this.containerId) + .should.equal(true); + return this.container.wait .called - .should.equal true + .should.equal(true); + }); - it "should call the callback with the exit", -> - @callback - .calledWith(null, @statusCode) - .should.equal true + return it("should call the callback with the exit", function() { + return this.callback + .calledWith(null, this.statusCode) + .should.equal(true); + }); + }); - describe "when the container does not return before the timeout", -> - beforeEach (done) -> - @container.wait = (callback = (error, exitCode) ->) -> - setTimeout () -> - callback(null, StatusCode: 42) - , 100 - @timeout = 5 - @DockerRunner.waitForContainer @containerId, @timeout, (args...) => - @callback(args...) - done() + return describe("when the container does not return before the timeout", function() { + beforeEach(function(done) { + this.container.wait = function(callback) { + if (callback == null) { callback = function(error, exitCode) {}; } + return setTimeout(() => callback(null, {StatusCode: 42}) + , 100); + }; + this.timeout = 5; + return this.DockerRunner.waitForContainer(this.containerId, this.timeout, (...args) => { + this.callback(...Array.from(args || [])); + return done(); + }); + }); - it "should call kill on the container", -> - @getContainer - .calledWith(@containerId) - .should.equal true - @container.kill + it("should call kill on the container", function() { + this.getContainer + .calledWith(this.containerId) + .should.equal(true); + return this.container.kill .called - .should.equal true + .should.equal(true); + }); - it "should call the callback with an error", -> - error = new Error("container timed out") - error.timedout = true - @callback + return it("should call the callback with an error", function() { + const error = new Error("container timed out"); + error.timedout = true; + return this.callback .calledWith(error) - .should.equal true + .should.equal(true); + }); + }); + }); - describe "destroyOldContainers", -> - beforeEach (done) -> - oneHourInSeconds = 60 * 60 - oneHourInMilliseconds = oneHourInSeconds * 1000 - nowInSeconds = Date.now()/1000 - @containers = [{ - Name: "/project-old-container-name" - Id: "old-container-id" + describe("destroyOldContainers", function() { + beforeEach(function(done) { + const oneHourInSeconds = 60 * 60; + const oneHourInMilliseconds = oneHourInSeconds * 1000; + const nowInSeconds = Date.now()/1000; + this.containers = [{ + Name: "/project-old-container-name", + Id: "old-container-id", Created: nowInSeconds - oneHourInSeconds - 100 }, { - Name: "/project-new-container-name" - Id: "new-container-id" - Created: nowInSeconds - oneHourInSeconds + 100 + Name: "/project-new-container-name", + Id: "new-container-id", + Created: (nowInSeconds - oneHourInSeconds) + 100 }, { - Name: "/totally-not-a-project-container" - Id: "some-random-id" + Name: "/totally-not-a-project-container", + Id: "some-random-id", Created: nowInSeconds - (2 * oneHourInSeconds ) - }] - @DockerRunner.MAX_CONTAINER_AGE = oneHourInMilliseconds - @listContainers.callsArgWith(1, null, @containers) - @DockerRunner.destroyContainer = sinon.stub().callsArg(3) - @DockerRunner.destroyOldContainers (error) => - @callback(error) - done() + }]; + this.DockerRunner.MAX_CONTAINER_AGE = oneHourInMilliseconds; + this.listContainers.callsArgWith(1, null, this.containers); + this.DockerRunner.destroyContainer = sinon.stub().callsArg(3); + return this.DockerRunner.destroyOldContainers(error => { + this.callback(error); + return done(); + }); + }); - it "should list all containers", -> - @listContainers - .calledWith(all: true) - .should.equal true + it("should list all containers", function() { + return this.listContainers + .calledWith({all: true}) + .should.equal(true); + }); - it "should destroy old containers", -> - @DockerRunner.destroyContainer + it("should destroy old containers", function() { + this.DockerRunner.destroyContainer .callCount - .should.equal 1 - @DockerRunner.destroyContainer + .should.equal(1); + return this.DockerRunner.destroyContainer .calledWith("/project-old-container-name", "old-container-id") - .should.equal true + .should.equal(true); + }); - it "should not destroy new containers", -> - @DockerRunner.destroyContainer + it("should not destroy new containers", function() { + return this.DockerRunner.destroyContainer .calledWith("/project-new-container-name", "new-container-id") - .should.equal false + .should.equal(false); + }); - it "should not destroy non-project containers", -> - @DockerRunner.destroyContainer + it("should not destroy non-project containers", function() { + return this.DockerRunner.destroyContainer .calledWith("/totally-not-a-project-container", "some-random-id") - .should.equal false + .should.equal(false); + }); - it "should callback the callback", -> - @callback.called.should.equal true + return it("should callback the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe '_destroyContainer', -> - beforeEach -> - @containerId = 'some_id' - @fakeContainer = - remove: sinon.stub().callsArgWith(1, null) - @Docker::getContainer = sinon.stub().returns(@fakeContainer) + describe('_destroyContainer', function() { + beforeEach(function() { + this.containerId = 'some_id'; + this.fakeContainer = + {remove: sinon.stub().callsArgWith(1, null)}; + return this.Docker.prototype.getContainer = sinon.stub().returns(this.fakeContainer); + }); - it 'should get the container', (done) -> - @DockerRunner._destroyContainer @containerId, false, (err) => - @Docker::getContainer.callCount.should.equal 1 - @Docker::getContainer.calledWith(@containerId).should.equal true - done() + it('should get the container', function(done) { + return this.DockerRunner._destroyContainer(this.containerId, false, err => { + this.Docker.prototype.getContainer.callCount.should.equal(1); + this.Docker.prototype.getContainer.calledWith(this.containerId).should.equal(true); + return done(); + }); + }); - it 'should try to force-destroy the container when shouldForce=true', (done) -> - @DockerRunner._destroyContainer @containerId, true, (err) => - @fakeContainer.remove.callCount.should.equal 1 - @fakeContainer.remove.calledWith({force: true}).should.equal true - done() + it('should try to force-destroy the container when shouldForce=true', function(done) { + return this.DockerRunner._destroyContainer(this.containerId, true, err => { + this.fakeContainer.remove.callCount.should.equal(1); + this.fakeContainer.remove.calledWith({force: true}).should.equal(true); + return done(); + }); + }); - it 'should not try to force-destroy the container when shouldForce=false', (done) -> - @DockerRunner._destroyContainer @containerId, false, (err) => - @fakeContainer.remove.callCount.should.equal 1 - @fakeContainer.remove.calledWith({force: false}).should.equal true - done() + it('should not try to force-destroy the container when shouldForce=false', function(done) { + return this.DockerRunner._destroyContainer(this.containerId, false, err => { + this.fakeContainer.remove.callCount.should.equal(1); + this.fakeContainer.remove.calledWith({force: false}).should.equal(true); + return done(); + }); + }); - it 'should not produce an error', (done) -> - @DockerRunner._destroyContainer @containerId, false, (err) => - expect(err).to.equal null - done() + it('should not produce an error', function(done) { + return this.DockerRunner._destroyContainer(this.containerId, false, err => { + expect(err).to.equal(null); + return done(); + }); + }); - describe 'when the container is already gone', -> - beforeEach -> - @fakeError = new Error('woops') - @fakeError.statusCode = 404 - @fakeContainer = - remove: sinon.stub().callsArgWith(1, @fakeError) - @Docker::getContainer = sinon.stub().returns(@fakeContainer) + describe('when the container is already gone', function() { + beforeEach(function() { + this.fakeError = new Error('woops'); + this.fakeError.statusCode = 404; + this.fakeContainer = + {remove: sinon.stub().callsArgWith(1, this.fakeError)}; + return this.Docker.prototype.getContainer = sinon.stub().returns(this.fakeContainer); + }); - it 'should not produce an error', (done) -> - @DockerRunner._destroyContainer @containerId, false, (err) => - expect(err).to.equal null - done() + return it('should not produce an error', function(done) { + return this.DockerRunner._destroyContainer(this.containerId, false, err => { + expect(err).to.equal(null); + return done(); + }); + }); + }); - describe 'when container.destroy produces an error', (done) -> - beforeEach -> - @fakeError = new Error('woops') - @fakeError.statusCode = 500 - @fakeContainer = - remove: sinon.stub().callsArgWith(1, @fakeError) - @Docker::getContainer = sinon.stub().returns(@fakeContainer) + return describe('when container.destroy produces an error', function(done) { + beforeEach(function() { + this.fakeError = new Error('woops'); + this.fakeError.statusCode = 500; + this.fakeContainer = + {remove: sinon.stub().callsArgWith(1, this.fakeError)}; + return this.Docker.prototype.getContainer = sinon.stub().returns(this.fakeContainer); + }); - it 'should produce an error', (done) -> - @DockerRunner._destroyContainer @containerId, false, (err) => - expect(err).to.not.equal null - expect(err).to.equal @fakeError - done() + return it('should produce an error', function(done) { + return this.DockerRunner._destroyContainer(this.containerId, false, err => { + expect(err).to.not.equal(null); + expect(err).to.equal(this.fakeError); + return done(); + }); + }); + }); + }); - describe 'kill', -> - beforeEach -> - @containerId = 'some_id' - @fakeContainer = - kill: sinon.stub().callsArgWith(0, null) - @Docker::getContainer = sinon.stub().returns(@fakeContainer) + return describe('kill', function() { + beforeEach(function() { + this.containerId = 'some_id'; + this.fakeContainer = + {kill: sinon.stub().callsArgWith(0, null)}; + return this.Docker.prototype.getContainer = sinon.stub().returns(this.fakeContainer); + }); - it 'should get the container', (done) -> - @DockerRunner.kill @containerId, (err) => - @Docker::getContainer.callCount.should.equal 1 - @Docker::getContainer.calledWith(@containerId).should.equal true - done() + it('should get the container', function(done) { + return this.DockerRunner.kill(this.containerId, err => { + this.Docker.prototype.getContainer.callCount.should.equal(1); + this.Docker.prototype.getContainer.calledWith(this.containerId).should.equal(true); + return done(); + }); + }); - it 'should try to force-destroy the container', (done) -> - @DockerRunner.kill @containerId, (err) => - @fakeContainer.kill.callCount.should.equal 1 - done() + it('should try to force-destroy the container', function(done) { + return this.DockerRunner.kill(this.containerId, err => { + this.fakeContainer.kill.callCount.should.equal(1); + return done(); + }); + }); - it 'should not produce an error', (done) -> - @DockerRunner.kill @containerId, (err) => - expect(err).to.equal undefined - done() + it('should not produce an error', function(done) { + return this.DockerRunner.kill(this.containerId, err => { + expect(err).to.equal(undefined); + return done(); + }); + }); - describe 'when the container is not actually running', -> - beforeEach -> - @fakeError = new Error('woops') - @fakeError.statusCode = 500 - @fakeError.message = 'Cannot kill container is not running' - @fakeContainer = - kill: sinon.stub().callsArgWith(0, @fakeError) - @Docker::getContainer = sinon.stub().returns(@fakeContainer) + describe('when the container is not actually running', function() { + beforeEach(function() { + this.fakeError = new Error('woops'); + this.fakeError.statusCode = 500; + this.fakeError.message = 'Cannot kill container is not running'; + this.fakeContainer = + {kill: sinon.stub().callsArgWith(0, this.fakeError)}; + return this.Docker.prototype.getContainer = sinon.stub().returns(this.fakeContainer); + }); - it 'should not produce an error', (done) -> - @DockerRunner.kill @containerId, (err) => - expect(err).to.equal undefined - done() + return it('should not produce an error', function(done) { + return this.DockerRunner.kill(this.containerId, err => { + expect(err).to.equal(undefined); + return done(); + }); + }); + }); - describe 'when container.kill produces a legitimate error', (done) -> - beforeEach -> - @fakeError = new Error('woops') - @fakeError.statusCode = 500 - @fakeError.message = 'Totally legitimate reason to throw an error' - @fakeContainer = - kill: sinon.stub().callsArgWith(0, @fakeError) - @Docker::getContainer = sinon.stub().returns(@fakeContainer) + return describe('when container.kill produces a legitimate error', function(done) { + beforeEach(function() { + this.fakeError = new Error('woops'); + this.fakeError.statusCode = 500; + this.fakeError.message = 'Totally legitimate reason to throw an error'; + this.fakeContainer = + {kill: sinon.stub().callsArgWith(0, this.fakeError)}; + return this.Docker.prototype.getContainer = sinon.stub().returns(this.fakeContainer); + }); - it 'should produce an error', (done) -> - @DockerRunner.kill @containerId, (err) => - expect(err).to.not.equal undefined - expect(err).to.equal @fakeError - done() + return it('should produce an error', function(done) { + return this.DockerRunner.kill(this.containerId, err => { + expect(err).to.not.equal(undefined); + expect(err).to.equal(this.fakeError); + return done(); + }); + }); + }); + }); +}); diff --git a/test/unit/coffee/DraftModeManagerTests.js b/test/unit/coffee/DraftModeManagerTests.js index 549be29..ffea050 100644 --- a/test/unit/coffee/DraftModeManagerTests.js +++ b/test/unit/coffee/DraftModeManagerTests.js @@ -1,61 +1,77 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/DraftModeManager' +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/DraftModeManager'); -describe 'DraftModeManager', -> - beforeEach -> - @DraftModeManager = SandboxedModule.require modulePath, requires: - "fs": @fs = {} - "logger-sharelatex": @logger = {log: () ->} +describe('DraftModeManager', function() { + beforeEach(function() { + return this.DraftModeManager = SandboxedModule.require(modulePath, { requires: { + "fs": (this.fs = {}), + "logger-sharelatex": (this.logger = {log() {}}) + } + });}); - describe "_injectDraftOption", -> - it "should add draft option into documentclass with existing options", -> - @DraftModeManager - ._injectDraftOption(''' - \\documentclass[a4paper,foo=bar]{article} - ''') - .should.equal(''' - \\documentclass[draft,a4paper,foo=bar]{article} - ''') + describe("_injectDraftOption", function() { + it("should add draft option into documentclass with existing options", function() { + return this.DraftModeManager + ._injectDraftOption(`\ +\\documentclass[a4paper,foo=bar]{article}\ +`) + .should.equal(`\ +\\documentclass[draft,a4paper,foo=bar]{article}\ +`); + }); - it "should add draft option into documentclass with no options", -> - @DraftModeManager - ._injectDraftOption(''' - \\documentclass{article} - ''') - .should.equal(''' - \\documentclass[draft]{article} - ''') + return it("should add draft option into documentclass with no options", function() { + return this.DraftModeManager + ._injectDraftOption(`\ +\\documentclass{article}\ +`) + .should.equal(`\ +\\documentclass[draft]{article}\ +`); + }); + }); - describe "injectDraftMode", -> - beforeEach -> - @filename = "/mock/filename.tex" - @callback = sinon.stub() - content = ''' - \\documentclass{article} - \\begin{document} - Hello world - \\end{document} - ''' - @fs.readFile = sinon.stub().callsArgWith(2, null, content) - @fs.writeFile = sinon.stub().callsArg(2) - @DraftModeManager.injectDraftMode @filename, @callback + return describe("injectDraftMode", function() { + beforeEach(function() { + this.filename = "/mock/filename.tex"; + this.callback = sinon.stub(); + const content = `\ +\\documentclass{article} +\\begin{document} +Hello world +\\end{document}\ +`; + this.fs.readFile = sinon.stub().callsArgWith(2, null, content); + this.fs.writeFile = sinon.stub().callsArg(2); + return this.DraftModeManager.injectDraftMode(this.filename, this.callback); + }); - it "should read the file", -> - @fs.readFile - .calledWith(@filename, "utf8") - .should.equal true + it("should read the file", function() { + return this.fs.readFile + .calledWith(this.filename, "utf8") + .should.equal(true); + }); - it "should write the modified file", -> - @fs.writeFile - .calledWith(@filename, """ - \\documentclass[draft]{article} - \\begin{document} - Hello world - \\end{document} - """) - .should.equal true + it("should write the modified file", function() { + return this.fs.writeFile + .calledWith(this.filename, `\ +\\documentclass[draft]{article} +\\begin{document} +Hello world +\\end{document}\ +`) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); +}); diff --git a/test/unit/coffee/LatexRunnerTests.js b/test/unit/coffee/LatexRunnerTests.js index 77c6edb..5cb4d06 100644 --- a/test/unit/coffee/LatexRunnerTests.js +++ b/test/unit/coffee/LatexRunnerTests.js @@ -1,79 +1,105 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/LatexRunner' -Path = require "path" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/LatexRunner'); +const Path = require("path"); -describe "LatexRunner", -> - beforeEach -> - @LatexRunner = SandboxedModule.require modulePath, requires: - "settings-sharelatex": @Settings = - docker: +describe("LatexRunner", function() { + beforeEach(function() { + let Timer; + this.LatexRunner = SandboxedModule.require(modulePath, { requires: { + "settings-sharelatex": (this.Settings = { + docker: { socketPath: "/var/run/docker.sock" - "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() } - "./Metrics": - Timer: class Timer - done: () -> - "./CommandRunner": @CommandRunner = {} + } + }), + "logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }), + "./Metrics": { + Timer: (Timer = class Timer { + done() {} + }) + }, + "./CommandRunner": (this.CommandRunner = {}) + } + }); - @directory = "/local/compile/directory" - @mainFile = "main-file.tex" - @compiler = "pdflatex" - @image = "example.com/image" - @callback = sinon.stub() - @project_id = "project-id-123" - @env = {'foo': '123'} + this.directory = "/local/compile/directory"; + this.mainFile = "main-file.tex"; + this.compiler = "pdflatex"; + this.image = "example.com/image"; + this.callback = sinon.stub(); + this.project_id = "project-id-123"; + return this.env = {'foo': '123'};}); - describe "runLatex", -> - beforeEach -> - @CommandRunner.run = sinon.stub().callsArg(6) + return describe("runLatex", function() { + beforeEach(function() { + return this.CommandRunner.run = sinon.stub().callsArg(6); + }); - describe "normally", -> - beforeEach -> - @LatexRunner.runLatex @project_id, - directory: @directory - mainFile: @mainFile - compiler: @compiler - timeout: @timeout = 42000 - image: @image - environment: @env - @callback + describe("normally", function() { + beforeEach(function() { + return this.LatexRunner.runLatex(this.project_id, { + directory: this.directory, + mainFile: this.mainFile, + compiler: this.compiler, + timeout: (this.timeout = 42000), + image: this.image, + environment: this.env + }, + this.callback); + }); - it "should run the latex command", -> - @CommandRunner.run - .calledWith(@project_id, sinon.match.any, @directory, @image, @timeout, @env) - .should.equal true + return it("should run the latex command", function() { + return this.CommandRunner.run + .calledWith(this.project_id, sinon.match.any, this.directory, this.image, this.timeout, this.env) + .should.equal(true); + }); + }); - describe "with an .Rtex main file", -> - beforeEach -> - @LatexRunner.runLatex @project_id, - directory: @directory - mainFile: "main-file.Rtex" - compiler: @compiler - image: @image - timeout: @timeout = 42000 - @callback + describe("with an .Rtex main file", function() { + beforeEach(function() { + return this.LatexRunner.runLatex(this.project_id, { + directory: this.directory, + mainFile: "main-file.Rtex", + compiler: this.compiler, + image: this.image, + timeout: (this.timeout = 42000) + }, + this.callback); + }); - it "should run the latex command on the equivalent .tex file", -> - command = @CommandRunner.run.args[0][1] - mainFile = command.slice(-1)[0] - mainFile.should.equal "$COMPILE_DIR/main-file.tex" + return it("should run the latex command on the equivalent .tex file", function() { + const command = this.CommandRunner.run.args[0][1]; + const mainFile = command.slice(-1)[0]; + return mainFile.should.equal("$COMPILE_DIR/main-file.tex"); + }); + }); - describe "with a flags option", -> - beforeEach -> - @LatexRunner.runLatex @project_id, - directory: @directory - mainFile: @mainFile - compiler: @compiler - image: @image - timeout: @timeout = 42000 + return describe("with a flags option", function() { + beforeEach(function() { + return this.LatexRunner.runLatex(this.project_id, { + directory: this.directory, + mainFile: this.mainFile, + compiler: this.compiler, + image: this.image, + timeout: (this.timeout = 42000), flags: ["-file-line-error", "-halt-on-error"] - @callback + }, + this.callback); + }); - it "should include the flags in the command", -> - command = @CommandRunner.run.args[0][1] - flags = command.filter (arg) -> - (arg == "-file-line-error") || (arg == "-halt-on-error") - flags.length.should.equal 2 - flags[0].should.equal "-file-line-error" - flags[1].should.equal "-halt-on-error" + return it("should include the flags in the command", function() { + const command = this.CommandRunner.run.args[0][1]; + const flags = command.filter(arg => (arg === "-file-line-error") || (arg === "-halt-on-error")); + flags.length.should.equal(2); + flags[0].should.equal("-file-line-error"); + return flags[1].should.equal("-halt-on-error"); + }); + }); + }); +}); diff --git a/test/unit/coffee/LockManagerTests.js b/test/unit/coffee/LockManagerTests.js index 9dd1d46..d716a44 100644 --- a/test/unit/coffee/LockManagerTests.js +++ b/test/unit/coffee/LockManagerTests.js @@ -1,57 +1,77 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/LockManager' -Path = require "path" -Errors = require "../../../app/js/Errors" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/LockManager'); +const Path = require("path"); +const Errors = require("../../../app/js/Errors"); -describe "DockerLockManager", -> - beforeEach -> - @LockManager = SandboxedModule.require modulePath, requires: - "settings-sharelatex": {} - "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub(), err:-> } - "fs": - lstat:sinon.stub().callsArgWith(1) +describe("DockerLockManager", function() { + beforeEach(function() { + this.LockManager = SandboxedModule.require(modulePath, { requires: { + "settings-sharelatex": {}, + "logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub(), err() {} }), + "fs": { + lstat:sinon.stub().callsArgWith(1), readdir: sinon.stub().callsArgWith(1) - "lockfile": @Lockfile = {} - @lockFile = "/local/compile/directory/.project-lock" + }, + "lockfile": (this.Lockfile = {}) + } + }); + return this.lockFile = "/local/compile/directory/.project-lock"; + }); - describe "runWithLock", -> - beforeEach -> - @runner = sinon.stub().callsArgWith(0, null, "foo", "bar") - @callback = sinon.stub() + return describe("runWithLock", function() { + beforeEach(function() { + this.runner = sinon.stub().callsArgWith(0, null, "foo", "bar"); + return this.callback = sinon.stub(); + }); - describe "normally", -> - beforeEach -> - @Lockfile.lock = sinon.stub().callsArgWith(2, null) - @Lockfile.unlock = sinon.stub().callsArgWith(1, null) - @LockManager.runWithLock @lockFile, @runner, @callback + describe("normally", function() { + beforeEach(function() { + this.Lockfile.lock = sinon.stub().callsArgWith(2, null); + this.Lockfile.unlock = sinon.stub().callsArgWith(1, null); + return this.LockManager.runWithLock(this.lockFile, this.runner, this.callback); + }); - it "should run the compile", -> - @runner + it("should run the compile", function() { + return this.runner .calledWith() - .should.equal true + .should.equal(true); + }); - it "should call the callback with the response from the compile", -> - @callback + return it("should call the callback with the response from the compile", function() { + return this.callback .calledWithExactly(null, "foo", "bar") - .should.equal true + .should.equal(true); + }); + }); - describe "when the project is locked", -> - beforeEach -> - @error = new Error() - @error.code = "EEXIST" - @Lockfile.lock = sinon.stub().callsArgWith(2,@error) - @Lockfile.unlock = sinon.stub().callsArgWith(1, null) - @LockManager.runWithLock @lockFile, @runner, @callback + return describe("when the project is locked", function() { + beforeEach(function() { + this.error = new Error(); + this.error.code = "EEXIST"; + this.Lockfile.lock = sinon.stub().callsArgWith(2,this.error); + this.Lockfile.unlock = sinon.stub().callsArgWith(1, null); + return this.LockManager.runWithLock(this.lockFile, this.runner, this.callback); + }); - it "should not run the compile", -> - @runner + it("should not run the compile", function() { + return this.runner .called - .should.equal false + .should.equal(false); + }); - it "should return an error", -> - error = new Errors.AlreadyCompilingError() - @callback + return it("should return an error", function() { + const error = new Errors.AlreadyCompilingError(); + return this.callback .calledWithExactly(error) - .should.equal true + .should.equal(true); + }); + }); + }); +}); diff --git a/test/unit/coffee/OutputFileFinderTests.js b/test/unit/coffee/OutputFileFinderTests.js index 46d8c1f..3292d0a 100644 --- a/test/unit/coffee/OutputFileFinderTests.js +++ b/test/unit/coffee/OutputFileFinderTests.js @@ -1,68 +1,92 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/OutputFileFinder' -path = require "path" -expect = require("chai").expect -EventEmitter = require("events").EventEmitter +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/OutputFileFinder'); +const path = require("path"); +const { expect } = require("chai"); +const { EventEmitter } = require("events"); -describe "OutputFileFinder", -> - beforeEach -> - @OutputFileFinder = SandboxedModule.require modulePath, requires: - "fs": @fs = {} - "child_process": spawn: @spawn = sinon.stub() +describe("OutputFileFinder", function() { + beforeEach(function() { + this.OutputFileFinder = SandboxedModule.require(modulePath, { requires: { + "fs": (this.fs = {}), + "child_process": { spawn: (this.spawn = sinon.stub()) + }, "logger-sharelatex": { log: sinon.stub(), warn: sinon.stub() } - @directory = "/test/dir" - @callback = sinon.stub() + } + }); + this.directory = "/test/dir"; + return this.callback = sinon.stub(); + }); - describe "findOutputFiles", -> - beforeEach -> - @resource_path = "resource/path.tex" - @output_paths = ["output.pdf", "extra/file.tex"] - @all_paths = @output_paths.concat [@resource_path] - @resources = [ - path: @resource_path = "resource/path.tex" - ] - @OutputFileFinder._getAllFiles = sinon.stub().callsArgWith(1, null, @all_paths) - @OutputFileFinder.findOutputFiles @resources, @directory, (error, @outputFiles) => + describe("findOutputFiles", function() { + beforeEach(function() { + this.resource_path = "resource/path.tex"; + this.output_paths = ["output.pdf", "extra/file.tex"]; + this.all_paths = this.output_paths.concat([this.resource_path]); + this.resources = [ + {path: (this.resource_path = "resource/path.tex")} + ]; + this.OutputFileFinder._getAllFiles = sinon.stub().callsArgWith(1, null, this.all_paths); + return this.OutputFileFinder.findOutputFiles(this.resources, this.directory, (error, outputFiles) => { + this.outputFiles = outputFiles; + + }); + }); - it "should only return the output files, not directories or resource paths", -> - expect(@outputFiles).to.deep.equal [{ - path: "output.pdf" + return it("should only return the output files, not directories or resource paths", function() { + return expect(this.outputFiles).to.deep.equal([{ + path: "output.pdf", type: "pdf" }, { path: "extra/file.tex", type: "tex" - }] + }]); + }); +}); - describe "_getAllFiles", -> - beforeEach -> - @proc = new EventEmitter() - @proc.stdout = new EventEmitter() - @spawn.returns @proc - @directory = "/base/dir" - @OutputFileFinder._getAllFiles @directory, @callback + return describe("_getAllFiles", function() { + beforeEach(function() { + this.proc = new EventEmitter(); + this.proc.stdout = new EventEmitter(); + this.spawn.returns(this.proc); + this.directory = "/base/dir"; + return this.OutputFileFinder._getAllFiles(this.directory, this.callback); + }); - describe "successfully", -> - beforeEach -> - @proc.stdout.emit( + describe("successfully", function() { + beforeEach(function() { + this.proc.stdout.emit( "data", ["/base/dir/main.tex", "/base/dir/chapters/chapter1.tex"].join("\n") + "\n" - ) - @proc.emit "close", 0 + ); + return this.proc.emit("close", 0); + }); - it "should call the callback with the relative file paths", -> - @callback.calledWith( + return it("should call the callback with the relative file paths", function() { + return this.callback.calledWith( null, ["main.tex", "chapters/chapter1.tex"] - ).should.equal true + ).should.equal(true); + }); + }); - describe "when the directory doesn't exist", -> - beforeEach -> - @proc.emit "close", 1 + return describe("when the directory doesn't exist", function() { + beforeEach(function() { + return this.proc.emit("close", 1); + }); - it "should call the callback with a blank array", -> - @callback.calledWith( + return it("should call the callback with a blank array", function() { + return this.callback.calledWith( null, [] - ).should.equal true + ).should.equal(true); + }); + }); + }); +}); diff --git a/test/unit/coffee/OutputFileOptimiserTests.js b/test/unit/coffee/OutputFileOptimiserTests.js index 2988715..8934c71 100644 --- a/test/unit/coffee/OutputFileOptimiserTests.js +++ b/test/unit/coffee/OutputFileOptimiserTests.js @@ -1,103 +1,141 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/OutputFileOptimiser' -path = require "path" -expect = require("chai").expect -EventEmitter = require("events").EventEmitter +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/OutputFileOptimiser'); +const path = require("path"); +const { expect } = require("chai"); +const { EventEmitter } = require("events"); -describe "OutputFileOptimiser", -> - beforeEach -> - @OutputFileOptimiser = SandboxedModule.require modulePath, requires: - "fs": @fs = {} - "path": @Path = {} - "child_process": spawn: @spawn = sinon.stub() - "logger-sharelatex": { log: sinon.stub(), warn: sinon.stub() } +describe("OutputFileOptimiser", function() { + beforeEach(function() { + this.OutputFileOptimiser = SandboxedModule.require(modulePath, { requires: { + "fs": (this.fs = {}), + "path": (this.Path = {}), + "child_process": { spawn: (this.spawn = sinon.stub()) + }, + "logger-sharelatex": { log: sinon.stub(), warn: sinon.stub() }, "./Metrics" : {} - @directory = "/test/dir" - @callback = sinon.stub() + } + }); + this.directory = "/test/dir"; + return this.callback = sinon.stub(); + }); - describe "optimiseFile", -> - beforeEach -> - @src = "./output.pdf" - @dst = "./output.pdf" + describe("optimiseFile", function() { + beforeEach(function() { + this.src = "./output.pdf"; + return this.dst = "./output.pdf"; + }); - describe "when the file is not a pdf file", -> - beforeEach (done)-> - @src = "./output.log" - @OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, false) - @OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null) - @OutputFileOptimiser.optimiseFile @src, @dst, done + describe("when the file is not a pdf file", function() { + beforeEach(function(done){ + this.src = "./output.log"; + this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, false); + this.OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null); + return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done); + }); - it "should not check if the file is optimised", -> - @OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(@src).should.equal false + it("should not check if the file is optimised", function() { + return this.OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(this.src).should.equal(false); + }); - it "should not optimise the file", -> - @OutputFileOptimiser.optimisePDF.calledWith(@src, @dst).should.equal false + return it("should not optimise the file", function() { + return this.OutputFileOptimiser.optimisePDF.calledWith(this.src, this.dst).should.equal(false); + }); + }); - describe "when the pdf file is not optimised", -> - beforeEach (done) -> - @OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, false) - @OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null) - @OutputFileOptimiser.optimiseFile @src, @dst, done + describe("when the pdf file is not optimised", function() { + beforeEach(function(done) { + this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, false); + this.OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null); + return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done); + }); - it "should check if the pdf is optimised", -> - @OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(@src).should.equal true + it("should check if the pdf is optimised", function() { + return this.OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(this.src).should.equal(true); + }); - it "should optimise the pdf", -> - @OutputFileOptimiser.optimisePDF.calledWith(@src, @dst).should.equal true + return it("should optimise the pdf", function() { + return this.OutputFileOptimiser.optimisePDF.calledWith(this.src, this.dst).should.equal(true); + }); + }); - describe "when the pdf file is optimised", -> - beforeEach (done) -> - @OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, true) - @OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null) - @OutputFileOptimiser.optimiseFile @src, @dst, done + return describe("when the pdf file is optimised", function() { + beforeEach(function(done) { + this.OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, true); + this.OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null); + return this.OutputFileOptimiser.optimiseFile(this.src, this.dst, done); + }); - it "should check if the pdf is optimised", -> - @OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(@src).should.equal true + it("should check if the pdf is optimised", function() { + return this.OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(this.src).should.equal(true); + }); - it "should not optimise the pdf", -> - @OutputFileOptimiser.optimisePDF.calledWith(@src, @dst).should.equal false + return it("should not optimise the pdf", function() { + return this.OutputFileOptimiser.optimisePDF.calledWith(this.src, this.dst).should.equal(false); + }); + }); + }); - describe "checkIfPDFISOptimised", -> - beforeEach () -> - @callback = sinon.stub() - @fd = 1234 - @fs.open = sinon.stub().yields(null, @fd) - @fs.read = sinon.stub().withArgs(@fd).yields(null, 100, new Buffer("hello /Linearized 1")) - @fs.close = sinon.stub().withArgs(@fd).yields(null) - @OutputFileOptimiser.checkIfPDFIsOptimised @src, @callback + return describe("checkIfPDFISOptimised", function() { + beforeEach(function() { + this.callback = sinon.stub(); + this.fd = 1234; + this.fs.open = sinon.stub().yields(null, this.fd); + this.fs.read = sinon.stub().withArgs(this.fd).yields(null, 100, new Buffer("hello /Linearized 1")); + this.fs.close = sinon.stub().withArgs(this.fd).yields(null); + return this.OutputFileOptimiser.checkIfPDFIsOptimised(this.src, this.callback); + }); - describe "for a linearised file", -> - beforeEach () -> - @fs.read = sinon.stub().withArgs(@fd).yields(null, 100, new Buffer("hello /Linearized 1")) - @OutputFileOptimiser.checkIfPDFIsOptimised @src, @callback + describe("for a linearised file", function() { + beforeEach(function() { + this.fs.read = sinon.stub().withArgs(this.fd).yields(null, 100, new Buffer("hello /Linearized 1")); + return this.OutputFileOptimiser.checkIfPDFIsOptimised(this.src, this.callback); + }); - it "should open the file", -> - @fs.open.calledWith(@src, "r").should.equal true + it("should open the file", function() { + return this.fs.open.calledWith(this.src, "r").should.equal(true); + }); - it "should read the header", -> - @fs.read.calledWith(@fd).should.equal true + it("should read the header", function() { + return this.fs.read.calledWith(this.fd).should.equal(true); + }); - it "should close the file", -> - @fs.close.calledWith(@fd).should.equal true + it("should close the file", function() { + return this.fs.close.calledWith(this.fd).should.equal(true); + }); - it "should call the callback with a true result", -> - @callback.calledWith(null, true).should.equal true + return it("should call the callback with a true result", function() { + return this.callback.calledWith(null, true).should.equal(true); + }); + }); - describe "for an unlinearised file", -> - beforeEach () -> - @fs.read = sinon.stub().withArgs(@fd).yields(null, 100, new Buffer("hello not linearized 1")) - @OutputFileOptimiser.checkIfPDFIsOptimised @src, @callback + return describe("for an unlinearised file", function() { + beforeEach(function() { + this.fs.read = sinon.stub().withArgs(this.fd).yields(null, 100, new Buffer("hello not linearized 1")); + return this.OutputFileOptimiser.checkIfPDFIsOptimised(this.src, this.callback); + }); - it "should open the file", -> - @fs.open.calledWith(@src, "r").should.equal true + it("should open the file", function() { + return this.fs.open.calledWith(this.src, "r").should.equal(true); + }); - it "should read the header", -> - @fs.read.calledWith(@fd).should.equal true + it("should read the header", function() { + return this.fs.read.calledWith(this.fd).should.equal(true); + }); - it "should close the file", -> - @fs.close.calledWith(@fd).should.equal true + it("should close the file", function() { + return this.fs.close.calledWith(this.fd).should.equal(true); + }); - it "should call the callback with a false result", -> - @callback.calledWith(null, false).should.equal true + return it("should call the callback with a false result", function() { + return this.callback.calledWith(null, false).should.equal(true); + }); + }); + }); +}); diff --git a/test/unit/coffee/ProjectPersistenceManagerTests.js b/test/unit/coffee/ProjectPersistenceManagerTests.js index 69bfd4f..c15cd80 100644 --- a/test/unit/coffee/ProjectPersistenceManagerTests.js +++ b/test/unit/coffee/ProjectPersistenceManagerTests.js @@ -1,62 +1,82 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/ProjectPersistenceManager' -tk = require("timekeeper") +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/ProjectPersistenceManager'); +const tk = require("timekeeper"); -describe "ProjectPersistenceManager", -> - beforeEach -> - @ProjectPersistenceManager = SandboxedModule.require modulePath, requires: - "./UrlCache": @UrlCache = {} - "./CompileManager": @CompileManager = {} - "logger-sharelatex": @logger = { log: sinon.stub() } - "./db": @db = {} - @callback = sinon.stub() - @project_id = "project-id-123" - @user_id = "1234" +describe("ProjectPersistenceManager", function() { + beforeEach(function() { + this.ProjectPersistenceManager = SandboxedModule.require(modulePath, { requires: { + "./UrlCache": (this.UrlCache = {}), + "./CompileManager": (this.CompileManager = {}), + "logger-sharelatex": (this.logger = { log: sinon.stub() }), + "./db": (this.db = {}) + } + }); + this.callback = sinon.stub(); + this.project_id = "project-id-123"; + return this.user_id = "1234"; + }); - describe "clearExpiredProjects", -> - beforeEach -> - @project_ids = [ - "project-id-1" + describe("clearExpiredProjects", function() { + beforeEach(function() { + this.project_ids = [ + "project-id-1", "project-id-2" - ] - @ProjectPersistenceManager._findExpiredProjectIds = sinon.stub().callsArgWith(0, null, @project_ids) - @ProjectPersistenceManager.clearProjectFromCache = sinon.stub().callsArg(1) - @CompileManager.clearExpiredProjects = sinon.stub().callsArg(1) - @ProjectPersistenceManager.clearExpiredProjects @callback + ]; + this.ProjectPersistenceManager._findExpiredProjectIds = sinon.stub().callsArgWith(0, null, this.project_ids); + this.ProjectPersistenceManager.clearProjectFromCache = sinon.stub().callsArg(1); + this.CompileManager.clearExpiredProjects = sinon.stub().callsArg(1); + return this.ProjectPersistenceManager.clearExpiredProjects(this.callback); + }); - it "should clear each expired project", -> - for project_id in @project_ids - @ProjectPersistenceManager.clearProjectFromCache + it("should clear each expired project", function() { + return Array.from(this.project_ids).map((project_id) => + this.ProjectPersistenceManager.clearProjectFromCache .calledWith(project_id) - .should.equal true + .should.equal(true)); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "clearProject", -> - beforeEach -> - @ProjectPersistenceManager._clearProjectFromDatabase = sinon.stub().callsArg(1) - @UrlCache.clearProject = sinon.stub().callsArg(1) - @CompileManager.clearProject = sinon.stub().callsArg(2) - @ProjectPersistenceManager.clearProject @project_id, @user_id, @callback + return describe("clearProject", function() { + beforeEach(function() { + this.ProjectPersistenceManager._clearProjectFromDatabase = sinon.stub().callsArg(1); + this.UrlCache.clearProject = sinon.stub().callsArg(1); + this.CompileManager.clearProject = sinon.stub().callsArg(2); + return this.ProjectPersistenceManager.clearProject(this.project_id, this.user_id, this.callback); + }); - it "should clear the project from the database", -> - @ProjectPersistenceManager._clearProjectFromDatabase - .calledWith(@project_id) - .should.equal true + it("should clear the project from the database", function() { + return this.ProjectPersistenceManager._clearProjectFromDatabase + .calledWith(this.project_id) + .should.equal(true); + }); - it "should clear all the cached Urls for the project", -> - @UrlCache.clearProject - .calledWith(@project_id) - .should.equal true + it("should clear all the cached Urls for the project", function() { + return this.UrlCache.clearProject + .calledWith(this.project_id) + .should.equal(true); + }); - it "should clear the project compile folder", -> - @CompileManager.clearProject - .calledWith(@project_id, @user_id) - .should.equal true + it("should clear the project compile folder", function() { + return this.CompileManager.clearProject + .calledWith(this.project_id, this.user_id) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); +}); diff --git a/test/unit/coffee/RequestParserTests.js b/test/unit/coffee/RequestParserTests.js index e263e49..5ca0941 100644 --- a/test/unit/coffee/RequestParserTests.js +++ b/test/unit/coffee/RequestParserTests.js @@ -1,279 +1,380 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -expect = require('chai').expect -modulePath = require('path').join __dirname, '../../../app/js/RequestParser' -tk = require("timekeeper") +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const { expect } = require('chai'); +const modulePath = require('path').join(__dirname, '../../../app/js/RequestParser'); +const tk = require("timekeeper"); -describe "RequestParser", -> - beforeEach -> - tk.freeze() - @callback = sinon.stub() - @validResource = - path: "main.tex" - date: "12:00 01/02/03" +describe("RequestParser", function() { + beforeEach(function() { + tk.freeze(); + this.callback = sinon.stub(); + this.validResource = { + path: "main.tex", + date: "12:00 01/02/03", content: "Hello world" - @validRequest = - compile: - token: "token-123" - options: - imageName: "basicImageName/here:2017-1" - compiler: "pdflatex" + }; + this.validRequest = { + compile: { + token: "token-123", + options: { + imageName: "basicImageName/here:2017-1", + compiler: "pdflatex", timeout: 42 + }, resources: [] - @RequestParser = SandboxedModule.require modulePath, requires: - "settings-sharelatex": @settings = {} + } + }; + return this.RequestParser = SandboxedModule.require(modulePath, { requires: { + "settings-sharelatex": (this.settings = {}) + } + });}); - afterEach -> - tk.reset() + afterEach(() => tk.reset()); - describe "without a top level object", -> - beforeEach -> - @RequestParser.parse [], @callback + describe("without a top level object", function() { + beforeEach(function() { + return this.RequestParser.parse([], this.callback); + }); - it "should return an error", -> - @callback.calledWith("top level object should have a compile attribute") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("top level object should have a compile attribute") + .should.equal(true); + }); + }); - describe "without a compile attribute", -> - beforeEach -> - @RequestParser.parse {}, @callback + describe("without a compile attribute", function() { + beforeEach(function() { + return this.RequestParser.parse({}, this.callback); + }); - it "should return an error", -> - @callback.calledWith("top level object should have a compile attribute") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("top level object should have a compile attribute") + .should.equal(true); + }); + }); - describe "without a valid compiler", -> - beforeEach -> - @validRequest.compile.options.compiler = "not-a-compiler" - @RequestParser.parse @validRequest, @callback + describe("without a valid compiler", function() { + beforeEach(function() { + this.validRequest.compile.options.compiler = "not-a-compiler"; + return this.RequestParser.parse(this.validRequest, this.callback); + }); - it "should return an error", -> - @callback.calledWith("compiler attribute should be one of: pdflatex, latex, xelatex, lualatex") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("compiler attribute should be one of: pdflatex, latex, xelatex, lualatex") + .should.equal(true); + }); + }); - describe "without a compiler specified", -> - beforeEach -> - delete @validRequest.compile.options.compiler - @RequestParser.parse @validRequest, (error, @data) => + describe("without a compiler specified", function() { + beforeEach(function() { + delete this.validRequest.compile.options.compiler; + return this.RequestParser.parse(this.validRequest, (error, data) => { + this.data = data; + + }); + }); - it "should set the compiler to pdflatex by default", -> - @data.compiler.should.equal "pdflatex" + return it("should set the compiler to pdflatex by default", function() { + return this.data.compiler.should.equal("pdflatex"); + }); + }); - describe "with imageName set", -> - beforeEach -> - @RequestParser.parse @validRequest, (error, @data) => + describe("with imageName set", function() { + beforeEach(function() { + return this.RequestParser.parse(this.validRequest, (error, data) => { + this.data = data; + + }); + }); - it "should set the imageName", -> - @data.imageName.should.equal "basicImageName/here:2017-1" + return it("should set the imageName", function() { + return this.data.imageName.should.equal("basicImageName/here:2017-1"); + }); + }); - describe "with flags set", -> - beforeEach -> - @validRequest.compile.options.flags = ["-file-line-error"] - @RequestParser.parse @validRequest, (error, @data) => + describe("with flags set", function() { + beforeEach(function() { + this.validRequest.compile.options.flags = ["-file-line-error"]; + return this.RequestParser.parse(this.validRequest, (error, data) => { + this.data = data; + + }); + }); - it "should set the flags attribute", -> - expect(@data.flags).to.deep.equal ["-file-line-error"] + return it("should set the flags attribute", function() { + return expect(this.data.flags).to.deep.equal(["-file-line-error"]); + }); +}); - describe "with flags not specified", -> - beforeEach -> - @RequestParser.parse @validRequest, (error, @data) => + describe("with flags not specified", function() { + beforeEach(function() { + return this.RequestParser.parse(this.validRequest, (error, data) => { + this.data = data; + + }); + }); - it "it should have an empty flags list", -> - expect(@data.flags).to.deep.equal [] + return it("it should have an empty flags list", function() { + return expect(this.data.flags).to.deep.equal([]); + }); +}); - describe "without a timeout specified", -> - beforeEach -> - delete @validRequest.compile.options.timeout - @RequestParser.parse @validRequest, (error, @data) => + describe("without a timeout specified", function() { + beforeEach(function() { + delete this.validRequest.compile.options.timeout; + return this.RequestParser.parse(this.validRequest, (error, data) => { + this.data = data; + + }); + }); - it "should set the timeout to MAX_TIMEOUT", -> - @data.timeout.should.equal @RequestParser.MAX_TIMEOUT * 1000 + return it("should set the timeout to MAX_TIMEOUT", function() { + return this.data.timeout.should.equal(this.RequestParser.MAX_TIMEOUT * 1000); + }); + }); - describe "with a timeout larger than the maximum", -> - beforeEach -> - @validRequest.compile.options.timeout = @RequestParser.MAX_TIMEOUT + 1 - @RequestParser.parse @validRequest, (error, @data) => + describe("with a timeout larger than the maximum", function() { + beforeEach(function() { + this.validRequest.compile.options.timeout = this.RequestParser.MAX_TIMEOUT + 1; + return this.RequestParser.parse(this.validRequest, (error, data) => { + this.data = data; + + }); + }); - it "should set the timeout to MAX_TIMEOUT", -> - @data.timeout.should.equal @RequestParser.MAX_TIMEOUT * 1000 + return it("should set the timeout to MAX_TIMEOUT", function() { + return this.data.timeout.should.equal(this.RequestParser.MAX_TIMEOUT * 1000); + }); + }); - describe "with a timeout", -> - beforeEach -> - @RequestParser.parse @validRequest, (error, @data) => + describe("with a timeout", function() { + beforeEach(function() { + return this.RequestParser.parse(this.validRequest, (error, data) => { + this.data = data; + + }); + }); - it "should set the timeout (in milliseconds)", -> - @data.timeout.should.equal @validRequest.compile.options.timeout * 1000 + return it("should set the timeout (in milliseconds)", function() { + return this.data.timeout.should.equal(this.validRequest.compile.options.timeout * 1000); + }); + }); - describe "with a resource without a path", -> - beforeEach -> - delete @validResource.path - @validRequest.compile.resources.push @validResource - @RequestParser.parse @validRequest, @callback + describe("with a resource without a path", function() { + beforeEach(function() { + delete this.validResource.path; + this.validRequest.compile.resources.push(this.validResource); + return this.RequestParser.parse(this.validRequest, this.callback); + }); - it "should return an error", -> - @callback.calledWith("all resources should have a path attribute") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("all resources should have a path attribute") + .should.equal(true); + }); + }); - describe "with a resource with a path", -> - beforeEach -> - @validResource.path = @path = "test.tex" - @validRequest.compile.resources.push @validResource - @RequestParser.parse @validRequest, @callback - @data = @callback.args[0][1] + describe("with a resource with a path", function() { + beforeEach(function() { + this.validResource.path = (this.path = "test.tex"); + this.validRequest.compile.resources.push(this.validResource); + this.RequestParser.parse(this.validRequest, this.callback); + return this.data = this.callback.args[0][1];}); - it "should return the path in the parsed response", -> - @data.resources[0].path.should.equal @path + return it("should return the path in the parsed response", function() { + return this.data.resources[0].path.should.equal(this.path); + }); + }); - describe "with a resource with a malformed modified date", -> - beforeEach -> - @validResource.modified = "not-a-date" - @validRequest.compile.resources.push @validResource - @RequestParser.parse @validRequest, @callback + describe("with a resource with a malformed modified date", function() { + beforeEach(function() { + this.validResource.modified = "not-a-date"; + this.validRequest.compile.resources.push(this.validResource); + return this.RequestParser.parse(this.validRequest, this.callback); + }); - it "should return an error", -> - @callback + return it("should return an error", function() { + return this.callback .calledWith( "resource modified date could not be understood: "+ - @validResource.modified + this.validResource.modified ) - .should.equal true + .should.equal(true); + }); + }); - describe "with a resource with a valid date", -> - beforeEach -> - @date = "12:00 01/02/03" - @validResource.modified = @date - @validRequest.compile.resources.push @validResource - @RequestParser.parse @validRequest, @callback - @data = @callback.args[0][1] + describe("with a resource with a valid date", function() { + beforeEach(function() { + this.date = "12:00 01/02/03"; + this.validResource.modified = this.date; + this.validRequest.compile.resources.push(this.validResource); + this.RequestParser.parse(this.validRequest, this.callback); + return this.data = this.callback.args[0][1];}); - it "should return the date as a Javascript Date object", -> - (@data.resources[0].modified instanceof Date).should.equal true - @data.resources[0].modified.getTime().should.equal Date.parse(@date) + return it("should return the date as a Javascript Date object", function() { + (this.data.resources[0].modified instanceof Date).should.equal(true); + return this.data.resources[0].modified.getTime().should.equal(Date.parse(this.date)); + }); + }); - describe "with a resource without either a content or URL attribute", -> - beforeEach -> - delete @validResource.url - delete @validResource.content - @validRequest.compile.resources.push @validResource - @RequestParser.parse @validRequest, @callback + describe("with a resource without either a content or URL attribute", function() { + beforeEach(function() { + delete this.validResource.url; + delete this.validResource.content; + this.validRequest.compile.resources.push(this.validResource); + return this.RequestParser.parse(this.validRequest, this.callback); + }); - it "should return an error", -> - @callback.calledWith("all resources should have either a url or content attribute") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("all resources should have either a url or content attribute") + .should.equal(true); + }); + }); - describe "with a resource where the content is not a string", -> - beforeEach -> - @validResource.content = [] - @validRequest.compile.resources.push @validResource - @RequestParser.parse (@validRequest), @callback + describe("with a resource where the content is not a string", function() { + beforeEach(function() { + this.validResource.content = []; + this.validRequest.compile.resources.push(this.validResource); + return this.RequestParser.parse((this.validRequest), this.callback); + }); - it "should return an error", -> - @callback.calledWith("content attribute should be a string") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("content attribute should be a string") + .should.equal(true); + }); + }); - describe "with a resource where the url is not a string", -> - beforeEach -> - @validResource.url = [] - @validRequest.compile.resources.push @validResource - @RequestParser.parse (@validRequest), @callback + describe("with a resource where the url is not a string", function() { + beforeEach(function() { + this.validResource.url = []; + this.validRequest.compile.resources.push(this.validResource); + return this.RequestParser.parse((this.validRequest), this.callback); + }); - it "should return an error", -> - @callback.calledWith("url attribute should be a string") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("url attribute should be a string") + .should.equal(true); + }); + }); - describe "with a resource with a url", -> - beforeEach -> - @validResource.url = @url = "www.example.com" - @validRequest.compile.resources.push @validResource - @RequestParser.parse (@validRequest), @callback - @data = @callback.args[0][1] + describe("with a resource with a url", function() { + beforeEach(function() { + this.validResource.url = (this.url = "www.example.com"); + this.validRequest.compile.resources.push(this.validResource); + this.RequestParser.parse((this.validRequest), this.callback); + return this.data = this.callback.args[0][1];}); - it "should return the url in the parsed response", -> - @data.resources[0].url.should.equal @url + return it("should return the url in the parsed response", function() { + return this.data.resources[0].url.should.equal(this.url); + }); + }); - describe "with a resource with a content attribute", -> - beforeEach -> - @validResource.content = @content = "Hello world" - @validRequest.compile.resources.push @validResource - @RequestParser.parse (@validRequest), @callback - @data = @callback.args[0][1] + describe("with a resource with a content attribute", function() { + beforeEach(function() { + this.validResource.content = (this.content = "Hello world"); + this.validRequest.compile.resources.push(this.validResource); + this.RequestParser.parse((this.validRequest), this.callback); + return this.data = this.callback.args[0][1];}); - it "should return the content in the parsed response", -> - @data.resources[0].content.should.equal @content + return it("should return the content in the parsed response", function() { + return this.data.resources[0].content.should.equal(this.content); + }); + }); - describe "without a root resource path", -> - beforeEach -> - delete @validRequest.compile.rootResourcePath - @RequestParser.parse (@validRequest), @callback - @data = @callback.args[0][1] + describe("without a root resource path", function() { + beforeEach(function() { + delete this.validRequest.compile.rootResourcePath; + this.RequestParser.parse((this.validRequest), this.callback); + return this.data = this.callback.args[0][1];}); - it "should set the root resource path to 'main.tex' by default", -> - @data.rootResourcePath.should.equal "main.tex" + return it("should set the root resource path to 'main.tex' by default", function() { + return this.data.rootResourcePath.should.equal("main.tex"); + }); + }); - describe "with a root resource path", -> - beforeEach -> - @validRequest.compile.rootResourcePath = @path = "test.tex" - @RequestParser.parse (@validRequest), @callback - @data = @callback.args[0][1] + describe("with a root resource path", function() { + beforeEach(function() { + this.validRequest.compile.rootResourcePath = (this.path = "test.tex"); + this.RequestParser.parse((this.validRequest), this.callback); + return this.data = this.callback.args[0][1];}); - it "should return the root resource path in the parsed response", -> - @data.rootResourcePath.should.equal @path + return it("should return the root resource path in the parsed response", function() { + return this.data.rootResourcePath.should.equal(this.path); + }); + }); - describe "with a root resource path that is not a string", -> - beforeEach -> - @validRequest.compile.rootResourcePath = [] - @RequestParser.parse (@validRequest), @callback + describe("with a root resource path that is not a string", function() { + beforeEach(function() { + this.validRequest.compile.rootResourcePath = []; + return this.RequestParser.parse((this.validRequest), this.callback); + }); - it "should return an error", -> - @callback.calledWith("rootResourcePath attribute should be a string") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("rootResourcePath attribute should be a string") + .should.equal(true); + }); + }); - describe "with a root resource path that needs escaping", -> - beforeEach -> - @badPath = "`rm -rf foo`.tex" - @goodPath = "rm -rf foo.tex" - @validRequest.compile.rootResourcePath = @badPath - @validRequest.compile.resources.push { - path: @badPath - date: "12:00 01/02/03" + describe("with a root resource path that needs escaping", function() { + beforeEach(function() { + this.badPath = "`rm -rf foo`.tex"; + this.goodPath = "rm -rf foo.tex"; + this.validRequest.compile.rootResourcePath = this.badPath; + this.validRequest.compile.resources.push({ + path: this.badPath, + date: "12:00 01/02/03", content: "Hello world" - } - @RequestParser.parse @validRequest, @callback - @data = @callback.args[0][1] + }); + this.RequestParser.parse(this.validRequest, this.callback); + return this.data = this.callback.args[0][1];}); - it "should return the escaped resource", -> - @data.rootResourcePath.should.equal @goodPath + it("should return the escaped resource", function() { + return this.data.rootResourcePath.should.equal(this.goodPath); + }); - it "should also escape the resource path", -> - @data.resources[0].path.should.equal @goodPath + return it("should also escape the resource path", function() { + return this.data.resources[0].path.should.equal(this.goodPath); + }); + }); - describe "with a root resource path that has a relative path", -> - beforeEach -> - @validRequest.compile.rootResourcePath = "foo/../../bar.tex" - @RequestParser.parse @validRequest, @callback - @data = @callback.args[0][1] + describe("with a root resource path that has a relative path", function() { + beforeEach(function() { + this.validRequest.compile.rootResourcePath = "foo/../../bar.tex"; + this.RequestParser.parse(this.validRequest, this.callback); + return this.data = this.callback.args[0][1];}); - it "should return an error", -> - @callback.calledWith("relative path in root resource") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("relative path in root resource") + .should.equal(true); + }); + }); - describe "with a root resource path that has unescaped + relative path", -> - beforeEach -> - @validRequest.compile.rootResourcePath = "foo/#../bar.tex" - @RequestParser.parse @validRequest, @callback - @data = @callback.args[0][1] + describe("with a root resource path that has unescaped + relative path", function() { + beforeEach(function() { + this.validRequest.compile.rootResourcePath = "foo/#../bar.tex"; + this.RequestParser.parse(this.validRequest, this.callback); + return this.data = this.callback.args[0][1];}); - it "should return an error", -> - @callback.calledWith("relative path in root resource") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("relative path in root resource") + .should.equal(true); + }); + }); - describe "with an unknown syncType", -> - beforeEach -> - @validRequest.compile.options.syncType = "unexpected" - @RequestParser.parse @validRequest, @callback - @data = @callback.args[0][1] + return describe("with an unknown syncType", function() { + beforeEach(function() { + this.validRequest.compile.options.syncType = "unexpected"; + this.RequestParser.parse(this.validRequest, this.callback); + return this.data = this.callback.args[0][1];}); - it "should return an error", -> - @callback.calledWith("syncType attribute should be one of: full, incremental") - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith("syncType attribute should be one of: full, incremental") + .should.equal(true); + }); + }); +}); diff --git a/test/unit/coffee/ResourceStateManagerTests.js b/test/unit/coffee/ResourceStateManagerTests.js index e5e1c13..4b09135 100644 --- a/test/unit/coffee/ResourceStateManagerTests.js +++ b/test/unit/coffee/ResourceStateManagerTests.js @@ -1,109 +1,147 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -should = require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/ResourceStateManager' -Path = require "path" -Errors = require "../../../app/js/Errors" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +const should = require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/ResourceStateManager'); +const Path = require("path"); +const Errors = require("../../../app/js/Errors"); -describe "ResourceStateManager", -> - beforeEach -> - @ResourceStateManager = SandboxedModule.require modulePath, requires: - "fs": @fs = {} - "logger-sharelatex": {log: sinon.stub(), err: sinon.stub()} - "./SafeReader": @SafeReader = {} - @basePath = "/path/to/write/files/to" - @resources = [ - {path: "resource-1-mock"} - {path: "resource-2-mock"} +describe("ResourceStateManager", function() { + beforeEach(function() { + this.ResourceStateManager = SandboxedModule.require(modulePath, { requires: { + "fs": (this.fs = {}), + "logger-sharelatex": {log: sinon.stub(), err: sinon.stub()}, + "./SafeReader": (this.SafeReader = {}) + } + }); + this.basePath = "/path/to/write/files/to"; + this.resources = [ + {path: "resource-1-mock"}, + {path: "resource-2-mock"}, {path: "resource-3-mock"} - ] - @state = "1234567890" - @resourceFileName = "#{@basePath}/.project-sync-state" - @resourceFileContents = "#{@resources[0].path}\n#{@resources[1].path}\n#{@resources[2].path}\nstateHash:#{@state}" - @callback = sinon.stub() + ]; + this.state = "1234567890"; + this.resourceFileName = `${this.basePath}/.project-sync-state`; + this.resourceFileContents = `${this.resources[0].path}\n${this.resources[1].path}\n${this.resources[2].path}\nstateHash:${this.state}`; + return this.callback = sinon.stub(); + }); - describe "saveProjectState", -> - beforeEach -> - @fs.writeFile = sinon.stub().callsArg(2) + describe("saveProjectState", function() { + beforeEach(function() { + return this.fs.writeFile = sinon.stub().callsArg(2); + }); - describe "when the state is specified", -> - beforeEach -> - @ResourceStateManager.saveProjectState(@state, @resources, @basePath, @callback) + describe("when the state is specified", function() { + beforeEach(function() { + return this.ResourceStateManager.saveProjectState(this.state, this.resources, this.basePath, this.callback); + }); - it "should write the resource list to disk", -> - @fs.writeFile - .calledWith(@resourceFileName, @resourceFileContents) - .should.equal true + it("should write the resource list to disk", function() { + return this.fs.writeFile + .calledWith(this.resourceFileName, this.resourceFileContents) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "when the state is undefined", -> - beforeEach -> - @state = undefined - @fs.unlink = sinon.stub().callsArg(1) - @ResourceStateManager.saveProjectState(@state, @resources, @basePath, @callback) + return describe("when the state is undefined", function() { + beforeEach(function() { + this.state = undefined; + this.fs.unlink = sinon.stub().callsArg(1); + return this.ResourceStateManager.saveProjectState(this.state, this.resources, this.basePath, this.callback); + }); - it "should unlink the resource file", -> - @fs.unlink - .calledWith(@resourceFileName) - .should.equal true + it("should unlink the resource file", function() { + return this.fs.unlink + .calledWith(this.resourceFileName) + .should.equal(true); + }); - it "should not write the resource list to disk", -> - @fs.writeFile.called.should.equal false + it("should not write the resource list to disk", function() { + return this.fs.writeFile.called.should.equal(false); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); + }); - describe "checkProjectStateMatches", -> + describe("checkProjectStateMatches", function() { - describe "when the state matches", -> - beforeEach -> - @SafeReader.readFile = sinon.stub().callsArgWith(3, null, @resourceFileContents) - @ResourceStateManager.checkProjectStateMatches(@state, @basePath, @callback) + describe("when the state matches", function() { + beforeEach(function() { + this.SafeReader.readFile = sinon.stub().callsArgWith(3, null, this.resourceFileContents); + return this.ResourceStateManager.checkProjectStateMatches(this.state, this.basePath, this.callback); + }); - it "should read the resource file", -> - @SafeReader.readFile - .calledWith(@resourceFileName) - .should.equal true + it("should read the resource file", function() { + return this.SafeReader.readFile + .calledWith(this.resourceFileName) + .should.equal(true); + }); - it "should call the callback with the results", -> - @callback.calledWithMatch(null, @resources).should.equal true + return it("should call the callback with the results", function() { + return this.callback.calledWithMatch(null, this.resources).should.equal(true); + }); + }); - describe "when the state does not match", -> - beforeEach -> - @SafeReader.readFile = sinon.stub().callsArgWith(3, null, @resourceFileContents) - @ResourceStateManager.checkProjectStateMatches("not-the-original-state", @basePath, @callback) + return describe("when the state does not match", function() { + beforeEach(function() { + this.SafeReader.readFile = sinon.stub().callsArgWith(3, null, this.resourceFileContents); + return this.ResourceStateManager.checkProjectStateMatches("not-the-original-state", this.basePath, this.callback); + }); - it "should call the callback with an error", -> - error = new Errors.FilesOutOfSyncError("invalid state for incremental update") - @callback.calledWith(error).should.equal true + return it("should call the callback with an error", function() { + const error = new Errors.FilesOutOfSyncError("invalid state for incremental update"); + return this.callback.calledWith(error).should.equal(true); + }); + }); + }); - describe "checkResourceFiles", -> - describe "when all the files are present", -> - beforeEach -> - @allFiles = [ @resources[0].path, @resources[1].path, @resources[2].path] - @ResourceStateManager.checkResourceFiles(@resources, @allFiles, @basePath, @callback) + return describe("checkResourceFiles", function() { + describe("when all the files are present", function() { + beforeEach(function() { + this.allFiles = [ this.resources[0].path, this.resources[1].path, this.resources[2].path]; + return this.ResourceStateManager.checkResourceFiles(this.resources, this.allFiles, this.basePath, this.callback); + }); - it "should call the callback", -> - @callback.calledWithExactly().should.equal true + return it("should call the callback", function() { + return this.callback.calledWithExactly().should.equal(true); + }); + }); - describe "when there is a missing file", -> - beforeEach -> - @allFiles = [ @resources[0].path, @resources[1].path] - @fs.stat = sinon.stub().callsArgWith(1, new Error()) - @ResourceStateManager.checkResourceFiles(@resources, @allFiles, @basePath, @callback) + describe("when there is a missing file", function() { + beforeEach(function() { + this.allFiles = [ this.resources[0].path, this.resources[1].path]; + this.fs.stat = sinon.stub().callsArgWith(1, new Error()); + return this.ResourceStateManager.checkResourceFiles(this.resources, this.allFiles, this.basePath, this.callback); + }); - it "should call the callback with an error", -> - error = new Errors.FilesOutOfSyncError("resource files missing in incremental update") - @callback.calledWith(error).should.equal true + return it("should call the callback with an error", function() { + const error = new Errors.FilesOutOfSyncError("resource files missing in incremental update"); + return this.callback.calledWith(error).should.equal(true); + }); + }); - describe "when a resource contains a relative path", -> - beforeEach -> - @resources[0].path = "../foo/bar.tex" - @allFiles = [ @resources[0].path, @resources[1].path, @resources[2].path] - @ResourceStateManager.checkResourceFiles(@resources, @allFiles, @basePath, @callback) + return describe("when a resource contains a relative path", function() { + beforeEach(function() { + this.resources[0].path = "../foo/bar.tex"; + this.allFiles = [ this.resources[0].path, this.resources[1].path, this.resources[2].path]; + return this.ResourceStateManager.checkResourceFiles(this.resources, this.allFiles, this.basePath, this.callback); + }); - it "should call the callback with an error", -> - @callback.calledWith(new Error("relative path in resource file list")).should.equal true + return it("should call the callback with an error", function() { + return this.callback.calledWith(new Error("relative path in resource file list")).should.equal(true); + }); + }); + }); +}); diff --git a/test/unit/coffee/ResourceWriterTests.js b/test/unit/coffee/ResourceWriterTests.js index 4a88226..89433c8 100644 --- a/test/unit/coffee/ResourceWriterTests.js +++ b/test/unit/coffee/ResourceWriterTests.js @@ -1,324 +1,409 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -should = require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/ResourceWriter' -path = require "path" +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS206: Consider reworking classes to avoid initClass + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +const should = require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/ResourceWriter'); +const path = require("path"); -describe "ResourceWriter", -> - beforeEach -> - @ResourceWriter = SandboxedModule.require modulePath, requires: - "fs": @fs = - mkdir: sinon.stub().callsArg(1) +describe("ResourceWriter", function() { + beforeEach(function() { + let Timer; + this.ResourceWriter = SandboxedModule.require(modulePath, { requires: { + "fs": (this.fs = { + mkdir: sinon.stub().callsArg(1), unlink: sinon.stub().callsArg(1) - "./ResourceStateManager": @ResourceStateManager = {} - "wrench": @wrench = {} - "./UrlCache" : @UrlCache = {} - "mkdirp" : @mkdirp = sinon.stub().callsArg(1) - "./OutputFileFinder": @OutputFileFinder = {} - "logger-sharelatex": {log: sinon.stub(), err: sinon.stub()} - "./Metrics": @Metrics = - Timer: class Timer - done: sinon.stub() - @project_id = "project-id-123" - @basePath = "/path/to/write/files/to" - @callback = sinon.stub() + }), + "./ResourceStateManager": (this.ResourceStateManager = {}), + "wrench": (this.wrench = {}), + "./UrlCache" : (this.UrlCache = {}), + "mkdirp" : (this.mkdirp = sinon.stub().callsArg(1)), + "./OutputFileFinder": (this.OutputFileFinder = {}), + "logger-sharelatex": {log: sinon.stub(), err: sinon.stub()}, + "./Metrics": (this.Metrics = { + Timer: (Timer = (function() { + Timer = class Timer { + static initClass() { + this.prototype.done = sinon.stub(); + } + }; + Timer.initClass(); + return Timer; + })()) + }) + } + } + ); + this.project_id = "project-id-123"; + this.basePath = "/path/to/write/files/to"; + return this.callback = sinon.stub(); + }); - describe "syncResourcesToDisk on a full request", -> - beforeEach -> - @resources = [ - "resource-1-mock" - "resource-2-mock" + describe("syncResourcesToDisk on a full request", function() { + beforeEach(function() { + this.resources = [ + "resource-1-mock", + "resource-2-mock", "resource-3-mock" - ] - @ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3) - @ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2) - @ResourceStateManager.saveProjectState = sinon.stub().callsArg(3) - @ResourceWriter.syncResourcesToDisk({ - project_id: @project_id - syncState: @syncState = "0123456789abcdef" - resources: @resources - }, @basePath, @callback) + ]; + this.ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3); + this.ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2); + this.ResourceStateManager.saveProjectState = sinon.stub().callsArg(3); + return this.ResourceWriter.syncResourcesToDisk({ + project_id: this.project_id, + syncState: (this.syncState = "0123456789abcdef"), + resources: this.resources + }, this.basePath, this.callback); + }); - it "should remove old files", -> - @ResourceWriter._removeExtraneousFiles - .calledWith(@resources, @basePath) - .should.equal true + it("should remove old files", function() { + return this.ResourceWriter._removeExtraneousFiles + .calledWith(this.resources, this.basePath) + .should.equal(true); + }); - it "should write each resource to disk", -> - for resource in @resources - @ResourceWriter._writeResourceToDisk - .calledWith(@project_id, resource, @basePath) - .should.equal true + it("should write each resource to disk", function() { + return Array.from(this.resources).map((resource) => + this.ResourceWriter._writeResourceToDisk + .calledWith(this.project_id, resource, this.basePath) + .should.equal(true)); + }); - it "should store the sync state and resource list", -> - @ResourceStateManager.saveProjectState - .calledWith(@syncState, @resources, @basePath) - .should.equal true + it("should store the sync state and resource list", function() { + return this.ResourceStateManager.saveProjectState + .calledWith(this.syncState, this.resources, this.basePath) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "syncResourcesToDisk on an incremental update", -> - beforeEach -> - @resources = [ + describe("syncResourcesToDisk on an incremental update", function() { + beforeEach(function() { + this.resources = [ "resource-1-mock" - ] - @ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3) - @ResourceWriter._removeExtraneousFiles = sinon.stub().callsArgWith(2, null, @outputFiles = [], @allFiles = []) - @ResourceStateManager.checkProjectStateMatches = sinon.stub().callsArgWith(2, null, @resources) - @ResourceStateManager.saveProjectState = sinon.stub().callsArg(3) - @ResourceStateManager.checkResourceFiles = sinon.stub().callsArg(3) - @ResourceWriter.syncResourcesToDisk({ - project_id: @project_id, + ]; + this.ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3); + this.ResourceWriter._removeExtraneousFiles = sinon.stub().callsArgWith(2, null, (this.outputFiles = []), (this.allFiles = [])); + this.ResourceStateManager.checkProjectStateMatches = sinon.stub().callsArgWith(2, null, this.resources); + this.ResourceStateManager.saveProjectState = sinon.stub().callsArg(3); + this.ResourceStateManager.checkResourceFiles = sinon.stub().callsArg(3); + return this.ResourceWriter.syncResourcesToDisk({ + project_id: this.project_id, syncType: "incremental", - syncState: @syncState = "1234567890abcdef", - resources: @resources - }, @basePath, @callback) + syncState: (this.syncState = "1234567890abcdef"), + resources: this.resources + }, this.basePath, this.callback); + }); - it "should check the sync state matches", -> - @ResourceStateManager.checkProjectStateMatches - .calledWith(@syncState, @basePath) - .should.equal true + it("should check the sync state matches", function() { + return this.ResourceStateManager.checkProjectStateMatches + .calledWith(this.syncState, this.basePath) + .should.equal(true); + }); - it "should remove old files", -> - @ResourceWriter._removeExtraneousFiles - .calledWith(@resources, @basePath) - .should.equal true + it("should remove old files", function() { + return this.ResourceWriter._removeExtraneousFiles + .calledWith(this.resources, this.basePath) + .should.equal(true); + }); - it "should check each resource exists", -> - @ResourceStateManager.checkResourceFiles - .calledWith(@resources, @allFiles, @basePath) - .should.equal true + it("should check each resource exists", function() { + return this.ResourceStateManager.checkResourceFiles + .calledWith(this.resources, this.allFiles, this.basePath) + .should.equal(true); + }); - it "should write each resource to disk", -> - for resource in @resources - @ResourceWriter._writeResourceToDisk - .calledWith(@project_id, resource, @basePath) - .should.equal true + it("should write each resource to disk", function() { + return Array.from(this.resources).map((resource) => + this.ResourceWriter._writeResourceToDisk + .calledWith(this.project_id, resource, this.basePath) + .should.equal(true)); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "syncResourcesToDisk on an incremental update when the state does not match", -> - beforeEach -> - @resources = [ + describe("syncResourcesToDisk on an incremental update when the state does not match", function() { + beforeEach(function() { + this.resources = [ "resource-1-mock" - ] - @ResourceStateManager.checkProjectStateMatches = sinon.stub().callsArgWith(2, @error = new Error()) - @ResourceWriter.syncResourcesToDisk({ - project_id: @project_id, + ]; + this.ResourceStateManager.checkProjectStateMatches = sinon.stub().callsArgWith(2, (this.error = new Error())); + return this.ResourceWriter.syncResourcesToDisk({ + project_id: this.project_id, syncType: "incremental", - syncState: @syncState = "1234567890abcdef", - resources: @resources - }, @basePath, @callback) + syncState: (this.syncState = "1234567890abcdef"), + resources: this.resources + }, this.basePath, this.callback); + }); - it "should check whether the sync state matches", -> - @ResourceStateManager.checkProjectStateMatches - .calledWith(@syncState, @basePath) - .should.equal true + it("should check whether the sync state matches", function() { + return this.ResourceStateManager.checkProjectStateMatches + .calledWith(this.syncState, this.basePath) + .should.equal(true); + }); - it "should call the callback with an error", -> - @callback.calledWith(@error).should.equal true + return it("should call the callback with an error", function() { + return this.callback.calledWith(this.error).should.equal(true); + }); + }); - describe "_removeExtraneousFiles", -> - beforeEach -> - @output_files = [{ - path: "output.pdf" + describe("_removeExtraneousFiles", function() { + beforeEach(function() { + this.output_files = [{ + path: "output.pdf", type: "pdf" }, { - path: "extra/file.tex" + path: "extra/file.tex", type: "tex" }, { - path: "extra.aux" + path: "extra.aux", type: "aux" }, { path: "cache/_chunk1" },{ - path: "figures/image-eps-converted-to.pdf" + path: "figures/image-eps-converted-to.pdf", type: "pdf" },{ - path: "foo/main-figure0.md5" + path: "foo/main-figure0.md5", type: "md5" }, { - path: "foo/main-figure0.dpth" + path: "foo/main-figure0.dpth", type: "dpth" }, { - path: "foo/main-figure0.pdf" + path: "foo/main-figure0.pdf", type: "pdf" }, { - path: "_minted-main/default-pyg-prefix.pygstyle" + path: "_minted-main/default-pyg-prefix.pygstyle", type: "pygstyle" }, { - path: "_minted-main/default.pygstyle" + path: "_minted-main/default.pygstyle", type: "pygstyle" }, { - path: "_minted-main/35E248B60965545BD232AE9F0FE9750D504A7AF0CD3BAA7542030FC560DFCC45.pygtex" + path: "_minted-main/35E248B60965545BD232AE9F0FE9750D504A7AF0CD3BAA7542030FC560DFCC45.pygtex", type: "pygtex" }, { - path: "_markdown_main/30893013dec5d869a415610079774c2f.md.tex" + path: "_markdown_main/30893013dec5d869a415610079774c2f.md.tex", type: "tex" - }] - @resources = "mock-resources" - @OutputFileFinder.findOutputFiles = sinon.stub().callsArgWith(2, null, @output_files) - @ResourceWriter._deleteFileIfNotDirectory = sinon.stub().callsArg(1) - @ResourceWriter._removeExtraneousFiles(@resources, @basePath, @callback) + }]; + this.resources = "mock-resources"; + this.OutputFileFinder.findOutputFiles = sinon.stub().callsArgWith(2, null, this.output_files); + this.ResourceWriter._deleteFileIfNotDirectory = sinon.stub().callsArg(1); + return this.ResourceWriter._removeExtraneousFiles(this.resources, this.basePath, this.callback); + }); - it "should find the existing output files", -> - @OutputFileFinder.findOutputFiles - .calledWith(@resources, @basePath) - .should.equal true + it("should find the existing output files", function() { + return this.OutputFileFinder.findOutputFiles + .calledWith(this.resources, this.basePath) + .should.equal(true); + }); - it "should delete the output files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "output.pdf")) - .should.equal true + it("should delete the output files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "output.pdf")) + .should.equal(true); + }); - it "should delete the extra files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "extra/file.tex")) - .should.equal true + it("should delete the extra files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "extra/file.tex")) + .should.equal(true); + }); - it "should not delete the extra aux files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "extra.aux")) - .should.equal false + it("should not delete the extra aux files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "extra.aux")) + .should.equal(false); + }); - it "should not delete the knitr cache file", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "cache/_chunk1")) - .should.equal false + it("should not delete the knitr cache file", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "cache/_chunk1")) + .should.equal(false); + }); - it "should not delete the epstopdf converted files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "figures/image-eps-converted-to.pdf")) - .should.equal false + it("should not delete the epstopdf converted files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "figures/image-eps-converted-to.pdf")) + .should.equal(false); + }); - it "should not delete the tikz md5 files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "foo/main-figure0.md5")) - .should.equal false + it("should not delete the tikz md5 files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "foo/main-figure0.md5")) + .should.equal(false); + }); - it "should not delete the tikz dpth files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "foo/main-figure0.dpth")) - .should.equal false + it("should not delete the tikz dpth files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "foo/main-figure0.dpth")) + .should.equal(false); + }); - it "should not delete the tikz pdf files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "foo/main-figure0.pdf")) - .should.equal false + it("should not delete the tikz pdf files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "foo/main-figure0.pdf")) + .should.equal(false); + }); - it "should not delete the minted pygstyle files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "_minted-main/default-pyg-prefix.pygstyle")) - .should.equal false + it("should not delete the minted pygstyle files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "_minted-main/default-pyg-prefix.pygstyle")) + .should.equal(false); + }); - it "should not delete the minted default pygstyle files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "_minted-main/default.pygstyle")) - .should.equal false + it("should not delete the minted default pygstyle files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "_minted-main/default.pygstyle")) + .should.equal(false); + }); - it "should not delete the minted default pygtex files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "_minted-main/35E248B60965545BD232AE9F0FE9750D504A7AF0CD3BAA7542030FC560DFCC45.pygtex")) - .should.equal false + it("should not delete the minted default pygtex files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "_minted-main/35E248B60965545BD232AE9F0FE9750D504A7AF0CD3BAA7542030FC560DFCC45.pygtex")) + .should.equal(false); + }); - it "should not delete the markdown md.tex files", -> - @ResourceWriter._deleteFileIfNotDirectory - .calledWith(path.join(@basePath, "_markdown_main/30893013dec5d869a415610079774c2f.md.tex")) - .should.equal false + it("should not delete the markdown md.tex files", function() { + return this.ResourceWriter._deleteFileIfNotDirectory + .calledWith(path.join(this.basePath, "_markdown_main/30893013dec5d869a415610079774c2f.md.tex")) + .should.equal(false); + }); - it "should call the callback", -> - @callback.called.should.equal true + it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); - it "should time the request", -> - @Metrics.Timer::done.called.should.equal true + return it("should time the request", function() { + return this.Metrics.Timer.prototype.done.called.should.equal(true); + }); + }); - describe "_writeResourceToDisk", -> - describe "with a url based resource", -> - beforeEach -> - @resource = - path: "main.tex" - url: "http://www.example.com/main.tex" + describe("_writeResourceToDisk", function() { + describe("with a url based resource", function() { + beforeEach(function() { + this.resource = { + path: "main.tex", + url: "http://www.example.com/main.tex", modified: Date.now() - @UrlCache.downloadUrlToFile = sinon.stub().callsArgWith(4, "fake error downloading file") - @ResourceWriter._writeResourceToDisk(@project_id, @resource, @basePath, @callback) + }; + this.UrlCache.downloadUrlToFile = sinon.stub().callsArgWith(4, "fake error downloading file"); + return this.ResourceWriter._writeResourceToDisk(this.project_id, this.resource, this.basePath, this.callback); + }); - it "should ensure the directory exists", -> - @mkdirp - .calledWith(path.dirname(path.join(@basePath, @resource.path))) - .should.equal true + it("should ensure the directory exists", function() { + return this.mkdirp + .calledWith(path.dirname(path.join(this.basePath, this.resource.path))) + .should.equal(true); + }); - it "should write the URL from the cache", -> - @UrlCache.downloadUrlToFile - .calledWith(@project_id, @resource.url, path.join(@basePath, @resource.path), @resource.modified) - .should.equal true + it("should write the URL from the cache", function() { + return this.UrlCache.downloadUrlToFile + .calledWith(this.project_id, this.resource.url, path.join(this.basePath, this.resource.path), this.resource.modified) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); - it "should not return an error if the resource writer errored", -> - should.not.exist @callback.args[0][0] + return it("should not return an error if the resource writer errored", function() { + return should.not.exist(this.callback.args[0][0]); + }); + }); - describe "with a content based resource", -> - beforeEach -> - @resource = - path: "main.tex" + describe("with a content based resource", function() { + beforeEach(function() { + this.resource = { + path: "main.tex", content: "Hello world" - @fs.writeFile = sinon.stub().callsArg(2) - @ResourceWriter._writeResourceToDisk(@project_id, @resource, @basePath, @callback) + }; + this.fs.writeFile = sinon.stub().callsArg(2); + return this.ResourceWriter._writeResourceToDisk(this.project_id, this.resource, this.basePath, this.callback); + }); - it "should ensure the directory exists", -> - @mkdirp - .calledWith(path.dirname(path.join(@basePath, @resource.path))) - .should.equal true + it("should ensure the directory exists", function() { + return this.mkdirp + .calledWith(path.dirname(path.join(this.basePath, this.resource.path))) + .should.equal(true); + }); - it "should write the contents to disk", -> - @fs.writeFile - .calledWith(path.join(@basePath, @resource.path), @resource.content) - .should.equal true + it("should write the contents to disk", function() { + return this.fs.writeFile + .calledWith(path.join(this.basePath, this.resource.path), this.resource.content) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "with a file path that breaks out of the root folder", -> - beforeEach -> - @resource = - path: "../../main.tex" + return describe("with a file path that breaks out of the root folder", function() { + beforeEach(function() { + this.resource = { + path: "../../main.tex", content: "Hello world" - @fs.writeFile = sinon.stub().callsArg(2) - @ResourceWriter._writeResourceToDisk(@project_id, @resource, @basePath, @callback) + }; + this.fs.writeFile = sinon.stub().callsArg(2); + return this.ResourceWriter._writeResourceToDisk(this.project_id, this.resource, this.basePath, this.callback); + }); - it "should not write to disk", -> - @fs.writeFile.called.should.equal false + it("should not write to disk", function() { + return this.fs.writeFile.called.should.equal(false); + }); - it "should return an error", -> - @callback + return it("should return an error", function() { + return this.callback .calledWith(new Error("resource path is outside root directory")) - .should.equal true + .should.equal(true); + }); + }); + }); - describe "checkPath", -> - describe "with a valid path", -> - beforeEach -> - @ResourceWriter.checkPath("foo", "bar", @callback) + return describe("checkPath", function() { + describe("with a valid path", function() { + beforeEach(function() { + return this.ResourceWriter.checkPath("foo", "bar", this.callback); + }); - it "should return the joined path", -> - @callback.calledWith(null, "foo/bar") - .should.equal true + return it("should return the joined path", function() { + return this.callback.calledWith(null, "foo/bar") + .should.equal(true); + }); + }); - describe "with an invalid path", -> - beforeEach -> - @ResourceWriter.checkPath("foo", "baz/../../bar", @callback) + describe("with an invalid path", function() { + beforeEach(function() { + return this.ResourceWriter.checkPath("foo", "baz/../../bar", this.callback); + }); - it "should return an error", -> - @callback.calledWith(new Error("resource path is outside root directory")) - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith(new Error("resource path is outside root directory")) + .should.equal(true); + }); + }); - describe "with another invalid path matching on a prefix", -> - beforeEach -> - @ResourceWriter.checkPath("foo", "../foobar/baz", @callback) + return describe("with another invalid path matching on a prefix", function() { + beforeEach(function() { + return this.ResourceWriter.checkPath("foo", "../foobar/baz", this.callback); + }); - it "should return an error", -> - @callback.calledWith(new Error("resource path is outside root directory")) - .should.equal true + return it("should return an error", function() { + return this.callback.calledWith(new Error("resource path is outside root directory")) + .should.equal(true); + }); + }); + }); +}); diff --git a/test/unit/coffee/StaticServerForbidSymlinksTests.js b/test/unit/coffee/StaticServerForbidSymlinksTests.js index 4a87d64..9063c1f 100644 --- a/test/unit/coffee/StaticServerForbidSymlinksTests.js +++ b/test/unit/coffee/StaticServerForbidSymlinksTests.js @@ -1,158 +1,219 @@ -should = require('chai').should() -SandboxedModule = require('sandboxed-module') -assert = require('assert') -path = require('path') -sinon = require('sinon') -modulePath = path.join __dirname, "../../../app/js/StaticServerForbidSymlinks" -expect = require("chai").expect +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const should = require('chai').should(); +const SandboxedModule = require('sandboxed-module'); +const assert = require('assert'); +const path = require('path'); +const sinon = require('sinon'); +const modulePath = path.join(__dirname, "../../../app/js/StaticServerForbidSymlinks"); +const { expect } = require("chai"); -describe "StaticServerForbidSymlinks", -> +describe("StaticServerForbidSymlinks", function() { - beforeEach -> + beforeEach(function() { - @settings = - path: + this.settings = { + path: { compilesDir: "/compiles/here" + } + }; - @fs = {} - @ForbidSymlinks = SandboxedModule.require modulePath, requires: - "settings-sharelatex":@settings - "logger-sharelatex": - log:-> - warn:-> - error:-> - "fs":@fs + this.fs = {}; + this.ForbidSymlinks = SandboxedModule.require(modulePath, { requires: { + "settings-sharelatex":this.settings, + "logger-sharelatex": { + log() {}, + warn() {}, + error() {} + }, + "fs":this.fs + } + } + ); - @dummyStatic = (rootDir, options) -> - return (req, res, next) -> - # console.log "dummyStatic serving file", rootDir, "called with", req.url - # serve it + this.dummyStatic = (rootDir, options) => + (req, res, next) => + // console.log "dummyStatic serving file", rootDir, "called with", req.url + // serve it next() + + ; - @StaticServerForbidSymlinks = @ForbidSymlinks @dummyStatic, @settings.path.compilesDir - @req = - params: + this.StaticServerForbidSymlinks = this.ForbidSymlinks(this.dummyStatic, this.settings.path.compilesDir); + this.req = { + params: { project_id:"12345" + } + }; - @res = {} - @req.url = "/12345/output.pdf" + this.res = {}; + return this.req.url = "/12345/output.pdf"; + }); - describe "sending a normal file through", -> - beforeEach -> - @fs.realpath = sinon.stub().callsArgWith(1, null, "#{@settings.path.compilesDir}/#{@req.params.project_id}/output.pdf") + describe("sending a normal file through", function() { + beforeEach(function() { + return this.fs.realpath = sinon.stub().callsArgWith(1, null, `${this.settings.path.compilesDir}/${this.req.params.project_id}/output.pdf`); + }); - it "should call next", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 200 - done() - @StaticServerForbidSymlinks @req, @res, done + return it("should call next", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(200); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res, done); + }); + }); - describe "with a missing file", -> - beforeEach -> - @fs.realpath = sinon.stub().callsArgWith(1, {code: 'ENOENT'}, "#{@settings.path.compilesDir}/#{@req.params.project_id}/unknown.pdf") + describe("with a missing file", function() { + beforeEach(function() { + return this.fs.realpath = sinon.stub().callsArgWith(1, {code: 'ENOENT'}, `${this.settings.path.compilesDir}/${this.req.params.project_id}/unknown.pdf`); + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a symlink file", -> - beforeEach -> - @fs.realpath = sinon.stub().callsArgWith(1, null, "/etc/#{@req.params.project_id}/output.pdf") + describe("with a symlink file", function() { + beforeEach(function() { + return this.fs.realpath = sinon.stub().callsArgWith(1, null, `/etc/${this.req.params.project_id}/output.pdf`); + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a relative file", -> - beforeEach -> - @req.url = "/12345/../67890/output.pdf" + describe("with a relative file", function() { + beforeEach(function() { + return this.req.url = "/12345/../67890/output.pdf"; + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a unnormalized file containing .", -> - beforeEach -> - @req.url = "/12345/foo/./output.pdf" + describe("with a unnormalized file containing .", function() { + beforeEach(function() { + return this.req.url = "/12345/foo/./output.pdf"; + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a file containing an empty path", -> - beforeEach -> - @req.url = "/12345/foo//output.pdf" + describe("with a file containing an empty path", function() { + beforeEach(function() { + return this.req.url = "/12345/foo//output.pdf"; + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a non-project file", -> - beforeEach -> - @req.url = "/.foo/output.pdf" + describe("with a non-project file", function() { + beforeEach(function() { + return this.req.url = "/.foo/output.pdf"; + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a file outside the compiledir", -> - beforeEach -> - @req.url = "/../bar/output.pdf" + describe("with a file outside the compiledir", function() { + beforeEach(function() { + return this.req.url = "/../bar/output.pdf"; + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a file with no leading /", -> - beforeEach -> - @req.url = "./../bar/output.pdf" + describe("with a file with no leading /", function() { + beforeEach(function() { + return this.req.url = "./../bar/output.pdf"; + }); - it "should send a 404", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 404 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 404", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(404); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); - describe "with a github style path", -> - beforeEach -> - @req.url = "/henryoswald-latex_example/output/output.log" - @fs.realpath = sinon.stub().callsArgWith(1, null, "#{@settings.path.compilesDir}/henryoswald-latex_example/output/output.log") + describe("with a github style path", function() { + beforeEach(function() { + this.req.url = "/henryoswald-latex_example/output/output.log"; + return this.fs.realpath = sinon.stub().callsArgWith(1, null, `${this.settings.path.compilesDir}/henryoswald-latex_example/output/output.log`); + }); - it "should call next", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 200 - done() - @StaticServerForbidSymlinks @req, @res, done + return it("should call next", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(200); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res, done); + }); + }); - describe "with an error from fs.realpath", -> + return describe("with an error from fs.realpath", function() { - beforeEach -> - @fs.realpath = sinon.stub().callsArgWith(1, "error") + beforeEach(function() { + return this.fs.realpath = sinon.stub().callsArgWith(1, "error"); + }); - it "should send a 500", (done)-> - @res.sendStatus = (resCode)-> - resCode.should.equal 500 - done() - @StaticServerForbidSymlinks @req, @res + return it("should send a 500", function(done){ + this.res.sendStatus = function(resCode){ + resCode.should.equal(500); + return done(); + }; + return this.StaticServerForbidSymlinks(this.req, this.res); + }); + }); +}); diff --git a/test/unit/coffee/TikzManager.js b/test/unit/coffee/TikzManager.js index 69968aa..c792fab 100644 --- a/test/unit/coffee/TikzManager.js +++ b/test/unit/coffee/TikzManager.js @@ -1,117 +1,150 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/TikzManager' +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/TikzManager'); -describe 'TikzManager', -> - beforeEach -> - @TikzManager = SandboxedModule.require modulePath, requires: - "./ResourceWriter": @ResourceWriter = {} - "./SafeReader": @SafeReader = {} - "fs": @fs = {} - "logger-sharelatex": @logger = {log: () ->} +describe('TikzManager', function() { + beforeEach(function() { + return this.TikzManager = SandboxedModule.require(modulePath, { requires: { + "./ResourceWriter": (this.ResourceWriter = {}), + "./SafeReader": (this.SafeReader = {}), + "fs": (this.fs = {}), + "logger-sharelatex": (this.logger = {log() {}}) + } + });}); - describe "checkMainFile", -> - beforeEach -> - @compileDir = "compile-dir" - @mainFile = "main.tex" - @callback = sinon.stub() + describe("checkMainFile", function() { + beforeEach(function() { + this.compileDir = "compile-dir"; + this.mainFile = "main.tex"; + return this.callback = sinon.stub(); + }); - describe "if there is already an output.tex file in the resources", -> - beforeEach -> - @resources = [{path:"main.tex"},{path:"output.tex"}] - @TikzManager.checkMainFile @compileDir, @mainFile, @resources, @callback + describe("if there is already an output.tex file in the resources", function() { + beforeEach(function() { + this.resources = [{path:"main.tex"},{path:"output.tex"}]; + return this.TikzManager.checkMainFile(this.compileDir, this.mainFile, this.resources, this.callback); + }); - it "should call the callback with false ", -> - @callback.calledWithExactly(null, false) - .should.equal true + return it("should call the callback with false ", function() { + return this.callback.calledWithExactly(null, false) + .should.equal(true); + }); + }); - describe "if there is no output.tex file in the resources", -> - beforeEach -> - @resources = [{path:"main.tex"}] - @ResourceWriter.checkPath = sinon.stub() - .withArgs(@compileDir, @mainFile) - .callsArgWith(2, null, "#{@compileDir}/#{@mainFile}") + return describe("if there is no output.tex file in the resources", function() { + beforeEach(function() { + this.resources = [{path:"main.tex"}]; + return this.ResourceWriter.checkPath = sinon.stub() + .withArgs(this.compileDir, this.mainFile) + .callsArgWith(2, null, `${this.compileDir}/${this.mainFile}`); + }); - describe "and the main file contains tikzexternalize", -> - beforeEach -> - @SafeReader.readFile = sinon.stub() - .withArgs("#{@compileDir}/#{@mainFile}") - .callsArgWith(3, null, "hello \\tikzexternalize") - @TikzManager.checkMainFile @compileDir, @mainFile, @resources, @callback + describe("and the main file contains tikzexternalize", function() { + beforeEach(function() { + this.SafeReader.readFile = sinon.stub() + .withArgs(`${this.compileDir}/${this.mainFile}`) + .callsArgWith(3, null, "hello \\tikzexternalize"); + return this.TikzManager.checkMainFile(this.compileDir, this.mainFile, this.resources, this.callback); + }); - it "should look at the file on disk", -> - @SafeReader.readFile - .calledWith("#{@compileDir}/#{@mainFile}") - .should.equal true + it("should look at the file on disk", function() { + return this.SafeReader.readFile + .calledWith(`${this.compileDir}/${this.mainFile}`) + .should.equal(true); + }); - it "should call the callback with true ", -> - @callback.calledWithExactly(null, true) - .should.equal true + return it("should call the callback with true ", function() { + return this.callback.calledWithExactly(null, true) + .should.equal(true); + }); + }); - describe "and the main file does not contain tikzexternalize", -> - beforeEach -> - @SafeReader.readFile = sinon.stub() - .withArgs("#{@compileDir}/#{@mainFile}") - .callsArgWith(3, null, "hello") - @TikzManager.checkMainFile @compileDir, @mainFile, @resources, @callback + describe("and the main file does not contain tikzexternalize", function() { + beforeEach(function() { + this.SafeReader.readFile = sinon.stub() + .withArgs(`${this.compileDir}/${this.mainFile}`) + .callsArgWith(3, null, "hello"); + return this.TikzManager.checkMainFile(this.compileDir, this.mainFile, this.resources, this.callback); + }); - it "should look at the file on disk", -> - @SafeReader.readFile - .calledWith("#{@compileDir}/#{@mainFile}") - .should.equal true + it("should look at the file on disk", function() { + return this.SafeReader.readFile + .calledWith(`${this.compileDir}/${this.mainFile}`) + .should.equal(true); + }); - it "should call the callback with false", -> - @callback.calledWithExactly(null, false) - .should.equal true + return it("should call the callback with false", function() { + return this.callback.calledWithExactly(null, false) + .should.equal(true); + }); + }); - describe "and the main file contains \\usepackage{pstool}", -> - beforeEach -> - @SafeReader.readFile = sinon.stub() - .withArgs("#{@compileDir}/#{@mainFile}") - .callsArgWith(3, null, "hello \\usepackage[random-options]{pstool}") - @TikzManager.checkMainFile @compileDir, @mainFile, @resources, @callback + return describe("and the main file contains \\usepackage{pstool}", function() { + beforeEach(function() { + this.SafeReader.readFile = sinon.stub() + .withArgs(`${this.compileDir}/${this.mainFile}`) + .callsArgWith(3, null, "hello \\usepackage[random-options]{pstool}"); + return this.TikzManager.checkMainFile(this.compileDir, this.mainFile, this.resources, this.callback); + }); - it "should look at the file on disk", -> - @SafeReader.readFile - .calledWith("#{@compileDir}/#{@mainFile}") - .should.equal true + it("should look at the file on disk", function() { + return this.SafeReader.readFile + .calledWith(`${this.compileDir}/${this.mainFile}`) + .should.equal(true); + }); - it "should call the callback with true ", -> - @callback.calledWithExactly(null, true) - .should.equal true + return it("should call the callback with true ", function() { + return this.callback.calledWithExactly(null, true) + .should.equal(true); + }); + }); + }); + }); - describe "injectOutputFile", -> - beforeEach -> - @rootDir = "/mock" - @filename = "filename.tex" - @callback = sinon.stub() - @content = ''' - \\documentclass{article} - \\usepackage{tikz} - \\tikzexternalize - \\begin{document} - Hello world - \\end{document} - ''' - @fs.readFile = sinon.stub().callsArgWith(2, null, @content) - @fs.writeFile = sinon.stub().callsArg(3) - @ResourceWriter.checkPath = sinon.stub().callsArgWith(2, null, "#{@rootDir}/#{@filename}") - @TikzManager.injectOutputFile @rootDir, @filename, @callback + return describe("injectOutputFile", function() { + beforeEach(function() { + this.rootDir = "/mock"; + this.filename = "filename.tex"; + this.callback = sinon.stub(); + this.content = `\ +\\documentclass{article} +\\usepackage{tikz} +\\tikzexternalize +\\begin{document} +Hello world +\\end{document}\ +`; + this.fs.readFile = sinon.stub().callsArgWith(2, null, this.content); + this.fs.writeFile = sinon.stub().callsArg(3); + this.ResourceWriter.checkPath = sinon.stub().callsArgWith(2, null, `${this.rootDir}/${this.filename}`); + return this.TikzManager.injectOutputFile(this.rootDir, this.filename, this.callback); + }); - it "sould check the path", -> - @ResourceWriter.checkPath.calledWith(@rootDir, @filename) - .should.equal true + it("sould check the path", function() { + return this.ResourceWriter.checkPath.calledWith(this.rootDir, this.filename) + .should.equal(true); + }); - it "should read the file", -> - @fs.readFile - .calledWith("#{@rootDir}/#{@filename}", "utf8") - .should.equal true + it("should read the file", function() { + return this.fs.readFile + .calledWith(`${this.rootDir}/${this.filename}`, "utf8") + .should.equal(true); + }); - it "should write out the same file as output.tex", -> - @fs.writeFile - .calledWith("#{@rootDir}/output.tex", @content, {flag: 'wx'}) - .should.equal true + it("should write out the same file as output.tex", function() { + return this.fs.writeFile + .calledWith(`${this.rootDir}/output.tex`, this.content, {flag: 'wx'}) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); +}); diff --git a/test/unit/coffee/UrlCacheTests.js b/test/unit/coffee/UrlCacheTests.js index 36a11cb..a3af008 100644 --- a/test/unit/coffee/UrlCacheTests.js +++ b/test/unit/coffee/UrlCacheTests.js @@ -1,200 +1,262 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/UrlCache' -EventEmitter = require("events").EventEmitter +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/UrlCache'); +const { EventEmitter } = require("events"); -describe "UrlCache", -> - beforeEach -> - @callback = sinon.stub() - @url = "www.example.com/file" - @project_id = "project-id-123" - @UrlCache = SandboxedModule.require modulePath, requires: - "./db" : {} - "./UrlFetcher" : @UrlFetcher = {} - "logger-sharelatex": @logger = {log: sinon.stub()} - "settings-sharelatex": @Settings = { path: clsiCacheDir: "/cache/dir" } - "fs": @fs = {} +describe("UrlCache", function() { + beforeEach(function() { + this.callback = sinon.stub(); + this.url = "www.example.com/file"; + this.project_id = "project-id-123"; + return this.UrlCache = SandboxedModule.require(modulePath, { requires: { + "./db" : {}, + "./UrlFetcher" : (this.UrlFetcher = {}), + "logger-sharelatex": (this.logger = {log: sinon.stub()}), + "settings-sharelatex": (this.Settings = { path: {clsiCacheDir: "/cache/dir"} }), + "fs": (this.fs = {}) + } + });}); - describe "_doesUrlNeedDownloading", -> - beforeEach -> - @lastModified = new Date() - @lastModifiedRoundedToSeconds = new Date(Math.floor(@lastModified.getTime() / 1000) * 1000) + describe("_doesUrlNeedDownloading", function() { + beforeEach(function() { + this.lastModified = new Date(); + return this.lastModifiedRoundedToSeconds = new Date(Math.floor(this.lastModified.getTime() / 1000) * 1000); + }); - describe "when URL does not exist in cache", -> - beforeEach -> - @UrlCache._findUrlDetails = sinon.stub().callsArgWith(2, null, null) - @UrlCache._doesUrlNeedDownloading(@project_id, @url, @lastModified, @callback) + describe("when URL does not exist in cache", function() { + beforeEach(function() { + this.UrlCache._findUrlDetails = sinon.stub().callsArgWith(2, null, null); + return this.UrlCache._doesUrlNeedDownloading(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should return the callback with true", -> - @callback.calledWith(null, true).should.equal true + return it("should return the callback with true", function() { + return this.callback.calledWith(null, true).should.equal(true); + }); + }); - describe "when URL does exist in cache", -> - beforeEach -> - @urlDetails = {} - @UrlCache._findUrlDetails = sinon.stub().callsArgWith(2, null, @urlDetails) + return describe("when URL does exist in cache", function() { + beforeEach(function() { + this.urlDetails = {}; + return this.UrlCache._findUrlDetails = sinon.stub().callsArgWith(2, null, this.urlDetails); + }); - describe "when the modified date is more recent than the cached modified date", -> - beforeEach -> - @urlDetails.lastModified = new Date(@lastModified.getTime() - 1000) - @UrlCache._doesUrlNeedDownloading(@project_id, @url, @lastModified, @callback) + describe("when the modified date is more recent than the cached modified date", function() { + beforeEach(function() { + this.urlDetails.lastModified = new Date(this.lastModified.getTime() - 1000); + return this.UrlCache._doesUrlNeedDownloading(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should get the url details", -> - @UrlCache._findUrlDetails - .calledWith(@project_id, @url) - .should.equal true + it("should get the url details", function() { + return this.UrlCache._findUrlDetails + .calledWith(this.project_id, this.url) + .should.equal(true); + }); - it "should return the callback with true", -> - @callback.calledWith(null, true).should.equal true + return it("should return the callback with true", function() { + return this.callback.calledWith(null, true).should.equal(true); + }); + }); - describe "when the cached modified date is more recent than the modified date", -> - beforeEach -> - @urlDetails.lastModified = new Date(@lastModified.getTime() + 1000) - @UrlCache._doesUrlNeedDownloading(@project_id, @url, @lastModified, @callback) + describe("when the cached modified date is more recent than the modified date", function() { + beforeEach(function() { + this.urlDetails.lastModified = new Date(this.lastModified.getTime() + 1000); + return this.UrlCache._doesUrlNeedDownloading(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should return the callback with false", -> - @callback.calledWith(null, false).should.equal true + return it("should return the callback with false", function() { + return this.callback.calledWith(null, false).should.equal(true); + }); + }); - describe "when the cached modified date is equal to the modified date", -> - beforeEach -> - @urlDetails.lastModified = @lastModified - @UrlCache._doesUrlNeedDownloading(@project_id, @url, @lastModified, @callback) + describe("when the cached modified date is equal to the modified date", function() { + beforeEach(function() { + this.urlDetails.lastModified = this.lastModified; + return this.UrlCache._doesUrlNeedDownloading(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should return the callback with false", -> - @callback.calledWith(null, false).should.equal true + return it("should return the callback with false", function() { + return this.callback.calledWith(null, false).should.equal(true); + }); + }); - describe "when the provided modified date does not exist", -> - beforeEach -> - @lastModified = null - @UrlCache._doesUrlNeedDownloading(@project_id, @url, @lastModified, @callback) + describe("when the provided modified date does not exist", function() { + beforeEach(function() { + this.lastModified = null; + return this.UrlCache._doesUrlNeedDownloading(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should return the callback with true", -> - @callback.calledWith(null, true).should.equal true + return it("should return the callback with true", function() { + return this.callback.calledWith(null, true).should.equal(true); + }); + }); - describe "when the URL does not have a modified date", -> - beforeEach -> - @urlDetails.lastModified = null - @UrlCache._doesUrlNeedDownloading(@project_id, @url, @lastModified, @callback) + return describe("when the URL does not have a modified date", function() { + beforeEach(function() { + this.urlDetails.lastModified = null; + return this.UrlCache._doesUrlNeedDownloading(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should return the callback with true", -> - @callback.calledWith(null, true).should.equal true + return it("should return the callback with true", function() { + return this.callback.calledWith(null, true).should.equal(true); + }); + }); + }); + }); - describe "_ensureUrlIsInCache", -> - beforeEach -> - @UrlFetcher.pipeUrlToFile = sinon.stub().callsArg(2) - @UrlCache._updateOrCreateUrlDetails = sinon.stub().callsArg(3) + describe("_ensureUrlIsInCache", function() { + beforeEach(function() { + this.UrlFetcher.pipeUrlToFile = sinon.stub().callsArg(2); + return this.UrlCache._updateOrCreateUrlDetails = sinon.stub().callsArg(3); + }); - describe "when the URL needs updating", -> - beforeEach -> - @UrlCache._doesUrlNeedDownloading = sinon.stub().callsArgWith(3, null, true) - @UrlCache._ensureUrlIsInCache(@project_id, @url, @lastModified, @callback) + describe("when the URL needs updating", function() { + beforeEach(function() { + this.UrlCache._doesUrlNeedDownloading = sinon.stub().callsArgWith(3, null, true); + return this.UrlCache._ensureUrlIsInCache(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should check that the url needs downloading", -> - @UrlCache._doesUrlNeedDownloading - .calledWith(@project_id, @url, @lastModifiedRoundedToSeconds) - .should.equal true + it("should check that the url needs downloading", function() { + return this.UrlCache._doesUrlNeedDownloading + .calledWith(this.project_id, this.url, this.lastModifiedRoundedToSeconds) + .should.equal(true); + }); - it "should download the URL to the cache file", -> - @UrlFetcher.pipeUrlToFile - .calledWith(@url, @UrlCache._cacheFilePathForUrl(@project_id, @url)) - .should.equal true + it("should download the URL to the cache file", function() { + return this.UrlFetcher.pipeUrlToFile + .calledWith(this.url, this.UrlCache._cacheFilePathForUrl(this.project_id, this.url)) + .should.equal(true); + }); - it "should update the database entry", -> - @UrlCache._updateOrCreateUrlDetails - .calledWith(@project_id, @url, @lastModifiedRoundedToSeconds) - .should.equal true + it("should update the database entry", function() { + return this.UrlCache._updateOrCreateUrlDetails + .calledWith(this.project_id, this.url, this.lastModifiedRoundedToSeconds) + .should.equal(true); + }); - it "should return the callback with the cache file path", -> - @callback - .calledWith(null, @UrlCache._cacheFilePathForUrl(@project_id, @url)) - .should.equal true + return it("should return the callback with the cache file path", function() { + return this.callback + .calledWith(null, this.UrlCache._cacheFilePathForUrl(this.project_id, this.url)) + .should.equal(true); + }); + }); - describe "when the URL does not need updating", -> - beforeEach -> - @UrlCache._doesUrlNeedDownloading = sinon.stub().callsArgWith(3, null, false) - @UrlCache._ensureUrlIsInCache(@project_id, @url, @lastModified, @callback) + return describe("when the URL does not need updating", function() { + beforeEach(function() { + this.UrlCache._doesUrlNeedDownloading = sinon.stub().callsArgWith(3, null, false); + return this.UrlCache._ensureUrlIsInCache(this.project_id, this.url, this.lastModified, this.callback); + }); - it "should not download the URL to the cache file", -> - @UrlFetcher.pipeUrlToFile - .called.should.equal false + it("should not download the URL to the cache file", function() { + return this.UrlFetcher.pipeUrlToFile + .called.should.equal(false); + }); - it "should return the callback with the cache file path", -> - @callback - .calledWith(null, @UrlCache._cacheFilePathForUrl(@project_id, @url)) - .should.equal true + return it("should return the callback with the cache file path", function() { + return this.callback + .calledWith(null, this.UrlCache._cacheFilePathForUrl(this.project_id, this.url)) + .should.equal(true); + }); + }); + }); - describe "downloadUrlToFile", -> - beforeEach -> - @cachePath = "path/to/cached/url" - @destPath = "path/to/destination" - @UrlCache._copyFile = sinon.stub().callsArg(2) - @UrlCache._ensureUrlIsInCache = sinon.stub().callsArgWith(3, null, @cachePath) - @UrlCache.downloadUrlToFile(@project_id, @url, @destPath, @lastModified, @callback) + describe("downloadUrlToFile", function() { + beforeEach(function() { + this.cachePath = "path/to/cached/url"; + this.destPath = "path/to/destination"; + this.UrlCache._copyFile = sinon.stub().callsArg(2); + this.UrlCache._ensureUrlIsInCache = sinon.stub().callsArgWith(3, null, this.cachePath); + return this.UrlCache.downloadUrlToFile(this.project_id, this.url, this.destPath, this.lastModified, this.callback); + }); - it "should ensure the URL is downloaded and updated in the cache", -> - @UrlCache._ensureUrlIsInCache - .calledWith(@project_id, @url, @lastModified) - .should.equal true + it("should ensure the URL is downloaded and updated in the cache", function() { + return this.UrlCache._ensureUrlIsInCache + .calledWith(this.project_id, this.url, this.lastModified) + .should.equal(true); + }); - it "should copy the file to the new location", -> - @UrlCache._copyFile - .calledWith(@cachePath, @destPath) - .should.equal true + it("should copy the file to the new location", function() { + return this.UrlCache._copyFile + .calledWith(this.cachePath, this.destPath) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "_deleteUrlCacheFromDisk", -> - beforeEach -> - @fs.unlink = sinon.stub().callsArg(1) - @UrlCache._deleteUrlCacheFromDisk(@project_id, @url, @callback) + describe("_deleteUrlCacheFromDisk", function() { + beforeEach(function() { + this.fs.unlink = sinon.stub().callsArg(1); + return this.UrlCache._deleteUrlCacheFromDisk(this.project_id, this.url, this.callback); + }); - it "should delete the cache file", -> - @fs.unlink - .calledWith(@UrlCache._cacheFilePathForUrl(@project_id, @url)) - .should.equal true + it("should delete the cache file", function() { + return this.fs.unlink + .calledWith(this.UrlCache._cacheFilePathForUrl(this.project_id, this.url)) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "_clearUrlFromCache", -> - beforeEach -> - @UrlCache._deleteUrlCacheFromDisk = sinon.stub().callsArg(2) - @UrlCache._clearUrlDetails = sinon.stub().callsArg(2) - @UrlCache._clearUrlFromCache @project_id, @url, @callback + describe("_clearUrlFromCache", function() { + beforeEach(function() { + this.UrlCache._deleteUrlCacheFromDisk = sinon.stub().callsArg(2); + this.UrlCache._clearUrlDetails = sinon.stub().callsArg(2); + return this.UrlCache._clearUrlFromCache(this.project_id, this.url, this.callback); + }); - it "should delete the file on disk", -> - @UrlCache._deleteUrlCacheFromDisk - .calledWith(@project_id, @url) - .should.equal true + it("should delete the file on disk", function() { + return this.UrlCache._deleteUrlCacheFromDisk + .calledWith(this.project_id, this.url) + .should.equal(true); + }); - it "should clear the entry in the database", -> - @UrlCache._clearUrlDetails - .calledWith(@project_id, @url) - .should.equal true + it("should clear the entry in the database", function() { + return this.UrlCache._clearUrlDetails + .calledWith(this.project_id, this.url) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "clearProject", -> - beforeEach -> - @urls = [ - "www.example.com/file1" + return describe("clearProject", function() { + beforeEach(function() { + this.urls = [ + "www.example.com/file1", "www.example.com/file2" - ] - @UrlCache._findAllUrlsInProject = sinon.stub().callsArgWith(1, null, @urls) - @UrlCache._clearUrlFromCache = sinon.stub().callsArg(2) - @UrlCache.clearProject @project_id, @callback + ]; + this.UrlCache._findAllUrlsInProject = sinon.stub().callsArgWith(1, null, this.urls); + this.UrlCache._clearUrlFromCache = sinon.stub().callsArg(2); + return this.UrlCache.clearProject(this.project_id, this.callback); + }); - it "should clear the cache for each url in the project", -> - for url in @urls - @UrlCache._clearUrlFromCache - .calledWith(@project_id, url) - .should.equal true + it("should clear the cache for each url in the project", function() { + return Array.from(this.urls).map((url) => + this.UrlCache._clearUrlFromCache + .calledWith(this.project_id, url) + .should.equal(true)); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); +}); diff --git a/test/unit/coffee/UrlFetcherTests.js b/test/unit/coffee/UrlFetcherTests.js index e91720e..21258ab 100644 --- a/test/unit/coffee/UrlFetcherTests.js +++ b/test/unit/coffee/UrlFetcherTests.js @@ -1,120 +1,154 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../app/js/UrlFetcher' -EventEmitter = require("events").EventEmitter +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const SandboxedModule = require('sandboxed-module'); +const sinon = require('sinon'); +require('chai').should(); +const modulePath = require('path').join(__dirname, '../../../app/js/UrlFetcher'); +const { EventEmitter } = require("events"); -describe "UrlFetcher", -> - beforeEach -> - @callback = sinon.stub() - @url = "https://www.example.com/file/here?query=string" - @UrlFetcher = SandboxedModule.require modulePath, requires: - request: defaults: @defaults = sinon.stub().returns(@request = {}) - fs: @fs = {} - "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() } - "settings-sharelatex": @settings = {} +describe("UrlFetcher", function() { + beforeEach(function() { + this.callback = sinon.stub(); + this.url = "https://www.example.com/file/here?query=string"; + return this.UrlFetcher = SandboxedModule.require(modulePath, { requires: { + request: { defaults: (this.defaults = sinon.stub().returns(this.request = {})) + }, + fs: (this.fs = {}), + "logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }), + "settings-sharelatex": (this.settings = {}) + } + });}); - it "should turn off the cookie jar in request", -> - @defaults.calledWith(jar: false) - .should.equal true + it("should turn off the cookie jar in request", function() { + return this.defaults.calledWith({jar: false}) + .should.equal(true); + }); - describe "rewrite url domain if filestoreDomainOveride is set", -> - beforeEach -> - @path = "/path/to/file/on/disk" - @request.get = sinon.stub().returns(@urlStream = new EventEmitter) - @urlStream.pipe = sinon.stub() - @urlStream.pause = sinon.stub() - @urlStream.resume = sinon.stub() - @fs.createWriteStream = sinon.stub().returns(@fileStream = new EventEmitter) - @fs.unlink = (file, callback) -> callback() + describe("rewrite url domain if filestoreDomainOveride is set", function() { + beforeEach(function() { + this.path = "/path/to/file/on/disk"; + this.request.get = sinon.stub().returns(this.urlStream = new EventEmitter); + this.urlStream.pipe = sinon.stub(); + this.urlStream.pause = sinon.stub(); + this.urlStream.resume = sinon.stub(); + this.fs.createWriteStream = sinon.stub().returns(this.fileStream = new EventEmitter); + return this.fs.unlink = (file, callback) => callback(); + }); - it "should use the normal domain when override not set", (done)-> - @UrlFetcher.pipeUrlToFile @url, @path, => - @request.get.args[0][0].url.should.equal @url - done() - @res = statusCode: 200 - @urlStream.emit "response", @res - @urlStream.emit "end" - @fileStream.emit "finish" + it("should use the normal domain when override not set", function(done){ + this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => { + this.request.get.args[0][0].url.should.equal(this.url); + return done(); + }); + this.res = {statusCode: 200}; + this.urlStream.emit("response", this.res); + this.urlStream.emit("end"); + return this.fileStream.emit("finish"); + }); - it "should use override domain when filestoreDomainOveride is set", (done)-> - @settings.filestoreDomainOveride = "192.11.11.11" - @UrlFetcher.pipeUrlToFile @url, @path, => - @request.get.args[0][0].url.should.equal "192.11.11.11/file/here?query=string" - done() - @res = statusCode: 200 - @urlStream.emit "response", @res - @urlStream.emit "end" - @fileStream.emit "finish" + return it("should use override domain when filestoreDomainOveride is set", function(done){ + this.settings.filestoreDomainOveride = "192.11.11.11"; + this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => { + this.request.get.args[0][0].url.should.equal("192.11.11.11/file/here?query=string"); + return done(); + }); + this.res = {statusCode: 200}; + this.urlStream.emit("response", this.res); + this.urlStream.emit("end"); + return this.fileStream.emit("finish"); + }); + }); - describe "pipeUrlToFile", -> - beforeEach (done)-> - @path = "/path/to/file/on/disk" - @request.get = sinon.stub().returns(@urlStream = new EventEmitter) - @urlStream.pipe = sinon.stub() - @urlStream.pause = sinon.stub() - @urlStream.resume = sinon.stub() - @fs.createWriteStream = sinon.stub().returns(@fileStream = new EventEmitter) - @fs.unlink = (file, callback) -> callback() - done() + return describe("pipeUrlToFile", function() { + beforeEach(function(done){ + this.path = "/path/to/file/on/disk"; + this.request.get = sinon.stub().returns(this.urlStream = new EventEmitter); + this.urlStream.pipe = sinon.stub(); + this.urlStream.pause = sinon.stub(); + this.urlStream.resume = sinon.stub(); + this.fs.createWriteStream = sinon.stub().returns(this.fileStream = new EventEmitter); + this.fs.unlink = (file, callback) => callback(); + return done(); + }); - describe "successfully", -> - beforeEach (done)-> - @UrlFetcher.pipeUrlToFile @url, @path, => - @callback() - done() - @res = statusCode: 200 - @urlStream.emit "response", @res - @urlStream.emit "end" - @fileStream.emit "finish" + describe("successfully", function() { + beforeEach(function(done){ + this.UrlFetcher.pipeUrlToFile(this.url, this.path, () => { + this.callback(); + return done(); + }); + this.res = {statusCode: 200}; + this.urlStream.emit("response", this.res); + this.urlStream.emit("end"); + return this.fileStream.emit("finish"); + }); - it "should request the URL", -> - @request.get - .calledWith(sinon.match {"url": @url}) - .should.equal true + it("should request the URL", function() { + return this.request.get + .calledWith(sinon.match({"url": this.url})) + .should.equal(true); + }); - it "should open the file for writing", -> - @fs.createWriteStream - .calledWith(@path) - .should.equal true + it("should open the file for writing", function() { + return this.fs.createWriteStream + .calledWith(this.path) + .should.equal(true); + }); - it "should pipe the URL to the file", -> - @urlStream.pipe - .calledWith(@fileStream) - .should.equal true + it("should pipe the URL to the file", function() { + return this.urlStream.pipe + .calledWith(this.fileStream) + .should.equal(true); + }); - it "should call the callback", -> - @callback.called.should.equal true + return it("should call the callback", function() { + return this.callback.called.should.equal(true); + }); + }); - describe "with non success status code", -> - beforeEach (done)-> - @UrlFetcher.pipeUrlToFile @url, @path, (err)=> - @callback(err) - done() - @res = statusCode: 404 - @urlStream.emit "response", @res - @urlStream.emit "end" + describe("with non success status code", function() { + beforeEach(function(done){ + this.UrlFetcher.pipeUrlToFile(this.url, this.path, err=> { + this.callback(err); + return done(); + }); + this.res = {statusCode: 404}; + this.urlStream.emit("response", this.res); + return this.urlStream.emit("end"); + }); - it "should call the callback with an error", -> - @callback + return it("should call the callback with an error", function() { + return this.callback .calledWith(new Error("URL returned non-success status code: 404")) - .should.equal true + .should.equal(true); + }); + }); - describe "with error", -> - beforeEach (done)-> - @UrlFetcher.pipeUrlToFile @url, @path, (err)=> - @callback(err) - done() - @urlStream.emit "error", @error = new Error("something went wrong") + return describe("with error", function() { + beforeEach(function(done){ + this.UrlFetcher.pipeUrlToFile(this.url, this.path, err=> { + this.callback(err); + return done(); + }); + return this.urlStream.emit("error", (this.error = new Error("something went wrong"))); + }); - it "should call the callback with the error", -> - @callback - .calledWith(@error) - .should.equal true + it("should call the callback with the error", function() { + return this.callback + .calledWith(this.error) + .should.equal(true); + }); - it "should only call the callback once, even if end is called", -> - @urlStream.emit "end" - @callback.calledOnce.should.equal true + return it("should only call the callback once, even if end is called", function() { + this.urlStream.emit("end"); + return this.callback.calledOnce.should.equal(true); + }); + }); + }); +});