فهرست منبع

decaffeinate: Convert AWSSDKPersistorManagerTests.coffee and 12 other files to JS

decaffeinate 6 سال پیش
والد
کامیت
5cf7138ef1

+ 349 - 268
services/filestore/test/unit/coffee/AWSSDKPersistorManagerTests.js

@@ -1,272 +1,353 @@
-sinon = require 'sinon'
-chai = require 'chai'
-
-should = chai.should()
-expect = chai.expect
-
-modulePath = "../../../app/js/AWSSDKPersistorManager.js"
-SandboxedModule = require 'sandboxed-module'
-
-describe "AWSSDKPersistorManager", ->
-	beforeEach ->
-		@settings =
-			filestore:
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require('sinon');
+const chai = require('chai');
+
+const should = chai.should();
+const {
+    expect
+} = chai;
+
+const modulePath = "../../../app/js/AWSSDKPersistorManager.js";
+const SandboxedModule = require('sandboxed-module');
+
+describe("AWSSDKPersistorManager", function() {
+	beforeEach(function() {
+		this.settings = {
+			filestore: {
 				backend: "aws-sdk"
-		@s3 =
-			upload: sinon.stub()
-			getObject: sinon.stub()
-			copyObject: sinon.stub()
-			deleteObject: sinon.stub()
-			listObjects: sinon.stub()
-			deleteObjects: sinon.stub()
+			}
+		};
+		this.s3 = {
+			upload: sinon.stub(),
+			getObject: sinon.stub(),
+			copyObject: sinon.stub(),
+			deleteObject: sinon.stub(),
+			listObjects: sinon.stub(),
+			deleteObjects: sinon.stub(),
 			headObject: sinon.stub()
-		@awssdk =
-			S3: sinon.stub().returns @s3
-
-		@requires =
-			"aws-sdk": @awssdk
-			"settings-sharelatex": @settings
-			"logger-sharelatex":
-				log:->
-				err:->
-			"fs": @fs =
-				createReadStream: sinon.stub()
-			"./Errors": @Errors =
-				NotFoundError: sinon.stub()
-		@key = "my/key"
-		@bucketName = "my-bucket"
-		@error = "my error"
-		@AWSSDKPersistorManager = SandboxedModule.require modulePath, requires: @requires
-
-	describe "sendFile", ->
-		beforeEach ->
-			@stream = {}
-			@fsPath = "/usr/local/some/file"
-			@fs.createReadStream.returns @stream
-
-		it "should put the file with s3.upload", (done) ->
-			@s3.upload.callsArgWith 1
-			@AWSSDKPersistorManager.sendFile @bucketName, @key, @fsPath, (err) =>
-				expect(err).to.not.be.ok
-				expect(@s3.upload.calledOnce, "called only once").to.be.true
-				expect((@s3.upload.calledWith Bucket: @bucketName, Key: @key, Body: @stream)
-							 , "called with correct arguments").to.be.true
-				done()
-
-		it "should dispatch the error from s3.upload", (done) ->
-			@s3.upload.callsArgWith 1, @error
-			@AWSSDKPersistorManager.sendFile @bucketName, @key, @fsPath, (err) =>
-				expect(err).to.equal @error
-				done()
-
-
-	describe "sendStream", ->
-		beforeEach ->
-			@stream = {}
-
-		it "should put the file with s3.upload", (done) ->
-			@s3.upload.callsArgWith 1
-			@AWSSDKPersistorManager.sendStream @bucketName, @key, @stream, (err) =>
-				expect(err).to.not.be.ok
-				expect(@s3.upload.calledOnce, "called only once").to.be.true
-				expect((@s3.upload.calledWith Bucket: @bucketName, Key: @key, Body: @stream),
-							 "called with correct arguments").to.be.true
-				done()
-
-		it "should dispatch the error from s3.upload", (done) ->
-			@s3.upload.callsArgWith 1, @error
-			@AWSSDKPersistorManager.sendStream @bucketName, @key, @stream, (err) =>
-				expect(err).to.equal @error
-				done()
-
-	describe "getFileStream", ->
-		beforeEach ->
-			@opts = {}
-			@stream = {}
-			@read_stream =
-				on: @read_stream_on = sinon.stub()
-			@object =
-				createReadStream: sinon.stub().returns @read_stream
-			@s3.getObject.returns @object
-
-		it "should return a stream from s3.getObject", (done) ->
-			@read_stream_on.withArgs('readable').callsArgWith 1
-
-			@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
-				expect(@read_stream_on.calledTwice)
-				expect(err).to.not.be.ok
-				expect(stream, "returned the stream").to.equal @read_stream
-				expect((@s3.getObject.calledWith Bucket: @bucketName, Key: @key),
-							 "called with correct arguments").to.be.true
-				done()
-
-		describe "with start and end options", ->
-			beforeEach ->
-				@opts =
-					start: 0
+		};
+		this.awssdk =
+			{S3: sinon.stub().returns(this.s3)};
+
+		this.requires = {
+			"aws-sdk": this.awssdk,
+			"settings-sharelatex": this.settings,
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			},
+			"fs": (this.fs =
+				{createReadStream: sinon.stub()}),
+			"./Errors": (this.Errors =
+				{NotFoundError: sinon.stub()})
+		};
+		this.key = "my/key";
+		this.bucketName = "my-bucket";
+		this.error = "my error";
+		return this.AWSSDKPersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
+	});
+
+	describe("sendFile", function() {
+		beforeEach(function() {
+			this.stream = {};
+			this.fsPath = "/usr/local/some/file";
+			return this.fs.createReadStream.returns(this.stream);
+		});
+
+		it("should put the file with s3.upload", function(done) {
+			this.s3.upload.callsArgWith(1);
+			return this.AWSSDKPersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err => {
+				expect(err).to.not.be.ok;
+				expect(this.s3.upload.calledOnce, "called only once").to.be.true;
+				expect((this.s3.upload.calledWith({Bucket: this.bucketName, Key: this.key, Body: this.stream}))
+							 , "called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		return it("should dispatch the error from s3.upload", function(done) {
+			this.s3.upload.callsArgWith(1, this.error);
+			return this.AWSSDKPersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err => {
+				expect(err).to.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+
+	describe("sendStream", function() {
+		beforeEach(function() {
+			return this.stream = {};});
+
+		it("should put the file with s3.upload", function(done) {
+			this.s3.upload.callsArgWith(1);
+			return this.AWSSDKPersistorManager.sendStream(this.bucketName, this.key, this.stream, err => {
+				expect(err).to.not.be.ok;
+				expect(this.s3.upload.calledOnce, "called only once").to.be.true;
+				expect((this.s3.upload.calledWith({Bucket: this.bucketName, Key: this.key, Body: this.stream})),
+							 "called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		return it("should dispatch the error from s3.upload", function(done) {
+			this.s3.upload.callsArgWith(1, this.error);
+			return this.AWSSDKPersistorManager.sendStream(this.bucketName, this.key, this.stream, err => {
+				expect(err).to.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	describe("getFileStream", function() {
+		beforeEach(function() {
+			this.opts = {};
+			this.stream = {};
+			this.read_stream =
+				{on: (this.read_stream_on = sinon.stub())};
+			this.object =
+				{createReadStream: sinon.stub().returns(this.read_stream)};
+			return this.s3.getObject.returns(this.object);
+		});
+
+		it("should return a stream from s3.getObject", function(done) {
+			this.read_stream_on.withArgs('readable').callsArgWith(1);
+
+			return this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
+				expect(this.read_stream_on.calledTwice);
+				expect(err).to.not.be.ok;
+				expect(stream, "returned the stream").to.equal(this.read_stream);
+				expect((this.s3.getObject.calledWith({Bucket: this.bucketName, Key: this.key})),
+							 "called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		describe("with start and end options", function() {
+			beforeEach(function() {
+				return this.opts = {
+					start: 0,
 					end: 8
-			it "should pass headers to the s3.GetObject", (done) ->
-				@read_stream_on.withArgs('readable').callsArgWith 1
-				@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
-					expect((@s3.getObject.calledWith Bucket: @bucketName, Key: @key, Range: 'bytes=0-8'),
-						"called with correct arguments").to.be.true
-				done()
-
-		describe "error conditions", ->
-			describe "when the file doesn't exist", ->
-				beforeEach ->
-					@error = new Error()
-					@error.code = 'NoSuchKey'
-				it "should produce a NotFoundError", (done) ->
-					@read_stream_on.withArgs('error').callsArgWith 1, @error
-					@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
-						expect(stream).to.not.be.ok
-						expect(err).to.be.ok
-						expect(err instanceof @Errors.NotFoundError, "error is a correct instance").to.equal true
-						done()
-
-			describe "when there is some other error", ->
-				beforeEach ->
-					@error = new Error()
-				it "should dispatch the error from s3 object stream", (done) ->
-					@read_stream_on.withArgs('error').callsArgWith 1, @error
-					@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
-						expect(stream).to.not.be.ok
-						expect(err).to.be.ok
-						expect(err).to.equal @error
-						done()
-
-	describe "copyFile", ->
-		beforeEach ->
-			@destKey = "some/key"
-			@stream = {}
-
-		it "should copy the file with s3.copyObject", (done) ->
-			@s3.copyObject.callsArgWith 1
-			@AWSSDKPersistorManager.copyFile @bucketName, @key, @destKey, (err) =>
-				expect(err).to.not.be.ok
-				expect(@s3.copyObject.calledOnce, "called only once").to.be.true
-				expect((@s3.copyObject.calledWith Bucket: @bucketName, Key: @destKey, CopySource: @bucketName + '/' + @key),
-					"called with correct arguments").to.be.true
-				done()
-
-		it "should dispatch the error from s3.copyObject", (done) ->
-			@s3.copyObject.callsArgWith 1, @error
-			@AWSSDKPersistorManager.copyFile @bucketName, @key, @destKey, (err) =>
-				expect(err).to.equal @error
-				done()
-
-	describe "deleteFile", ->
-		it "should delete the file with s3.deleteObject", (done) ->
-			@s3.deleteObject.callsArgWith 1
-			@AWSSDKPersistorManager.deleteFile @bucketName, @key, (err) =>
-				expect(err).to.not.be.ok
-				expect(@s3.deleteObject.calledOnce, "called only once").to.be.true
-				expect((@s3.deleteObject.calledWith Bucket: @bucketName, Key: @key),
-					"called with correct arguments").to.be.true
-				done()
-
-		it "should dispatch the error from s3.deleteObject", (done) ->
-			@s3.deleteObject.callsArgWith 1, @error
-			@AWSSDKPersistorManager.deleteFile @bucketName, @key, (err) =>
-				expect(err).to.equal @error
-				done()
-
-	describe "deleteDirectory", ->
-
-		it "should list the directory content using s3.listObjects", (done) ->
-			@s3.listObjects.callsArgWith 1, null, Contents: []
-			@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
-				expect(err).to.not.be.ok
-				expect(@s3.listObjects.calledOnce, "called only once").to.be.true
-				expect((@s3.listObjects.calledWith Bucket: @bucketName, Prefix: @key),
-					"called with correct arguments").to.be.true
-				done()
-
-		it "should dispatch the error from s3.listObjects", (done) ->
-			@s3.listObjects.callsArgWith 1, @error
-			@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
-				expect(err).to.equal @error
-				done()
-
-		describe "with directory content", ->
-			beforeEach ->
-				@fileList = [
-					Key: 'foo'
-				, Key: 'bar'
+				};
+			});
+			return it("should pass headers to the s3.GetObject", function(done) {
+				this.read_stream_on.withArgs('readable').callsArgWith(1);
+				this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
+					return expect((this.s3.getObject.calledWith({Bucket: this.bucketName, Key: this.key, Range: 'bytes=0-8'})),
+						"called with correct arguments").to.be.true;
+				});
+				return done();
+			});
+		});
+
+		return describe("error conditions", function() {
+			describe("when the file doesn't exist", function() {
+				beforeEach(function() {
+					this.error = new Error();
+					return this.error.code = 'NoSuchKey';
+				});
+				return it("should produce a NotFoundError", function(done) {
+					this.read_stream_on.withArgs('error').callsArgWith(1, this.error);
+					return this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
+						expect(stream).to.not.be.ok;
+						expect(err).to.be.ok;
+						expect(err instanceof this.Errors.NotFoundError, "error is a correct instance").to.equal(true);
+						return done();
+					});
+				});
+			});
+
+			return describe("when there is some other error", function() {
+				beforeEach(function() {
+					return this.error = new Error();
+				});
+				return it("should dispatch the error from s3 object stream", function(done) {
+					this.read_stream_on.withArgs('error').callsArgWith(1, this.error);
+					return this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
+						expect(stream).to.not.be.ok;
+						expect(err).to.be.ok;
+						expect(err).to.equal(this.error);
+						return done();
+					});
+				});
+			});
+		});
+	});
+
+	describe("copyFile", function() {
+		beforeEach(function() {
+			this.destKey = "some/key";
+			return this.stream = {};});
+
+		it("should copy the file with s3.copyObject", function(done) {
+			this.s3.copyObject.callsArgWith(1);
+			return this.AWSSDKPersistorManager.copyFile(this.bucketName, this.key, this.destKey, err => {
+				expect(err).to.not.be.ok;
+				expect(this.s3.copyObject.calledOnce, "called only once").to.be.true;
+				expect((this.s3.copyObject.calledWith({Bucket: this.bucketName, Key: this.destKey, CopySource: this.bucketName + '/' + this.key})),
+					"called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		return it("should dispatch the error from s3.copyObject", function(done) {
+			this.s3.copyObject.callsArgWith(1, this.error);
+			return this.AWSSDKPersistorManager.copyFile(this.bucketName, this.key, this.destKey, err => {
+				expect(err).to.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	describe("deleteFile", function() {
+		it("should delete the file with s3.deleteObject", function(done) {
+			this.s3.deleteObject.callsArgWith(1);
+			return this.AWSSDKPersistorManager.deleteFile(this.bucketName, this.key, err => {
+				expect(err).to.not.be.ok;
+				expect(this.s3.deleteObject.calledOnce, "called only once").to.be.true;
+				expect((this.s3.deleteObject.calledWith({Bucket: this.bucketName, Key: this.key})),
+					"called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		return it("should dispatch the error from s3.deleteObject", function(done) {
+			this.s3.deleteObject.callsArgWith(1, this.error);
+			return this.AWSSDKPersistorManager.deleteFile(this.bucketName, this.key, err => {
+				expect(err).to.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	describe("deleteDirectory", function() {
+
+		it("should list the directory content using s3.listObjects", function(done) {
+			this.s3.listObjects.callsArgWith(1, null, {Contents: []});
+			return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
+				expect(err).to.not.be.ok;
+				expect(this.s3.listObjects.calledOnce, "called only once").to.be.true;
+				expect((this.s3.listObjects.calledWith({Bucket: this.bucketName, Prefix: this.key})),
+					"called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		it("should dispatch the error from s3.listObjects", function(done) {
+			this.s3.listObjects.callsArgWith(1, this.error);
+			return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
+				expect(err).to.equal(this.error);
+				return done();
+			});
+		});
+
+		return describe("with directory content", function() {
+			beforeEach(function() {
+				return this.fileList = [
+					{Key: 'foo'}
+				, { Key: 'bar'
 				, Key: 'baz'
-				]
-
-			it "should forward the file keys to s3.deleteObjects", (done) ->
-				@s3.listObjects.callsArgWith 1, null, Contents: @fileList
-				@s3.deleteObjects.callsArgWith 1
-				@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
-					expect(err).to.not.be.ok
-					expect(@s3.deleteObjects.calledOnce, "called only once").to.be.true
-					expect((@s3.deleteObjects.calledWith
-							Bucket: @bucketName
-							Delete:
-								Quiet: true
-								Objects: @fileList),
-						"called with correct arguments").to.be.true
-					done()
-
-			it "should dispatch the error from s3.deleteObjects", (done) ->
-				@s3.listObjects.callsArgWith 1, null, Contents: @fileList
-				@s3.deleteObjects.callsArgWith 1, @error
-				@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
-					expect(err).to.equal @error
-					done()
-
-
-	describe "checkIfFileExists", ->
-
-		it "should check for the file with s3.headObject", (done) ->
-			@s3.headObject.callsArgWith 1, null, {}
-			@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
-				expect(err).to.not.be.ok
-				expect(@s3.headObject.calledOnce, "called only once").to.be.true
-				expect((@s3.headObject.calledWith Bucket: @bucketName, Key: @key),
-					"called with correct arguments").to.be.true
-				done()
-
-		it "should return false on an inexistant file", (done) ->
-			@s3.headObject.callsArgWith 1, null, {}
-			@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
-				expect(exists).to.be.false
-				done()
-
-		it "should return true on an existing file", (done) ->
-			@s3.headObject.callsArgWith 1, null, ETag: "etag"
-			@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
-				expect(exists).to.be.true
-				done()
-
-		it "should dispatch the error from s3.headObject", (done) ->
-			@s3.headObject.callsArgWith 1, @error
-			@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
-				expect(err).to.equal @error
-				done()
-
-	describe "directorySize", ->
-
-		it "should list the directory content using s3.listObjects", (done) ->
-			@s3.listObjects.callsArgWith 1, null, Contents: []
-			@AWSSDKPersistorManager.directorySize @bucketName, @key, (err) =>
-				expect(err).to.not.be.ok
-				expect(@s3.listObjects.calledOnce, "called only once").to.be.true
-				expect((@s3.listObjects.calledWith Bucket: @bucketName, Prefix: @key),
-					"called with correct arguments").to.be.true
-				done()
-
-		it "should dispatch the error from s3.listObjects", (done) ->
-			@s3.listObjects.callsArgWith 1, @error
-			@AWSSDKPersistorManager.directorySize @bucketName, @key, (err) =>
-				expect(err).to.equal @error
-				done()
-
-		it "should sum directory files sizes", (done) ->
-			@s3.listObjects.callsArgWith 1, null, Contents: [ { Size: 1024 }, { Size: 2048 }]
-			@AWSSDKPersistorManager.directorySize @bucketName, @key, (err, size) =>
-				expect(size).to.equal 3072
-				done()
+			}
+				];});
+
+			it("should forward the file keys to s3.deleteObjects", function(done) {
+				this.s3.listObjects.callsArgWith(1, null, {Contents: this.fileList});
+				this.s3.deleteObjects.callsArgWith(1);
+				return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
+					expect(err).to.not.be.ok;
+					expect(this.s3.deleteObjects.calledOnce, "called only once").to.be.true;
+					expect((this.s3.deleteObjects.calledWith({
+							Bucket: this.bucketName,
+							Delete: {
+								Quiet: true,
+								Objects: this.fileList
+							}})),
+						"called with correct arguments").to.be.true;
+					return done();
+				});
+			});
+
+			return it("should dispatch the error from s3.deleteObjects", function(done) {
+				this.s3.listObjects.callsArgWith(1, null, {Contents: this.fileList});
+				this.s3.deleteObjects.callsArgWith(1, this.error);
+				return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
+					expect(err).to.equal(this.error);
+					return done();
+				});
+			});
+		});
+	});
+
+
+	describe("checkIfFileExists", function() {
+
+		it("should check for the file with s3.headObject", function(done) {
+			this.s3.headObject.callsArgWith(1, null, {});
+			return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
+				expect(err).to.not.be.ok;
+				expect(this.s3.headObject.calledOnce, "called only once").to.be.true;
+				expect((this.s3.headObject.calledWith({Bucket: this.bucketName, Key: this.key})),
+					"called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		it("should return false on an inexistant file", function(done) {
+			this.s3.headObject.callsArgWith(1, null, {});
+			return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
+				expect(exists).to.be.false;
+				return done();
+			});
+		});
+
+		it("should return true on an existing file", function(done) {
+			this.s3.headObject.callsArgWith(1, null, {ETag: "etag"});
+			return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
+				expect(exists).to.be.true;
+				return done();
+			});
+		});
+
+		return it("should dispatch the error from s3.headObject", function(done) {
+			this.s3.headObject.callsArgWith(1, this.error);
+			return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
+				expect(err).to.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	return describe("directorySize", function() {
+
+		it("should list the directory content using s3.listObjects", function(done) {
+			this.s3.listObjects.callsArgWith(1, null, {Contents: []});
+			return this.AWSSDKPersistorManager.directorySize(this.bucketName, this.key, err => {
+				expect(err).to.not.be.ok;
+				expect(this.s3.listObjects.calledOnce, "called only once").to.be.true;
+				expect((this.s3.listObjects.calledWith({Bucket: this.bucketName, Prefix: this.key})),
+					"called with correct arguments").to.be.true;
+				return done();
+			});
+		});
+
+		it("should dispatch the error from s3.listObjects", function(done) {
+			this.s3.listObjects.callsArgWith(1, this.error);
+			return this.AWSSDKPersistorManager.directorySize(this.bucketName, this.key, err => {
+				expect(err).to.equal(this.error);
+				return done();
+			});
+		});
+
+		return it("should sum directory files sizes", function(done) {
+			this.s3.listObjects.callsArgWith(1, null, {Contents: [ { Size: 1024 }, { Size: 2048 }]});
+			return this.AWSSDKPersistorManager.directorySize(this.bucketName, this.key, (err, size) => {
+				expect(size).to.equal(3072);
+				return done();
+			});
+		});
+	});
+});

+ 88 - 59
services/filestore/test/unit/coffee/BucketControllerTests.js

@@ -1,71 +1,100 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/BucketController.js"
-SandboxedModule = require('sandboxed-module')
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/BucketController.js";
+const SandboxedModule = require('sandboxed-module');
 
-describe "BucketController", ->
+describe("BucketController", function() {
 
-	beforeEach ->
-		@PersistorManager =
-			sendStream: sinon.stub()
-			copyFile: sinon.stub()
+	beforeEach(function() {
+		this.PersistorManager = {
+			sendStream: sinon.stub(),
+			copyFile: sinon.stub(),
 			deleteFile:sinon.stub()
+		};
 
-		@settings =
-			s3:
-				buckets:
+		this.settings = {
+			s3: {
+				buckets: {
 					user_files:"user_files"
-			filestore:
-				backend: "s3"
-				s3:
-					secret: "secret"
+				}
+			},
+			filestore: {
+				backend: "s3",
+				s3: {
+					secret: "secret",
 					key: "this_key"
+				}
+			}
+		};
 
-		@FileHandler =
-			getFile: sinon.stub()
-			deleteFile: sinon.stub()
-			insertFile: sinon.stub()
+		this.FileHandler = {
+			getFile: sinon.stub(),
+			deleteFile: sinon.stub(),
+			insertFile: sinon.stub(),
 			getDirectorySize: sinon.stub()
-		@LocalFileWriter = {}
-		@controller = SandboxedModule.require modulePath, requires:
-			"./LocalFileWriter":@LocalFileWriter
-			"./FileHandler": @FileHandler
-			"./PersistorManager":@PersistorManager
-			"settings-sharelatex": @settings
-			"metrics-sharelatex": 
-				inc:->
-			"logger-sharelatex":
-				log:->
-				err:->
-		@project_id = "project_id"
-		@file_id = "file_id"
-		@bucket = "user_files"
-		@key = "#{@project_id}/#{@file_id}"
-		@req =
-			query:{}
-			params:
-				bucket: @bucket
-				0: @key
+		};
+		this.LocalFileWriter = {};
+		this.controller = SandboxedModule.require(modulePath, { requires: {
+			"./LocalFileWriter":this.LocalFileWriter,
+			"./FileHandler": this.FileHandler,
+			"./PersistorManager":this.PersistorManager,
+			"settings-sharelatex": this.settings,
+			"metrics-sharelatex": { 
+				inc() {}
+			},
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			}
+		}
+	}
+		);
+		this.project_id = "project_id";
+		this.file_id = "file_id";
+		this.bucket = "user_files";
+		this.key = `${this.project_id}/${this.file_id}`;
+		this.req = {
+			query:{},
+			params: {
+				bucket: this.bucket,
+				0: this.key
+			},
 			headers: {}
-		@res =
-			setHeader: ->
-		@fileStream = {}
+		};
+		this.res =
+			{setHeader() {}};
+		return this.fileStream = {};});
 
-	describe "getFile", ->
+	return describe("getFile", function() {
 
-		it "should pipe the stream", (done)->
-			@FileHandler.getFile.callsArgWith(3, null, @fileStream)
-			@fileStream.pipe = (res)=>
-				res.should.equal @res
-				done()
-			@controller.getFile @req, @res
+		it("should pipe the stream", function(done){
+			this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
+			this.fileStream.pipe = res=> {
+				res.should.equal(this.res);
+				return done();
+			};
+			return this.controller.getFile(this.req, this.res);
+		});
 
-		it "should send a 500 if there is a problem", (done)->
-			@FileHandler.getFile.callsArgWith(3, "error")
-			@res.send = (code)=>
-				code.should.equal 500
-				done()
-			@controller.getFile @req, @res
+		return it("should send a 500 if there is a problem", function(done){
+			this.FileHandler.getFile.callsArgWith(3, "error");
+			this.res.send = code=> {
+				code.should.equal(500);
+				return done();
+			};
+			return this.controller.getFile(this.req, this.res);
+		});
+	});
+});

+ 369 - 278
services/filestore/test/unit/coffee/FSPersistorManagerTests.js

@@ -1,281 +1,372 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should
-expect = chai.expect
-modulePath = "../../../app/js/FSPersistorManager.js"
-SandboxedModule = require('sandboxed-module')
-fs = require("fs")
-response = require("response")
-
-describe "FSPersistorManagerTests", ->
-
-  beforeEach ->
-    @Fs =
-      rename:sinon.stub()
-      createReadStream:sinon.stub()
-      createWriteStream:sinon.stub()
-      unlink:sinon.stub()
-      rmdir:sinon.stub()
-      exists:sinon.stub()
-      readdir:sinon.stub()
-      open:sinon.stub()
-      openSync:sinon.stub()
-      fstatSync:sinon.stub()
-      closeSync:sinon.stub()
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+  assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const {
+  should
+} = chai;
+const {
+  expect
+} = chai;
+const modulePath = "../../../app/js/FSPersistorManager.js";
+const SandboxedModule = require('sandboxed-module');
+const fs = require("fs");
+const response = require("response");
+
+describe("FSPersistorManagerTests", function() {
+
+  beforeEach(function() {
+    this.Fs = {
+      rename:sinon.stub(),
+      createReadStream:sinon.stub(),
+      createWriteStream:sinon.stub(),
+      unlink:sinon.stub(),
+      rmdir:sinon.stub(),
+      exists:sinon.stub(),
+      readdir:sinon.stub(),
+      open:sinon.stub(),
+      openSync:sinon.stub(),
+      fstatSync:sinon.stub(),
+      closeSync:sinon.stub(),
       stat:sinon.stub()
-    @Rimraf = sinon.stub()
-    @LocalFileWriter =
-      writeStream: sinon.stub()
+    };
+    this.Rimraf = sinon.stub();
+    this.LocalFileWriter = {
+      writeStream: sinon.stub(),
       deleteFile: sinon.stub()
-    @requires =
-      "./LocalFileWriter":@LocalFileWriter
-      "fs":@Fs
-      "logger-sharelatex":
-        log:->
-        err:->
-      "response":response
-      "rimraf":@Rimraf
-      "./Errors": @Errors =
-        NotFoundError: sinon.stub()
-    @location = "/tmp"
-    @name1 = "530f2407e7ef165704000007/530f838b46d9a9e859000008"
-    @name1Filtered ="530f2407e7ef165704000007_530f838b46d9a9e859000008"
-    @name2 = "second_file"
-    @error = "error_message"
-    @FSPersistorManager = SandboxedModule.require modulePath, requires: @requires
-
-  describe "sendFile", ->
-    beforeEach ->
-      @Fs.createReadStream = sinon.stub().returns({
-        on: ->
-        pipe: ->
-      })
-
-    it "should copy the file", (done) ->
-      @Fs.createWriteStream =sinon.stub().returns({
-        on: (event, handler) ->
-          process.nextTick(handler) if event is 'finish'
-      })
-      @FSPersistorManager.sendFile @location, @name1, @name2, (err)=>
-        @Fs.createReadStream.calledWith(@name2).should.equal true
-        @Fs.createWriteStream.calledWith("#{@location}/#{@name1Filtered}" ).should.equal true
-        done()
-
-    it "should return an error if the file cannot be stored", (done) ->
-      @Fs.createWriteStream =sinon.stub().returns({
-        on: (event, handler) =>
-         if event is 'error'
-          process.nextTick () =>
-            handler(@error)
-      })
-      @FSPersistorManager.sendFile @location, @name1, @name2, (err)=>
-        @Fs.createReadStream.calledWith(@name2).should.equal true
-        @Fs.createWriteStream.calledWith("#{@location}/#{@name1Filtered}" ).should.equal true
-        err.should.equal @error
-        done()
-
-  describe "sendStream", ->
-    beforeEach ->
-      @FSPersistorManager.sendFile = sinon.stub().callsArgWith(3)
-      @LocalFileWriter.writeStream.callsArgWith(2, null, @name1)
-      @LocalFileWriter.deleteFile.callsArg(1)
-      @SourceStream =
-        on:->
-
-    it "should sent stream to LocalFileWriter", (done)->
-      @FSPersistorManager.sendStream @location, @name1, @SourceStream, =>
-        @LocalFileWriter.writeStream.calledWith(@SourceStream).should.equal true
-        done()
-
-    it "should return the error from LocalFileWriter", (done)->
-      @LocalFileWriter.writeStream.callsArgWith(2, @error)
-      @FSPersistorManager.sendStream @location, @name1, @SourceStream, (err)=>
-        err.should.equal @error
-        done()
-
-    it "should send the file to the filestore", (done)->
-      @LocalFileWriter.writeStream.callsArgWith(2)
-      @FSPersistorManager.sendStream @location, @name1, @SourceStream, (err)=>
-        @FSPersistorManager.sendFile.called.should.equal true
-        done()
-
-  describe "getFileStream", ->
-    beforeEach ->
-      @opts = {}
-
-    it "should use correct file location", (done) ->
-      @FSPersistorManager.getFileStream @location, @name1, @opts, (err,res) =>
-      @Fs.open.calledWith("#{@location}/#{@name1Filtered}").should.equal true
-      done()
-
-    describe "with start and end options", ->
-
-      beforeEach ->
-        @fd = 2019
-        @opts_in = {start: 0, end: 8}
-        @opts = {start: 0, end: 8, fd: @fd}
-        @Fs.open.callsArgWith(2, null, @fd)
-
-      it 'should pass the options to createReadStream', (done) ->
-        @FSPersistorManager.getFileStream @location, @name1, @opts_in, (err,res)=>
-        @Fs.createReadStream.calledWith(null, @opts).should.equal true
-        done()
-
-    describe "error conditions", ->
-
-      describe "when the file does not exist", ->
-
-        beforeEach ->
-          @fakeCode = 'ENOENT'
-          err = new Error()
-          err.code = @fakeCode
-          @Fs.open.callsArgWith(2, err, null)
-
-        it "should give a NotFoundError", (done) ->
-          @FSPersistorManager.getFileStream @location, @name1, @opts, (err,res)=>
-            expect(res).to.equal null
-            expect(err).to.not.equal null
-            expect(err instanceof @Errors.NotFoundError).to.equal true
-            done()
-
-      describe "when some other error happens", ->
-
-        beforeEach ->
-          @fakeCode = 'SOMETHINGHORRIBLE'
-          err = new Error()
-          err.code = @fakeCode
-          @Fs.open.callsArgWith(2, err, null)
-
-        it "should give an Error", (done) ->
-          @FSPersistorManager.getFileStream @location, @name1, @opts, (err,res)=>
-            expect(res).to.equal null
-            expect(err).to.not.equal null
-            expect(err instanceof Error).to.equal true
-            done()
-
-  describe "getFileSize", ->
-    it "should return the file size", (done) ->
-      expectedFileSize = 75382
-      @Fs.stat.yields(new Error("fs.stat got unexpected arguments"))
-      @Fs.stat.withArgs("#{@location}/#{@name1Filtered}")
-        .yields(null, { size: expectedFileSize })
-
-      @FSPersistorManager.getFileSize @location, @name1, (err, fileSize) =>
-        if err?
-          return done(err)
-        expect(fileSize).to.equal(expectedFileSize)
-        done()
-
-    it "should throw a NotFoundError if the file does not exist", (done) ->
-      error = new Error()
-      error.code = "ENOENT"
-      @Fs.stat.yields(error)
-
-      @FSPersistorManager.getFileSize @location, @name1, (err, fileSize) =>
-        expect(err).to.be.instanceof(@Errors.NotFoundError)
-        done()
-
-    it "should rethrow any other error", (done) ->
-      error = new Error()
-      @Fs.stat.yields(error)
-
-      @FSPersistorManager.getFileSize @location, @name1, (err, fileSize) =>
-        expect(err).to.equal(error)
-        done()
-
-  describe "copyFile", ->
-    beforeEach ->
-      @ReadStream=
-        on:->
+    };
+    this.requires = {
+      "./LocalFileWriter":this.LocalFileWriter,
+      "fs":this.Fs,
+      "logger-sharelatex": {
+        log() {},
+        err() {}
+      },
+      "response":response,
+      "rimraf":this.Rimraf,
+      "./Errors": (this.Errors =
+        {NotFoundError: sinon.stub()})
+    };
+    this.location = "/tmp";
+    this.name1 = "530f2407e7ef165704000007/530f838b46d9a9e859000008";
+    this.name1Filtered ="530f2407e7ef165704000007_530f838b46d9a9e859000008";
+    this.name2 = "second_file";
+    this.error = "error_message";
+    return this.FSPersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
+  });
+
+  describe("sendFile", function() {
+    beforeEach(function() {
+      return this.Fs.createReadStream = sinon.stub().returns({
+        on() {},
+        pipe() {}
+      });
+    });
+
+    it("should copy the file", function(done) {
+      this.Fs.createWriteStream =sinon.stub().returns({
+        on(event, handler) {
+          if (event === 'finish') { return process.nextTick(handler); }
+        }
+      });
+      return this.FSPersistorManager.sendFile(this.location, this.name1, this.name2, err=> {
+        this.Fs.createReadStream.calledWith(this.name2).should.equal(true);
+        this.Fs.createWriteStream.calledWith(`${this.location}/${this.name1Filtered}` ).should.equal(true);
+        return done();
+      });
+    });
+
+    return it("should return an error if the file cannot be stored", function(done) {
+      this.Fs.createWriteStream =sinon.stub().returns({
+        on: (event, handler) => {
+         if (event === 'error') {
+          return process.nextTick(() => {
+            return handler(this.error);
+          });
+        }
+       }
+      });
+      return this.FSPersistorManager.sendFile(this.location, this.name1, this.name2, err=> {
+        this.Fs.createReadStream.calledWith(this.name2).should.equal(true);
+        this.Fs.createWriteStream.calledWith(`${this.location}/${this.name1Filtered}` ).should.equal(true);
+        err.should.equal(this.error);
+        return done();
+      });
+    });
+  });
+
+  describe("sendStream", function() {
+    beforeEach(function() {
+      this.FSPersistorManager.sendFile = sinon.stub().callsArgWith(3);
+      this.LocalFileWriter.writeStream.callsArgWith(2, null, this.name1);
+      this.LocalFileWriter.deleteFile.callsArg(1);
+      return this.SourceStream =
+        {on() {}};
+    });
+
+    it("should sent stream to LocalFileWriter", function(done){
+      return this.FSPersistorManager.sendStream(this.location, this.name1, this.SourceStream, () => {
+        this.LocalFileWriter.writeStream.calledWith(this.SourceStream).should.equal(true);
+        return done();
+      });
+    });
+
+    it("should return the error from LocalFileWriter", function(done){
+      this.LocalFileWriter.writeStream.callsArgWith(2, this.error);
+      return this.FSPersistorManager.sendStream(this.location, this.name1, this.SourceStream, err=> {
+        err.should.equal(this.error);
+        return done();
+      });
+    });
+
+    return it("should send the file to the filestore", function(done){
+      this.LocalFileWriter.writeStream.callsArgWith(2);
+      return this.FSPersistorManager.sendStream(this.location, this.name1, this.SourceStream, err=> {
+        this.FSPersistorManager.sendFile.called.should.equal(true);
+        return done();
+      });
+    });
+  });
+
+  describe("getFileStream", function() {
+    beforeEach(function() {
+      return this.opts = {};});
+
+    it("should use correct file location", function(done) {
+      this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts, (err,res) => {});
+      this.Fs.open.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
+      return done();
+    });
+
+    describe("with start and end options", function() {
+
+      beforeEach(function() {
+        this.fd = 2019;
+        this.opts_in = {start: 0, end: 8};
+        this.opts = {start: 0, end: 8, fd: this.fd};
+        return this.Fs.open.callsArgWith(2, null, this.fd);
+      });
+
+      return it('should pass the options to createReadStream', function(done) {
+        this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts_in, (err,res)=> {});
+        this.Fs.createReadStream.calledWith(null, this.opts).should.equal(true);
+        return done();
+      });
+    });
+
+    return describe("error conditions", function() {
+
+      describe("when the file does not exist", function() {
+
+        beforeEach(function() {
+          this.fakeCode = 'ENOENT';
+          const err = new Error();
+          err.code = this.fakeCode;
+          return this.Fs.open.callsArgWith(2, err, null);
+        });
+
+        return it("should give a NotFoundError", function(done) {
+          return this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts, (err,res)=> {
+            expect(res).to.equal(null);
+            expect(err).to.not.equal(null);
+            expect(err instanceof this.Errors.NotFoundError).to.equal(true);
+            return done();
+          });
+        });
+      });
+
+      return describe("when some other error happens", function() {
+
+        beforeEach(function() {
+          this.fakeCode = 'SOMETHINGHORRIBLE';
+          const err = new Error();
+          err.code = this.fakeCode;
+          return this.Fs.open.callsArgWith(2, err, null);
+        });
+
+        return it("should give an Error", function(done) {
+          return this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts, (err,res)=> {
+            expect(res).to.equal(null);
+            expect(err).to.not.equal(null);
+            expect(err instanceof Error).to.equal(true);
+            return done();
+          });
+        });
+      });
+    });
+  });
+
+  describe("getFileSize", function() {
+    it("should return the file size", function(done) {
+      const expectedFileSize = 75382;
+      this.Fs.stat.yields(new Error("fs.stat got unexpected arguments"));
+      this.Fs.stat.withArgs(`${this.location}/${this.name1Filtered}`)
+        .yields(null, { size: expectedFileSize });
+
+      return this.FSPersistorManager.getFileSize(this.location, this.name1, (err, fileSize) => {
+        if (err != null) {
+          return done(err);
+        }
+        expect(fileSize).to.equal(expectedFileSize);
+        return done();
+      });
+    });
+
+    it("should throw a NotFoundError if the file does not exist", function(done) {
+      const error = new Error();
+      error.code = "ENOENT";
+      this.Fs.stat.yields(error);
+
+      return this.FSPersistorManager.getFileSize(this.location, this.name1, (err, fileSize) => {
+        expect(err).to.be.instanceof(this.Errors.NotFoundError);
+        return done();
+      });
+    });
+
+    return it("should rethrow any other error", function(done) {
+      const error = new Error();
+      this.Fs.stat.yields(error);
+
+      return this.FSPersistorManager.getFileSize(this.location, this.name1, (err, fileSize) => {
+        expect(err).to.equal(error);
+        return done();
+      });
+    });
+  });
+
+  describe("copyFile", function() {
+    beforeEach(function() {
+      this.ReadStream= {
+        on() {},
         pipe:sinon.stub()
-      @WriteStream=
-        on:->
-      @Fs.createReadStream.returns(@ReadStream)
-      @Fs.createWriteStream.returns(@WriteStream)
-
-    it "Should open the source for reading", (done) ->
-      @FSPersistorManager.copyFile @location, @name1, @name2, ->
-      @Fs.createReadStream.calledWith("#{@location}/#{@name1Filtered}").should.equal true
-      done()
-
-    it "Should open the target for writing", (done) ->
-      @FSPersistorManager.copyFile @location, @name1, @name2, ->
-      @Fs.createWriteStream.calledWith("#{@location}/#{@name2}").should.equal true
-      done()
-
-    it "Should pipe the source to the target", (done) ->
-      @FSPersistorManager.copyFile @location, @name1, @name2, ->
-      @ReadStream.pipe.calledWith(@WriteStream).should.equal true
-      done()
-
-  describe "deleteFile", ->
-    beforeEach ->
-      @Fs.unlink.callsArgWith(1,@error)
-
-    it "Should call unlink with correct options", (done) ->
-      @FSPersistorManager.deleteFile @location, @name1, (err) =>
-        @Fs.unlink.calledWith("#{@location}/#{@name1Filtered}").should.equal true
-        done()
-
-    it "Should propogate the error", (done) ->
-      @FSPersistorManager.deleteFile @location, @name1, (err) =>
-        err.should.equal @error
-        done()
-
-
-  describe "deleteDirectory", ->
-    beforeEach ->
-      @Rimraf.callsArgWith(1,@error)
-
-    it "Should call rmdir(rimraf) with correct options", (done) ->
-      @FSPersistorManager.deleteDirectory @location, @name1, (err) =>
-        @Rimraf.calledWith("#{@location}/#{@name1Filtered}").should.equal true
-        done()
-
-    it "Should propogate the error", (done) ->
-      @FSPersistorManager.deleteDirectory @location, @name1, (err) =>
-        err.should.equal @error
-        done()
-
-  describe "checkIfFileExists", ->
-    beforeEach ->
-      @Fs.exists.callsArgWith(1,true)
-
-    it "Should call exists with correct options", (done) ->
-      @FSPersistorManager.checkIfFileExists @location, @name1, (exists) =>
-        @Fs.exists.calledWith("#{@location}/#{@name1Filtered}").should.equal true
-        done()
-
-    # fs.exists simply returns false on any error, so...
-    it "should not return an error", (done) ->
-      @FSPersistorManager.checkIfFileExists @location, @name1, (err,exists) =>
-        expect(err).to.be.null
-        done()
-
-    it "Should return true for existing files", (done) ->
-      @Fs.exists.callsArgWith(1,true)
-      @FSPersistorManager.checkIfFileExists @location, @name1, (err,exists) =>
-        exists.should.be.true
-        done()
-
-    it "Should return false for non-existing files", (done) ->
-      @Fs.exists.callsArgWith(1,false)
-      @FSPersistorManager.checkIfFileExists @location, @name1, (err,exists) =>
-        exists.should.be.false
-        done()
-
-  describe "directorySize", ->
-
-    it "should propogate the error", (done) ->
-      @Fs.readdir.callsArgWith(1, @error)
-      @FSPersistorManager.directorySize @location, @name1, (err, totalsize) =>
-        err.should.equal @error
-        done()
-
-    it "should sum directory files size", (done) ->
-      @Fs.readdir.callsArgWith(1, null, [ {'file1'}, {'file2'} ])
-      @Fs.fstatSync.returns({size : 1024})
-      @FSPersistorManager.directorySize @location, @name1, (err, totalsize) =>
-        expect(totalsize).to.equal 2048
-        done()
+      };
+      this.WriteStream=
+        {on() {}};
+      this.Fs.createReadStream.returns(this.ReadStream);
+      return this.Fs.createWriteStream.returns(this.WriteStream);
+    });
+
+    it("Should open the source for reading", function(done) {
+      this.FSPersistorManager.copyFile(this.location, this.name1, this.name2, function() {});
+      this.Fs.createReadStream.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
+      return done();
+    });
+
+    it("Should open the target for writing", function(done) {
+      this.FSPersistorManager.copyFile(this.location, this.name1, this.name2, function() {});
+      this.Fs.createWriteStream.calledWith(`${this.location}/${this.name2}`).should.equal(true);
+      return done();
+    });
+
+    return it("Should pipe the source to the target", function(done) {
+      this.FSPersistorManager.copyFile(this.location, this.name1, this.name2, function() {});
+      this.ReadStream.pipe.calledWith(this.WriteStream).should.equal(true);
+      return done();
+    });
+  });
+
+  describe("deleteFile", function() {
+    beforeEach(function() {
+      return this.Fs.unlink.callsArgWith(1,this.error);
+    });
+
+    it("Should call unlink with correct options", function(done) {
+      return this.FSPersistorManager.deleteFile(this.location, this.name1, err => {
+        this.Fs.unlink.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
+        return done();
+      });
+    });
+
+    return it("Should propogate the error", function(done) {
+      return this.FSPersistorManager.deleteFile(this.location, this.name1, err => {
+        err.should.equal(this.error);
+        return done();
+      });
+    });
+  });
+
+
+  describe("deleteDirectory", function() {
+    beforeEach(function() {
+      return this.Rimraf.callsArgWith(1,this.error);
+    });
+
+    it("Should call rmdir(rimraf) with correct options", function(done) {
+      return this.FSPersistorManager.deleteDirectory(this.location, this.name1, err => {
+        this.Rimraf.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
+        return done();
+      });
+    });
+
+    return it("Should propogate the error", function(done) {
+      return this.FSPersistorManager.deleteDirectory(this.location, this.name1, err => {
+        err.should.equal(this.error);
+        return done();
+      });
+    });
+  });
+
+  describe("checkIfFileExists", function() {
+    beforeEach(function() {
+      return this.Fs.exists.callsArgWith(1,true);
+    });
+
+    it("Should call exists with correct options", function(done) {
+      return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, exists => {
+        this.Fs.exists.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
+        return done();
+      });
+    });
+
+    // fs.exists simply returns false on any error, so...
+    it("should not return an error", function(done) {
+      return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, (err,exists) => {
+        expect(err).to.be.null;
+        return done();
+      });
+    });
+
+    it("Should return true for existing files", function(done) {
+      this.Fs.exists.callsArgWith(1,true);
+      return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, (err,exists) => {
+        exists.should.be.true;
+        return done();
+      });
+    });
+
+    return it("Should return false for non-existing files", function(done) {
+      this.Fs.exists.callsArgWith(1,false);
+      return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, (err,exists) => {
+        exists.should.be.false;
+        return done();
+      });
+    });
+  });
+
+  return describe("directorySize", function() {
+
+    it("should propogate the error", function(done) {
+      this.Fs.readdir.callsArgWith(1, this.error);
+      return this.FSPersistorManager.directorySize(this.location, this.name1, (err, totalsize) => {
+        err.should.equal(this.error);
+        return done();
+      });
+    });
+
+    return it("should sum directory files size", function(done) {
+      this.Fs.readdir.callsArgWith(1, null, [ {'file1': 'file1'}, {'file2': 'file2'} ]);
+      this.Fs.fstatSync.returns({size : 1024});
+      return this.FSPersistorManager.directorySize(this.location, this.name1, (err, totalsize) => {
+        expect(totalsize).to.equal(2048);
+        return done();
+      });
+    });
+  });
+});

+ 276 - 209
services/filestore/test/unit/coffee/FileControllerTests.js

@@ -1,216 +1,283 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/FileController.js"
-SandboxedModule = require('sandboxed-module')
-
-describe "FileController", ->
-
-	beforeEach ->
-		@PersistorManager =
-			sendStream: sinon.stub()
-			copyFile: sinon.stub()
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/FileController.js";
+const SandboxedModule = require('sandboxed-module');
+
+describe("FileController", function() {
+
+	beforeEach(function() {
+		this.PersistorManager = {
+			sendStream: sinon.stub(),
+			copyFile: sinon.stub(),
 			deleteFile:sinon.stub()
+		};
 
-		@settings =
-			s3:
-				buckets:
+		this.settings = {
+			s3: {
+				buckets: {
 					user_files:"user_files"
-		@FileHandler =
-			getFile: sinon.stub()
-			getFileSize: sinon.stub()
-			deleteFile: sinon.stub()
-			insertFile: sinon.stub()
+				}
+			}
+		};
+		this.FileHandler = {
+			getFile: sinon.stub(),
+			getFileSize: sinon.stub(),
+			deleteFile: sinon.stub(),
+			insertFile: sinon.stub(),
 			getDirectorySize: sinon.stub()
-		@LocalFileWriter = {}
-		@controller = SandboxedModule.require modulePath, requires:
-			"./LocalFileWriter":@LocalFileWriter
-			"./FileHandler": @FileHandler
-			"./PersistorManager":@PersistorManager
-			"./Errors": @Errors =
-				NotFoundError: sinon.stub()
-			"settings-sharelatex": @settings
-			"metrics-sharelatex": 
-				inc:->
-			"logger-sharelatex":
-				log:->
-				err:->
-		@project_id = "project_id"
-		@file_id = "file_id"
-		@bucket = "user_files"
-		@key = "#{@project_id}/#{@file_id}"
-		@req =
-			key:@key
-			bucket:@bucket
-			query:{}
-			params:
-				project_id:@project_id
-				file_id:@file_id
+		};
+		this.LocalFileWriter = {};
+		this.controller = SandboxedModule.require(modulePath, { requires: {
+			"./LocalFileWriter":this.LocalFileWriter,
+			"./FileHandler": this.FileHandler,
+			"./PersistorManager":this.PersistorManager,
+			"./Errors": (this.Errors =
+				{NotFoundError: sinon.stub()}),
+			"settings-sharelatex": this.settings,
+			"metrics-sharelatex": { 
+				inc() {}
+			},
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			}
+		}
+	}
+		);
+		this.project_id = "project_id";
+		this.file_id = "file_id";
+		this.bucket = "user_files";
+		this.key = `${this.project_id}/${this.file_id}`;
+		this.req = {
+			key:this.key,
+			bucket:this.bucket,
+			query:{},
+			params: {
+				project_id:this.project_id,
+				file_id:this.file_id
+			},
 			headers: {}
-		@res =
-			set: sinon.stub().returnsThis()
+		};
+		this.res = {
+			set: sinon.stub().returnsThis(),
 			status: sinon.stub().returnsThis()
-		@fileStream = {}
-
-	describe "getFile", ->
-
-		it "should pipe the stream", (done)->
-			@FileHandler.getFile.callsArgWith(3, null, @fileStream)
-			@fileStream.pipe = (res)=>
-				res.should.equal @res
-				done()
-			@controller.getFile @req, @res
-
-		it "should send a 200 if the cacheWarm param is true", (done)->
-			@req.query.cacheWarm = true
-			@FileHandler.getFile.callsArgWith(3, null, @fileStream)
-			@res.send = (statusCode)=>
-				statusCode.should.equal 200
-				done()
-			@controller.getFile @req, @res
-
-		it "should send a 500 if there is a problem", (done)->
-			@FileHandler.getFile.callsArgWith(3, "error")
-			@res.send = (code)=>
-				code.should.equal 500
-				done()
-			@controller.getFile @req, @res
-
-		describe "with a 'Range' header set", ->
-
-			beforeEach ->
-				@req.headers.range = 'bytes=0-8'
-
-			it "should pass 'start' and 'end' options to FileHandler", (done) ->
-				@FileHandler.getFile.callsArgWith(3, null, @fileStream)
-				@fileStream.pipe = (res)=>
-					expect(@FileHandler.getFile.lastCall.args[2].start).to.equal 0
-					expect(@FileHandler.getFile.lastCall.args[2].end).to.equal 8
-					done()
-				@controller.getFile @req, @res
-
-	describe "getFileHead", ->
-		it "should return the file size in a Content-Length header", (done) ->
-			expectedFileSize = 84921
-			@FileHandler.getFileSize.yields(
+		};
+		return this.fileStream = {};});
+
+	describe("getFile", function() {
+
+		it("should pipe the stream", function(done){
+			this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
+			this.fileStream.pipe = res=> {
+				res.should.equal(this.res);
+				return done();
+			};
+			return this.controller.getFile(this.req, this.res);
+		});
+
+		it("should send a 200 if the cacheWarm param is true", function(done){
+			this.req.query.cacheWarm = true;
+			this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
+			this.res.send = statusCode=> {
+				statusCode.should.equal(200);
+				return done();
+			};
+			return this.controller.getFile(this.req, this.res);
+		});
+
+		it("should send a 500 if there is a problem", function(done){
+			this.FileHandler.getFile.callsArgWith(3, "error");
+			this.res.send = code=> {
+				code.should.equal(500);
+				return done();
+			};
+			return this.controller.getFile(this.req, this.res);
+		});
+
+		return describe("with a 'Range' header set", function() {
+
+			beforeEach(function() {
+				return this.req.headers.range = 'bytes=0-8';
+			});
+
+			return it("should pass 'start' and 'end' options to FileHandler", function(done) {
+				this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
+				this.fileStream.pipe = res=> {
+					expect(this.FileHandler.getFile.lastCall.args[2].start).to.equal(0);
+					expect(this.FileHandler.getFile.lastCall.args[2].end).to.equal(8);
+					return done();
+				};
+				return this.controller.getFile(this.req, this.res);
+			});
+		});
+	});
+
+	describe("getFileHead", function() {
+		it("should return the file size in a Content-Length header", function(done) {
+			const expectedFileSize = 84921;
+			this.FileHandler.getFileSize.yields(
 				new Error("FileHandler.getFileSize: unexpected arguments")
-			)
-			@FileHandler.getFileSize.withArgs(@bucket, @key).yields(null, expectedFileSize)
-
-			@res.end = () =>
-				expect(@res.status.lastCall.args[0]).to.equal(200)
-				expect(@res.set.calledWith("Content-Length", expectedFileSize)).to.equal(true)
-				done()
-
-			@controller.getFileHead(@req, @res)
-
-		it "should return a 404 is the file is not found", (done) ->
-			@FileHandler.getFileSize.yields(new @Errors.NotFoundError())
-
-			@res.end = () =>
-				expect(@res.status.lastCall.args[0]).to.equal(404)
-				done()
-
-			@controller.getFileHead(@req, @res)
-
-		it "should return a 500 on internal errors", (done) ->
-			@FileHandler.getFileSize.yields(new Error())
-
-			@res.end = () =>
-				expect(@res.status.lastCall.args[0]).to.equal(500)
-				done()
-
-			@controller.getFileHead(@req, @res)
-
-	describe "insertFile", ->
-
-		it "should send bucket name key and res to PersistorManager", (done)->
-			@FileHandler.insertFile.callsArgWith(3)
-			@res.send = =>
-				@FileHandler.insertFile.calledWith(@bucket, @key, @req).should.equal true
-				done()
-			@controller.insertFile @req, @res
-
-	describe "copyFile", ->
-		beforeEach ->
-			@oldFile_id = "old_file_id"
-			@oldProject_id = "old_project_id"
-			@req.body =
-				source:
-					project_id: @oldProject_id
-					file_id: @oldFile_id
-
-		it "should send bucket name and both keys to PersistorManager", (done)->
-			@PersistorManager.copyFile.callsArgWith(3)
-			@res.send = (code)=>
-				code.should.equal 200
-				@PersistorManager.copyFile.calledWith(@bucket, "#{@oldProject_id}/#{@oldFile_id}", @key).should.equal true
-				done()
-			@controller.copyFile @req, @res
-
-		it "should send a 404 if the original file was not found", (done) ->
-			@PersistorManager.copyFile.callsArgWith(3, new @Errors.NotFoundError())
-			@res.send = (code)=>
-				code.should.equal 404
-				done()
-			@controller.copyFile @req, @res
-
-		it "should send a 500 if there was an error", (done)->
-			@PersistorManager.copyFile.callsArgWith(3, "error")
-			@res.send = (code)=>
-				code.should.equal 500
-				done()
-			@controller.copyFile @req, @res
-
-	describe "delete file", ->
-
-		it "should tell the file handler", (done)->
-			@FileHandler.deleteFile.callsArgWith(2)
-			@res.send = (code)=>
-				code.should.equal 204
-				@FileHandler.deleteFile.calledWith(@bucket, @key).should.equal true
-				done()
-			@controller.deleteFile @req, @res
-
-		it "should send a 500 if there was an error", (done)->
-			@FileHandler.deleteFile.callsArgWith(2, "error")
-			@res.send = (code)->
-				code.should.equal 500
-				done()
-			@controller.deleteFile @req, @res
-
-	describe "_get_range", ->
-
-		it "should parse a valid Range header", (done) ->
-			result = @controller._get_range('bytes=0-200')
-			expect(result).to.not.equal null
-			expect(result.start).to.equal 0
-			expect(result.end).to.equal 200
-			done()
-
-		it "should return null for an invalid Range header", (done) ->
-			result = @controller._get_range('wat')
-			expect(result).to.equal null
-			done()
-
-		it "should return null for any type other than 'bytes'", (done) ->
-			result = @controller._get_range('carrots=0-200')
-			expect(result).to.equal null
-			done()
-
-	describe "directorySize", ->
-
-		it "should return total directory size bytes", (done) ->
-			@FileHandler.getDirectorySize.callsArgWith(2, null, 1024)
-			@controller.directorySize @req, json:(result)=>
-				expect(result['total bytes']).to.equal 1024
-				done()
-
-		it "should send a 500 if there was an error", (done)->
-			@FileHandler.getDirectorySize.callsArgWith(2, "error")
-			@res.send = (code)->
-				code.should.equal 500
-				done()
-			@controller.directorySize @req, @res
+			);
+			this.FileHandler.getFileSize.withArgs(this.bucket, this.key).yields(null, expectedFileSize);
+
+			this.res.end = () => {
+				expect(this.res.status.lastCall.args[0]).to.equal(200);
+				expect(this.res.set.calledWith("Content-Length", expectedFileSize)).to.equal(true);
+				return done();
+			};
+
+			return this.controller.getFileHead(this.req, this.res);
+		});
+
+		it("should return a 404 is the file is not found", function(done) {
+			this.FileHandler.getFileSize.yields(new this.Errors.NotFoundError());
+
+			this.res.end = () => {
+				expect(this.res.status.lastCall.args[0]).to.equal(404);
+				return done();
+			};
+
+			return this.controller.getFileHead(this.req, this.res);
+		});
+
+		return it("should return a 500 on internal errors", function(done) {
+			this.FileHandler.getFileSize.yields(new Error());
+
+			this.res.end = () => {
+				expect(this.res.status.lastCall.args[0]).to.equal(500);
+				return done();
+			};
+
+			return this.controller.getFileHead(this.req, this.res);
+		});
+	});
+
+	describe("insertFile", () => it("should send bucket name key and res to PersistorManager", function(done){
+        this.FileHandler.insertFile.callsArgWith(3);
+        this.res.send = () => {
+            this.FileHandler.insertFile.calledWith(this.bucket, this.key, this.req).should.equal(true);
+            return done();
+        };
+        return this.controller.insertFile(this.req, this.res);
+    }));
+
+	describe("copyFile", function() {
+		beforeEach(function() {
+			this.oldFile_id = "old_file_id";
+			this.oldProject_id = "old_project_id";
+			return this.req.body = {
+				source: {
+					project_id: this.oldProject_id,
+					file_id: this.oldFile_id
+				}
+			};
+		});
+
+		it("should send bucket name and both keys to PersistorManager", function(done){
+			this.PersistorManager.copyFile.callsArgWith(3);
+			this.res.send = code=> {
+				code.should.equal(200);
+				this.PersistorManager.copyFile.calledWith(this.bucket, `${this.oldProject_id}/${this.oldFile_id}`, this.key).should.equal(true);
+				return done();
+			};
+			return this.controller.copyFile(this.req, this.res);
+		});
+
+		it("should send a 404 if the original file was not found", function(done) {
+			this.PersistorManager.copyFile.callsArgWith(3, new this.Errors.NotFoundError());
+			this.res.send = code=> {
+				code.should.equal(404);
+				return done();
+			};
+			return this.controller.copyFile(this.req, this.res);
+		});
+
+		return it("should send a 500 if there was an error", function(done){
+			this.PersistorManager.copyFile.callsArgWith(3, "error");
+			this.res.send = code=> {
+				code.should.equal(500);
+				return done();
+			};
+			return this.controller.copyFile(this.req, this.res);
+		});
+	});
+
+	describe("delete file", function() {
+
+		it("should tell the file handler", function(done){
+			this.FileHandler.deleteFile.callsArgWith(2);
+			this.res.send = code=> {
+				code.should.equal(204);
+				this.FileHandler.deleteFile.calledWith(this.bucket, this.key).should.equal(true);
+				return done();
+			};
+			return this.controller.deleteFile(this.req, this.res);
+		});
+
+		return it("should send a 500 if there was an error", function(done){
+			this.FileHandler.deleteFile.callsArgWith(2, "error");
+			this.res.send = function(code){
+				code.should.equal(500);
+				return done();
+			};
+			return this.controller.deleteFile(this.req, this.res);
+		});
+	});
+
+	describe("_get_range", function() {
+
+		it("should parse a valid Range header", function(done) {
+			const result = this.controller._get_range('bytes=0-200');
+			expect(result).to.not.equal(null);
+			expect(result.start).to.equal(0);
+			expect(result.end).to.equal(200);
+			return done();
+		});
+
+		it("should return null for an invalid Range header", function(done) {
+			const result = this.controller._get_range('wat');
+			expect(result).to.equal(null);
+			return done();
+		});
+
+		return it("should return null for any type other than 'bytes'", function(done) {
+			const result = this.controller._get_range('carrots=0-200');
+			expect(result).to.equal(null);
+			return done();
+		});
+	});
+
+	return describe("directorySize", function() {
+
+		it("should return total directory size bytes", function(done) {
+			this.FileHandler.getDirectorySize.callsArgWith(2, null, 1024);
+			return this.controller.directorySize(this.req, { json:result=> {
+				expect(result['total bytes']).to.equal(1024);
+				return done();
+			}
+		}
+			);
+		});
+
+		return it("should send a 500 if there was an error", function(done){
+			this.FileHandler.getDirectorySize.callsArgWith(2, "error");
+			this.res.send = function(code){
+				code.should.equal(500);
+				return done();
+			};
+			return this.controller.directorySize(this.req, this.res);
+		});
+	});
+});

+ 99 - 68
services/filestore/test/unit/coffee/FileConverterTests.js

@@ -1,81 +1,112 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/FileConverter.js"
-SandboxedModule = require('sandboxed-module')
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/FileConverter.js";
+const SandboxedModule = require('sandboxed-module');
 
-describe "FileConverter", ->
+describe("FileConverter", function() {
 
-	beforeEach ->
+	beforeEach(function() {
 
-		@safe_exec = sinon.stub()
-		@converter = SandboxedModule.require modulePath, requires:
-			"./SafeExec": @safe_exec
-			"logger-sharelatex":
-				log:->
-				err:->
-			"metrics-sharelatex": 
-				inc:->
-				Timer:->
-					done:->
-			"settings-sharelatex": @Settings =
-				commands:
+		this.safe_exec = sinon.stub();
+		this.converter = SandboxedModule.require(modulePath, { requires: {
+			"./SafeExec": this.safe_exec,
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			},
+			"metrics-sharelatex": { 
+				inc() {},
+				Timer() {
+					return {done() {}};
+				}
+			},
+			"settings-sharelatex": (this.Settings = {
+				commands: {
 					convertCommandPrefix: []
+				}
+			})
+		}
+	});
 
-		@sourcePath = "/this/path/here.eps"
-		@format = "png"
-		@error = "Error"
+		this.sourcePath = "/this/path/here.eps";
+		this.format = "png";
+		return this.error = "Error";
+	});
 
-	describe "convert", ->
+	describe("convert", function() {
 
-		it "should convert the source to the requested format", (done)->
-			@safe_exec.callsArgWith(2)
-			@converter.convert @sourcePath, @format, (err)=>
-				args = @safe_exec.args[0][0]
-				args.indexOf("#{@sourcePath}[0]").should.not.equal -1 
-				args.indexOf("#{@sourcePath}.#{@format}").should.not.equal -1 
-				done()
+		it("should convert the source to the requested format", function(done){
+			this.safe_exec.callsArgWith(2);
+			return this.converter.convert(this.sourcePath, this.format, err=> {
+				const args = this.safe_exec.args[0][0];
+				args.indexOf(`${this.sourcePath}[0]`).should.not.equal(-1); 
+				args.indexOf(`${this.sourcePath}.${this.format}`).should.not.equal(-1); 
+				return done();
+			});
+		});
 
-		it "should return the dest path", (done)->
-			@safe_exec.callsArgWith(2)
-			@converter.convert @sourcePath, @format, (err, destPath)=>
-				destPath.should.equal "#{@sourcePath}.#{@format}"
-				done()
+		it("should return the dest path", function(done){
+			this.safe_exec.callsArgWith(2);
+			return this.converter.convert(this.sourcePath, this.format, (err, destPath)=> {
+				destPath.should.equal(`${this.sourcePath}.${this.format}`);
+				return done();
+			});
+		});
 
-		it "should return the error from convert", (done)->
-			@safe_exec.callsArgWith(2, @error)
-			@converter.convert @sourcePath, @format, (err)=>
-				err.should.equal @error
-				done()
+		it("should return the error from convert", function(done){
+			this.safe_exec.callsArgWith(2, this.error);
+			return this.converter.convert(this.sourcePath, this.format, err=> {
+				err.should.equal(this.error);
+				return done();
+			});
+		});
 
-		it "should not accapt an non aproved format", (done)->
-			@safe_exec.callsArgWith(2)
-			@converter.convert @sourcePath, "ahhhhh", (err)=>
-				expect(err).to.exist
-				done()
+		it("should not accapt an non aproved format", function(done){
+			this.safe_exec.callsArgWith(2);
+			return this.converter.convert(this.sourcePath, "ahhhhh", err=> {
+				expect(err).to.exist;
+				return done();
+			});
+		});
 		
-		it "should prefix the command with Settings.commands.convertCommandPrefix", (done) ->
-			@safe_exec.callsArgWith(2)
-			@Settings.commands.convertCommandPrefix = ["nice"]
-			@converter.convert @sourcePath, @format, (err)=>
-				command = @safe_exec.args[0][0]
-				command[0].should.equal "nice"
-				done()
+		return it("should prefix the command with Settings.commands.convertCommandPrefix", function(done) {
+			this.safe_exec.callsArgWith(2);
+			this.Settings.commands.convertCommandPrefix = ["nice"];
+			return this.converter.convert(this.sourcePath, this.format, err=> {
+				const command = this.safe_exec.args[0][0];
+				command[0].should.equal("nice");
+				return done();
+			});
+		});
+	});
 
-	describe "thumbnail", ->
-		it "should call converter resize with args", (done)->
-			@safe_exec.callsArgWith(2)
-			@converter.thumbnail @sourcePath, (err)=>
-				args = @safe_exec.args[0][0]
-				args.indexOf("#{@sourcePath}[0]").should.not.equal -1 
-				done()
+	describe("thumbnail", () => it("should call converter resize with args", function(done){
+        this.safe_exec.callsArgWith(2);
+        return this.converter.thumbnail(this.sourcePath, err=> {
+            const args = this.safe_exec.args[0][0];
+            args.indexOf(`${this.sourcePath}[0]`).should.not.equal(-1); 
+            return done();
+        });
+    }));
 
-	describe "preview", ->
-		it "should call converter resize with args", (done)->
-			@safe_exec.callsArgWith(2)
-			@converter.preview @sourcePath, (err)=>
-				args = @safe_exec.args[0][0]
-				args.indexOf("#{@sourcePath}[0]").should.not.equal -1 
-				done()
+	return describe("preview", () => it("should call converter resize with args", function(done){
+        this.safe_exec.callsArgWith(2);
+        return this.converter.preview(this.sourcePath, err=> {
+            const args = this.safe_exec.args[0][0];
+            args.indexOf(`${this.sourcePath}[0]`).should.not.equal(-1); 
+            return done();
+        });
+    }));
+});

+ 269 - 202
services/filestore/test/unit/coffee/FileHandlerTests.js

@@ -1,208 +1,275 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/FileHandler.js"
-SandboxedModule = require('sandboxed-module')
-
-describe "FileHandler", ->
-
-	beforeEach ->
-		@settings =
-			s3:
-				buckets:
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/FileHandler.js";
+const SandboxedModule = require('sandboxed-module');
+
+describe("FileHandler", function() {
+
+	beforeEach(function() {
+		this.settings = {
+			s3: {
+				buckets: {
 					user_files:"user_files"
-		@PersistorManager =
-			getFileStream: sinon.stub()
-			checkIfFileExists: sinon.stub()
-			deleteFile: sinon.stub()
-			deleteDirectory: sinon.stub()
-			sendStream: sinon.stub()
-			insertFile: sinon.stub()
+				}
+			}
+		};
+		this.PersistorManager = {
+			getFileStream: sinon.stub(),
+			checkIfFileExists: sinon.stub(),
+			deleteFile: sinon.stub(),
+			deleteDirectory: sinon.stub(),
+			sendStream: sinon.stub(),
+			insertFile: sinon.stub(),
 			directorySize: sinon.stub()
-		@LocalFileWriter =
-			writeStream: sinon.stub()
-			getStream: sinon.stub()
+		};
+		this.LocalFileWriter = {
+			writeStream: sinon.stub(),
+			getStream: sinon.stub(),
 			deleteFile: sinon.stub()
-		@FileConverter =
-			convert: sinon.stub()
-			thumbnail: sinon.stub()
+		};
+		this.FileConverter = {
+			convert: sinon.stub(),
+			thumbnail: sinon.stub(),
 			preview: sinon.stub()
-		@keyBuilder =
-			addCachingToKey: sinon.stub()
+		};
+		this.keyBuilder = {
+			addCachingToKey: sinon.stub(),
 			getConvertedFolderKey: sinon.stub()
-		@ImageOptimiser =
-			compressPng: sinon.stub()
-		@handler = SandboxedModule.require modulePath, requires:
-			"settings-sharelatex": @settings
-			"./PersistorManager":@PersistorManager
-			"./LocalFileWriter":@LocalFileWriter
-			"./FileConverter":@FileConverter
-			"./KeyBuilder": @keyBuilder
-			"./ImageOptimiser":@ImageOptimiser
-			"logger-sharelatex":
-				log:->
-				err:->
-		@bucket = "my_bucket"
-		@key = "key/here"
-		@stubbedPath = "/var/somewhere/path"
-		@format = "png"
-		@formattedStubbedPath = "#{@stubbedPath}.#{@format}"
-
-	describe "insertFile", ->
-		beforeEach ->
-			@stream = {}
-			@PersistorManager.deleteDirectory.callsArgWith(2)
-			@PersistorManager.sendStream.callsArgWith(3)
-
-		it "should send file to the filestore", (done)->
-			@handler.insertFile @bucket, @key, @stream, =>
-				@PersistorManager.sendStream.calledWith(@bucket, @key, @stream).should.equal true
-				done()
-
-		it "should delete the convetedKey folder", (done)->
-			@keyBuilder.getConvertedFolderKey.returns(@stubbedConvetedKey)
-			@handler.insertFile @bucket, @key, @stream, =>
-				@PersistorManager.deleteDirectory.calledWith(@bucket, @stubbedConvetedKey).should.equal true
-				done()
-
-	describe "deleteFile", ->
-		beforeEach ->
-			@keyBuilder.getConvertedFolderKey.returns(@stubbedConvetedKey)
-			@PersistorManager.deleteFile.callsArgWith(2)
-			@PersistorManager.deleteDirectory.callsArgWith(2)
-
-		it "should tell the filestore manager to delete the file", (done)->
-			@handler.deleteFile @bucket, @key, =>
-				@PersistorManager.deleteFile.calledWith(@bucket, @key).should.equal true
-				done()
-
-		it "should tell the filestore manager to delete the cached foler", (done)->
-			@handler.deleteFile @bucket, @key, =>
-				@PersistorManager.deleteDirectory.calledWith(@bucket, @stubbedConvetedKey).should.equal true
-				done()
-
-	describe "getFile", ->
-		beforeEach ->
-			@handler._getStandardFile = sinon.stub().callsArgWith(3)
-			@handler._getConvertedFile = sinon.stub().callsArgWith(3)
-
-		it "should call _getStandardFile if no format or style are defined", (done)->
-
-			@handler.getFile @bucket, @key, null, =>
-				@handler._getStandardFile.called.should.equal true
-				@handler._getConvertedFile.called.should.equal false
-				done()
-
-		it "should pass options to _getStandardFile", (done) ->
-			options = {start: 0, end: 8}
-			@handler.getFile @bucket, @key, options, =>
-				expect(@handler._getStandardFile.lastCall.args[2].start).to.equal 0
-				expect(@handler._getStandardFile.lastCall.args[2].end).to.equal 8
-				done()
-
-		it "should call _getConvertedFile if a format is defined", (done)->
-			@handler.getFile @bucket, @key, format:"png", =>
-				@handler._getStandardFile.called.should.equal false
-				@handler._getConvertedFile.called.should.equal true
-				done()
-
-	describe "_getStandardFile", ->
-
-		beforeEach ->
-			@fileStream = {on:->}
-			@PersistorManager.getFileStream.callsArgWith(3, "err", @fileStream)
-
-		it "should get the stream", (done)->
-			@handler.getFile @bucket, @key, null, =>
-				@PersistorManager.getFileStream.calledWith(@bucket, @key).should.equal true
-				done()
-
-		it "should return the stream and error", (done)->
-			@handler.getFile @bucket, @key, null, (err, stream)=>
-				err.should.equal "err"
-				stream.should.equal @fileStream
-				done()
-
-		it "should pass options to PersistorManager", (done) ->
-			@handler.getFile @bucket, @key, {start: 0, end: 8}, =>
-				expect(@PersistorManager.getFileStream.lastCall.args[2].start).to.equal 0
-				expect(@PersistorManager.getFileStream.lastCall.args[2].end).to.equal 8
-				done()
-
-
-	describe "_getConvertedFile", ->
-
-		it "should getFileStream if it does exists", (done)->
-			@PersistorManager.checkIfFileExists.callsArgWith(2, null, true)
-			@PersistorManager.getFileStream.callsArgWith(3)
-			@handler._getConvertedFile @bucket, @key, {}, =>
-				@PersistorManager.getFileStream.calledWith(@bucket).should.equal true
-				done()
-
-		it "should call _getConvertedFileAndCache if it does exists", (done)->
-			@PersistorManager.checkIfFileExists.callsArgWith(2, null, false)
-			@handler._getConvertedFileAndCache = sinon.stub().callsArgWith(4)
-			@handler._getConvertedFile @bucket, @key, {}, =>
-				@handler._getConvertedFileAndCache.calledWith(@bucket, @key).should.equal true
-				done()
-
-	describe "_getConvertedFileAndCache", ->
-
-		it "should _convertFile ", (done)->
-			@stubbedStream = {"something":"here"}
-			@localStream = {
-				on: ->
+		};
+		this.ImageOptimiser =
+			{compressPng: sinon.stub()};
+		this.handler = SandboxedModule.require(modulePath, { requires: {
+			"settings-sharelatex": this.settings,
+			"./PersistorManager":this.PersistorManager,
+			"./LocalFileWriter":this.LocalFileWriter,
+			"./FileConverter":this.FileConverter,
+			"./KeyBuilder": this.keyBuilder,
+			"./ImageOptimiser":this.ImageOptimiser,
+			"logger-sharelatex": {
+				log() {},
+				err() {}
 			}
-			@PersistorManager.sendFile = sinon.stub().callsArgWith(3)
-			@LocalFileWriter.getStream = sinon.stub().callsArgWith(1, null, @localStream)
-			@convetedKey = @key+"converted"
-			@handler._convertFile = sinon.stub().callsArgWith(3, null, @stubbedPath)
-			@ImageOptimiser.compressPng = sinon.stub().callsArgWith(1)
-			@handler._getConvertedFileAndCache @bucket, @key, @convetedKey, {}, (err, fsStream)=>
-				@handler._convertFile.called.should.equal true
-				@PersistorManager.sendFile.calledWith(@bucket, @convetedKey, @stubbedPath).should.equal true
-				@ImageOptimiser.compressPng.calledWith(@stubbedPath).should.equal true
-				@LocalFileWriter.getStream.calledWith(@stubbedPath).should.equal true
-				fsStream.should.equal @localStream
-				done()
-
-	describe "_convertFile", ->
-		beforeEach ->
-			@FileConverter.convert.callsArgWith(2, null, @formattedStubbedPath)
-			@FileConverter.thumbnail.callsArgWith(1, null, @formattedStubbedPath)
-			@FileConverter.preview.callsArgWith(1, null, @formattedStubbedPath)
-			@handler._writeS3FileToDisk = sinon.stub().callsArgWith(3, null, @stubbedPath)
-			@LocalFileWriter.deleteFile.callsArgWith(1)
-
-		it "should call thumbnail on the writer path if style was thumbnail was specified", (done)->
-			@handler._convertFile @bucket, @key, style:"thumbnail", (err, path)=>
-				path.should.equal @formattedStubbedPath
-				@FileConverter.thumbnail.calledWith(@stubbedPath).should.equal true
-				@LocalFileWriter.deleteFile.calledWith(@stubbedPath).should.equal true
-				done()
-
-		it "should call preview on the writer path if style was preview was specified", (done)->
-			@handler._convertFile @bucket, @key, style:"preview", (err, path)=>
-				path.should.equal @formattedStubbedPath
-				@FileConverter.preview.calledWith(@stubbedPath).should.equal true
-				@LocalFileWriter.deleteFile.calledWith(@stubbedPath).should.equal true
-				done()
-
-		it "should call convert on the writer path if a format was specified", (done)->
-			@handler._convertFile @bucket, @key, format:@format, (err, path)=>
-				path.should.equal @formattedStubbedPath
-				@FileConverter.convert.calledWith(@stubbedPath, @format).should.equal true
-				@LocalFileWriter.deleteFile.calledWith(@stubbedPath).should.equal true
-				done()
-
-	describe "getDirectorySize", ->
-
-		beforeEach ->
-			@PersistorManager.directorySize.callsArgWith(2)
-
-		it "should call the filestore manager to get directory size", (done)->
-			@handler.getDirectorySize @bucket, @key, =>
-				@PersistorManager.directorySize.calledWith(@bucket, @key).should.equal true
-				done()
+		}
+	}
+		);
+		this.bucket = "my_bucket";
+		this.key = "key/here";
+		this.stubbedPath = "/var/somewhere/path";
+		this.format = "png";
+		return this.formattedStubbedPath = `${this.stubbedPath}.${this.format}`;
+	});
+
+	describe("insertFile", function() {
+		beforeEach(function() {
+			this.stream = {};
+			this.PersistorManager.deleteDirectory.callsArgWith(2);
+			return this.PersistorManager.sendStream.callsArgWith(3);
+		});
+
+		it("should send file to the filestore", function(done){
+			return this.handler.insertFile(this.bucket, this.key, this.stream, () => {
+				this.PersistorManager.sendStream.calledWith(this.bucket, this.key, this.stream).should.equal(true);
+				return done();
+			});
+		});
+
+		return it("should delete the convetedKey folder", function(done){
+			this.keyBuilder.getConvertedFolderKey.returns(this.stubbedConvetedKey);
+			return this.handler.insertFile(this.bucket, this.key, this.stream, () => {
+				this.PersistorManager.deleteDirectory.calledWith(this.bucket, this.stubbedConvetedKey).should.equal(true);
+				return done();
+			});
+		});
+	});
+
+	describe("deleteFile", function() {
+		beforeEach(function() {
+			this.keyBuilder.getConvertedFolderKey.returns(this.stubbedConvetedKey);
+			this.PersistorManager.deleteFile.callsArgWith(2);
+			return this.PersistorManager.deleteDirectory.callsArgWith(2);
+		});
+
+		it("should tell the filestore manager to delete the file", function(done){
+			return this.handler.deleteFile(this.bucket, this.key, () => {
+				this.PersistorManager.deleteFile.calledWith(this.bucket, this.key).should.equal(true);
+				return done();
+			});
+		});
+
+		return it("should tell the filestore manager to delete the cached foler", function(done){
+			return this.handler.deleteFile(this.bucket, this.key, () => {
+				this.PersistorManager.deleteDirectory.calledWith(this.bucket, this.stubbedConvetedKey).should.equal(true);
+				return done();
+			});
+		});
+	});
+
+	describe("getFile", function() {
+		beforeEach(function() {
+			this.handler._getStandardFile = sinon.stub().callsArgWith(3);
+			return this.handler._getConvertedFile = sinon.stub().callsArgWith(3);
+		});
+
+		it("should call _getStandardFile if no format or style are defined", function(done){
+
+			return this.handler.getFile(this.bucket, this.key, null, () => {
+				this.handler._getStandardFile.called.should.equal(true);
+				this.handler._getConvertedFile.called.should.equal(false);
+				return done();
+			});
+		});
+
+		it("should pass options to _getStandardFile", function(done) {
+			const options = {start: 0, end: 8};
+			return this.handler.getFile(this.bucket, this.key, options, () => {
+				expect(this.handler._getStandardFile.lastCall.args[2].start).to.equal(0);
+				expect(this.handler._getStandardFile.lastCall.args[2].end).to.equal(8);
+				return done();
+			});
+		});
+
+		return it("should call _getConvertedFile if a format is defined", function(done){
+			return this.handler.getFile(this.bucket, this.key, {format:"png"}, () => {
+				this.handler._getStandardFile.called.should.equal(false);
+				this.handler._getConvertedFile.called.should.equal(true);
+				return done();
+			});
+		});
+	});
+
+	describe("_getStandardFile", function() {
+
+		beforeEach(function() {
+			this.fileStream = {on() {}};
+			return this.PersistorManager.getFileStream.callsArgWith(3, "err", this.fileStream);
+		});
+
+		it("should get the stream", function(done){
+			return this.handler.getFile(this.bucket, this.key, null, () => {
+				this.PersistorManager.getFileStream.calledWith(this.bucket, this.key).should.equal(true);
+				return done();
+			});
+		});
+
+		it("should return the stream and error", function(done){
+			return this.handler.getFile(this.bucket, this.key, null, (err, stream)=> {
+				err.should.equal("err");
+				stream.should.equal(this.fileStream);
+				return done();
+			});
+		});
+
+		return it("should pass options to PersistorManager", function(done) {
+			return this.handler.getFile(this.bucket, this.key, {start: 0, end: 8}, () => {
+				expect(this.PersistorManager.getFileStream.lastCall.args[2].start).to.equal(0);
+				expect(this.PersistorManager.getFileStream.lastCall.args[2].end).to.equal(8);
+				return done();
+			});
+		});
+	});
+
+
+	describe("_getConvertedFile", function() {
+
+		it("should getFileStream if it does exists", function(done){
+			this.PersistorManager.checkIfFileExists.callsArgWith(2, null, true);
+			this.PersistorManager.getFileStream.callsArgWith(3);
+			return this.handler._getConvertedFile(this.bucket, this.key, {}, () => {
+				this.PersistorManager.getFileStream.calledWith(this.bucket).should.equal(true);
+				return done();
+			});
+		});
+
+		return it("should call _getConvertedFileAndCache if it does exists", function(done){
+			this.PersistorManager.checkIfFileExists.callsArgWith(2, null, false);
+			this.handler._getConvertedFileAndCache = sinon.stub().callsArgWith(4);
+			return this.handler._getConvertedFile(this.bucket, this.key, {}, () => {
+				this.handler._getConvertedFileAndCache.calledWith(this.bucket, this.key).should.equal(true);
+				return done();
+			});
+		});
+	});
+
+	describe("_getConvertedFileAndCache", () => it("should _convertFile ", function(done){
+        this.stubbedStream = {"something":"here"};
+        this.localStream = {
+            on() {}
+        };
+        this.PersistorManager.sendFile = sinon.stub().callsArgWith(3);
+        this.LocalFileWriter.getStream = sinon.stub().callsArgWith(1, null, this.localStream);
+        this.convetedKey = this.key+"converted";
+        this.handler._convertFile = sinon.stub().callsArgWith(3, null, this.stubbedPath);
+        this.ImageOptimiser.compressPng = sinon.stub().callsArgWith(1);
+        return this.handler._getConvertedFileAndCache(this.bucket, this.key, this.convetedKey, {}, (err, fsStream)=> {
+            this.handler._convertFile.called.should.equal(true);
+            this.PersistorManager.sendFile.calledWith(this.bucket, this.convetedKey, this.stubbedPath).should.equal(true);
+            this.ImageOptimiser.compressPng.calledWith(this.stubbedPath).should.equal(true);
+            this.LocalFileWriter.getStream.calledWith(this.stubbedPath).should.equal(true);
+            fsStream.should.equal(this.localStream);
+            return done();
+        });
+    }));
+
+	describe("_convertFile", function() {
+		beforeEach(function() {
+			this.FileConverter.convert.callsArgWith(2, null, this.formattedStubbedPath);
+			this.FileConverter.thumbnail.callsArgWith(1, null, this.formattedStubbedPath);
+			this.FileConverter.preview.callsArgWith(1, null, this.formattedStubbedPath);
+			this.handler._writeS3FileToDisk = sinon.stub().callsArgWith(3, null, this.stubbedPath);
+			return this.LocalFileWriter.deleteFile.callsArgWith(1);
+		});
+
+		it("should call thumbnail on the writer path if style was thumbnail was specified", function(done){
+			return this.handler._convertFile(this.bucket, this.key, {style:"thumbnail"}, (err, path)=> {
+				path.should.equal(this.formattedStubbedPath);
+				this.FileConverter.thumbnail.calledWith(this.stubbedPath).should.equal(true);
+				this.LocalFileWriter.deleteFile.calledWith(this.stubbedPath).should.equal(true);
+				return done();
+			});
+		});
+
+		it("should call preview on the writer path if style was preview was specified", function(done){
+			return this.handler._convertFile(this.bucket, this.key, {style:"preview"}, (err, path)=> {
+				path.should.equal(this.formattedStubbedPath);
+				this.FileConverter.preview.calledWith(this.stubbedPath).should.equal(true);
+				this.LocalFileWriter.deleteFile.calledWith(this.stubbedPath).should.equal(true);
+				return done();
+			});
+		});
+
+		return it("should call convert on the writer path if a format was specified", function(done){
+			return this.handler._convertFile(this.bucket, this.key, {format:this.format}, (err, path)=> {
+				path.should.equal(this.formattedStubbedPath);
+				this.FileConverter.convert.calledWith(this.stubbedPath, this.format).should.equal(true);
+				this.LocalFileWriter.deleteFile.calledWith(this.stubbedPath).should.equal(true);
+				return done();
+			});
+		});
+	});
+
+	return describe("getDirectorySize", function() {
+
+		beforeEach(function() {
+			return this.PersistorManager.directorySize.callsArgWith(2);
+		});
+
+		return it("should call the filestore manager to get directory size", function(done){
+			return this.handler.getDirectorySize(this.bucket, this.key, () => {
+				this.PersistorManager.directorySize.calledWith(this.bucket, this.key).should.equal(true);
+				return done();
+			});
+		});
+	});
+});

+ 72 - 52
services/filestore/test/unit/coffee/ImageOptimiserTests.js

@@ -1,64 +1,84 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/ImageOptimiser.js"
-SandboxedModule = require('sandboxed-module')
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/ImageOptimiser.js";
+const SandboxedModule = require('sandboxed-module');
 
-describe "ImageOptimiser", ->
+describe("ImageOptimiser", function() {
 
-	beforeEach ->
-		@child_process =
-			exec : sinon.stub()
-		@settings = 
-			enableConversions:true
-		@optimiser = SandboxedModule.require modulePath, requires:
-			'child_process': @child_process
-			"logger-sharelatex":
-				log:->
-				err:->
-				warn:->
-			"settings-sharelatex": @settings
+	beforeEach(function() {
+		this.child_process =
+			{exec : sinon.stub()};
+		this.settings = 
+			{enableConversions:true};
+		this.optimiser = SandboxedModule.require(modulePath, { requires: {
+			'child_process': this.child_process,
+			"logger-sharelatex": {
+				log() {},
+				err() {},
+				warn() {}
+			},
+			"settings-sharelatex": this.settings
+		}
+	}
+		);
 				
 
-		@sourcePath = "/this/path/here.eps"
-		@error = "Error"
+		this.sourcePath = "/this/path/here.eps";
+		return this.error = "Error";
+	});
 
-	describe "compressPng", ->
+	describe("compressPng", function() {
 		
 
-		it "convert the file", (done)->
-			@child_process.exec.callsArgWith(2)
-			@optimiser.compressPng @sourcePath, (err)=>
-				args = @child_process.exec.args[0][0]
-				args.should.equal "optipng #{@sourcePath}"
-				done()
+		it("convert the file", function(done){
+			this.child_process.exec.callsArgWith(2);
+			return this.optimiser.compressPng(this.sourcePath, err=> {
+				const args = this.child_process.exec.args[0][0];
+				args.should.equal(`optipng ${this.sourcePath}`);
+				return done();
+			});
+		});
 
 
-		it "should return the error", (done)->
-			@child_process.exec.callsArgWith(2, @error)
-			@optimiser.compressPng @sourcePath, (err)=>
-				err.should.equal @error
-				done()
+		return it("should return the error", function(done){
+			this.child_process.exec.callsArgWith(2, this.error);
+			return this.optimiser.compressPng(this.sourcePath, err=> {
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+	});
 
-	describe 'when enableConversions is disabled', ->
+	describe('when enableConversions is disabled', () => it('should produce an error', function(done) {
+        this.settings.enableConversions = false;
+        this.child_process.exec.callsArgWith(2);
+        return this.optimiser.compressPng(this.sourcePath, err=> {
+            this.child_process.exec.called.should.equal(false);
+            expect(err).to.exist;
+            return done();
+        });
+    }));
 
-		it 'should produce an error', (done) ->
-			@settings.enableConversions = false
-			@child_process.exec.callsArgWith(2)
-			@optimiser.compressPng @sourcePath, (err)=>
-				@child_process.exec.called.should.equal false
-				expect(err).to.exist
-				done()
 
-
-	describe 'when optimiser is sigkilled', ->
-
-		it 'should not produce an error', (done) ->
-			@error = new Error('woops')
-			@error.signal = 'SIGKILL'
-			@child_process.exec.callsArgWith(2, @error)
-			@optimiser.compressPng @sourcePath, (err)=>
-				expect(err).to.equal(null)
-				done()
+	return describe('when optimiser is sigkilled', () => it('should not produce an error', function(done) {
+        this.error = new Error('woops');
+        this.error.signal = 'SIGKILL';
+        this.child_process.exec.callsArgWith(2, this.error);
+        return this.optimiser.compressPng(this.sourcePath, err=> {
+            expect(err).to.equal(null);
+            return done();
+        });
+    }));
+});

+ 50 - 30
services/filestore/test/unit/coffee/KeybuilderTests.js

@@ -1,39 +1,59 @@
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
 
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/KeyBuilder.js"
-SandboxedModule = require('sandboxed-module')
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/KeyBuilder.js";
+const SandboxedModule = require('sandboxed-module');
 
-describe "LocalFileWriter", ->
+describe("LocalFileWriter", function() {
 
-	beforeEach ->
+	beforeEach(function() {
 
-		@keyBuilder = SandboxedModule.require modulePath, requires:
-			"logger-sharelatex":
-				log:->
-				err:->
-		@key = "123/456"
+		this.keyBuilder = SandboxedModule.require(modulePath, { requires: {
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			}
+		}
+	}
+		);
+		return this.key = "123/456";
+	});
 		
-	describe "cachedKey", ->
+	return describe("cachedKey", function() {
 
-		it "should add the fomat on", ->
-			opts =
-				format: "png"
-			newKey = @keyBuilder.addCachingToKey @key, opts
-			newKey.should.equal "#{@key}-converted-cache/format-png"
+		it("should add the fomat on", function() {
+			const opts =
+				{format: "png"};
+			const newKey = this.keyBuilder.addCachingToKey(this.key, opts);
+			return newKey.should.equal(`${this.key}-converted-cache/format-png`);
+		});
 
-		it "should add the style on", ->
-			opts =
-				style: "thumbnail"
-			newKey = @keyBuilder.addCachingToKey @key, opts
-			newKey.should.equal "#{@key}-converted-cache/style-thumbnail"
+		it("should add the style on", function() {
+			const opts =
+				{style: "thumbnail"};
+			const newKey = this.keyBuilder.addCachingToKey(this.key, opts);
+			return newKey.should.equal(`${this.key}-converted-cache/style-thumbnail`);
+		});
 
-		it "should add format on first", ->
-			opts =
-				style: "thumbnail"
+		return it("should add format on first", function() {
+			const opts = {
+				style: "thumbnail",
 				format: "png"
-			newKey = @keyBuilder.addCachingToKey @key, opts
-			newKey.should.equal "#{@key}-converted-cache/format-png-style-thumbnail"
+			};
+			const newKey = this.keyBuilder.addCachingToKey(this.key, opts);
+			return newKey.should.equal(`${this.key}-converted-cache/format-png-style-thumbnail`);
+		});
+	});
+});

+ 106 - 68
services/filestore/test/unit/coffee/LocalFileWriterTests.js

@@ -1,83 +1,121 @@
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
 
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/LocalFileWriter.js"
-SandboxedModule = require('sandboxed-module')
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/LocalFileWriter.js";
+const SandboxedModule = require('sandboxed-module');
 
-describe "LocalFileWriter", ->
+describe("LocalFileWriter", function() {
 
-	beforeEach ->
+	beforeEach(function() {
 
-		@writeStream = 
-			on: (type, cb)->
-				if type == "finish"
-					cb()
-		@readStream = 
-			on: ->
-		@fs = 
-			createWriteStream : sinon.stub().returns(@writeStream)
-			createReadStream: sinon.stub().returns(@readStream)
+		this.writeStream = { 
+			on(type, cb){
+				if (type === "finish") {
+					return cb();
+				}
+			}
+		};
+		this.readStream = 
+			{on() {}};
+		this.fs = { 
+			createWriteStream : sinon.stub().returns(this.writeStream),
+			createReadStream: sinon.stub().returns(this.readStream),
 			unlink: sinon.stub()
-		@settings =
-			path:
+		};
+		this.settings = {
+			path: {
 				uploadFolder:"somewhere"
-		@writer = SandboxedModule.require modulePath, requires:
-			"fs": @fs
-			"logger-sharelatex":
-				log:->
-				err:->
-			"settings-sharelatex":@settings
-			"metrics-sharelatex": 
-				inc:->
-				Timer:->
-					done:->
+			}
+		};
+		this.writer = SandboxedModule.require(modulePath, { requires: {
+			"fs": this.fs,
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			},
+			"settings-sharelatex":this.settings,
+			"metrics-sharelatex": { 
+				inc() {},
+				Timer() {
+					return {done() {}};
+				}
+			}
+		}
+	}
+		);
 
-		@stubbedFsPath = "something/uploads/eio2k1j3"
+		return this.stubbedFsPath = "something/uploads/eio2k1j3";
+	});
 
-	describe "writeStrem", ->
-		beforeEach ->
-			@writer._getPath = sinon.stub().returns(@stubbedFsPath)
+	describe("writeStrem", function() {
+		beforeEach(function() {
+			return this.writer._getPath = sinon.stub().returns(this.stubbedFsPath);
+		});
 
-		it "write the stream to ./uploads", (done)->
-			stream = 
-				pipe: (dest)=>
-					dest.should.equal @writeStream
-					done()
-				on: ->
-			@writer.writeStream stream, null, ()=>
+		it("write the stream to ./uploads", function(done){
+			const stream = { 
+				pipe: dest=> {
+					dest.should.equal(this.writeStream);
+					return done();
+				},
+				on() {}
+			};
+			return this.writer.writeStream(stream, null, ()=> {});
+		});
 
-		it "should send the path in the callback", (done)->
-			stream = 
-				pipe: (dest)=>
-				on: (type, cb)->
-					if type == "end"
-						cb()
-			@writer.writeStream stream, null, (err, fsPath)=>
-				fsPath.should.equal @stubbedFsPath
-				done()
+		return it("should send the path in the callback", function(done){
+			const stream = { 
+				pipe: dest=> {},
+				on(type, cb){
+					if (type === "end") {
+						return cb();
+					}
+				}
+			};
+			return this.writer.writeStream(stream, null, (err, fsPath)=> {
+				fsPath.should.equal(this.stubbedFsPath);
+				return done();
+			});
+		});
+	});
 
-	describe "getStream", ->
+	describe("getStream", function() {
 
-		it "should read the stream from the file ", (done)->
-			@writer.getStream @stubbedFsPath, (err, stream)=>
-				@fs.createReadStream.calledWith(@stubbedFsPath).should.equal true
-				done()
+		it("should read the stream from the file ", function(done){
+			return this.writer.getStream(this.stubbedFsPath, (err, stream)=> {
+				this.fs.createReadStream.calledWith(this.stubbedFsPath).should.equal(true);
+				return done();
+			});
+		});
 
-		it "should send the stream in the callback", (done)->
-			@writer.getStream @stubbedFsPath, (err, readStream)=>
-				readStream.should.equal @readStream
-				done()
+		return it("should send the stream in the callback", function(done){
+			return this.writer.getStream(this.stubbedFsPath, (err, readStream)=> {
+				readStream.should.equal(this.readStream);
+				return done();
+			});
+		});
+	});
 
-	describe "delete file", ->
-
-		it "should unlink the file", (done)->
-			error = "my error"
-			@fs.unlink.callsArgWith(1, error)
-			@writer.deleteFile @stubbedFsPath, (err)=>
-				@fs.unlink.calledWith(@stubbedFsPath).should.equal true
-				err.should.equal error
-				done()
+	return describe("delete file", () => it("should unlink the file", function(done){
+        const error = "my error";
+        this.fs.unlink.callsArgWith(1, error);
+        return this.writer.deleteFile(this.stubbedFsPath, err=> {
+            this.fs.unlink.calledWith(this.stubbedFsPath).should.equal(true);
+            err.should.equal(error);
+            return done();
+        });
+    }));
+});
 

+ 115 - 85
services/filestore/test/unit/coffee/PersistorManagerTests.js

@@ -1,101 +1,131 @@
-logger = require("logger-sharelatex")
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/PersistorManager.js"
-SandboxedModule = require('sandboxed-module')
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const logger = require("logger-sharelatex");
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/PersistorManager.js";
+const SandboxedModule = require('sandboxed-module');
 
 
-describe "PersistorManagerTests", ->
+describe("PersistorManagerTests", function() {
 
-	beforeEach ->
-		@S3PersistorManager =
-			getFileStream: sinon.stub()
-			checkIfFileExists: sinon.stub()
-			deleteFile: sinon.stub()
-			deleteDirectory: sinon.stub()
-			sendStream: sinon.stub()
+	beforeEach(function() {
+		return this.S3PersistorManager = {
+			getFileStream: sinon.stub(),
+			checkIfFileExists: sinon.stub(),
+			deleteFile: sinon.stub(),
+			deleteDirectory: sinon.stub(),
+			sendStream: sinon.stub(),
 			insertFile: sinon.stub()
+		};
+	});
 
-	describe "test s3 mixin", ->
-		beforeEach ->
-			@settings =
-				filestore:
+	describe("test s3 mixin", function() {
+		beforeEach(function() {
+			this.settings = {
+				filestore: {
 					backend: "s3"
-			@requires =
-				"./S3PersistorManager": @S3PersistorManager
-				"settings-sharelatex": @settings
-				"logger-sharelatex":
-					log:->
-					err:->
-			@PersistorManager = SandboxedModule.require modulePath, requires: @requires
+				}
+			};
+			this.requires = {
+				"./S3PersistorManager": this.S3PersistorManager,
+				"settings-sharelatex": this.settings,
+				"logger-sharelatex": {
+					log() {},
+					err() {}
+				}
+			};
+			return this.PersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
+		});
 
-		it "should load getFileStream", (done) ->
-			@PersistorManager.should.respondTo("getFileStream")
-			@PersistorManager.getFileStream()
-			@S3PersistorManager.getFileStream.calledOnce.should.equal true
-			done()
+		it("should load getFileStream", function(done) {
+			this.PersistorManager.should.respondTo("getFileStream");
+			this.PersistorManager.getFileStream();
+			this.S3PersistorManager.getFileStream.calledOnce.should.equal(true);
+			return done();
+		});
 
-		it "should load checkIfFileExists", (done) ->
-			@PersistorManager.checkIfFileExists()
-			@S3PersistorManager.checkIfFileExists.calledOnce.should.equal true
-			done()
+		it("should load checkIfFileExists", function(done) {
+			this.PersistorManager.checkIfFileExists();
+			this.S3PersistorManager.checkIfFileExists.calledOnce.should.equal(true);
+			return done();
+		});
 
-		it "should load deleteFile", (done) ->
-			@PersistorManager.deleteFile()
-			@S3PersistorManager.deleteFile.calledOnce.should.equal true
-			done()
+		it("should load deleteFile", function(done) {
+			this.PersistorManager.deleteFile();
+			this.S3PersistorManager.deleteFile.calledOnce.should.equal(true);
+			return done();
+		});
 
-		it "should load deleteDirectory", (done) ->
-			@PersistorManager.deleteDirectory()
-			@S3PersistorManager.deleteDirectory.calledOnce.should.equal true
-			done()
+		it("should load deleteDirectory", function(done) {
+			this.PersistorManager.deleteDirectory();
+			this.S3PersistorManager.deleteDirectory.calledOnce.should.equal(true);
+			return done();
+		});
 
-		it "should load sendStream", (done) ->
-			@PersistorManager.sendStream()
-			@S3PersistorManager.sendStream.calledOnce.should.equal true
-			done()
+		it("should load sendStream", function(done) {
+			this.PersistorManager.sendStream();
+			this.S3PersistorManager.sendStream.calledOnce.should.equal(true);
+			return done();
+		});
 
-		it "should load insertFile", (done) ->
-			@PersistorManager.insertFile()
-			@S3PersistorManager.insertFile.calledOnce.should.equal true
-			done()
+		return it("should load insertFile", function(done) {
+			this.PersistorManager.insertFile();
+			this.S3PersistorManager.insertFile.calledOnce.should.equal(true);
+			return done();
+		});
+	});
 
-	describe "test unspecified mixins", ->
+	describe("test unspecified mixins", () => it("should load s3 when no wrapper specified", function(done) {
+        this.settings = {filestore:{}};
+        this.requires = {
+            "./S3PersistorManager": this.S3PersistorManager,
+            "settings-sharelatex": this.settings,
+            "logger-sharelatex": {
+                log() {},
+                err() {}
+            }
+        };
+        this.PersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
+        this.PersistorManager.should.respondTo("getFileStream");
+        this.PersistorManager.getFileStream();
+        this.S3PersistorManager.getFileStream.calledOnce.should.equal(true);
+        return done();
+    }));
 
-		it "should load s3 when no wrapper specified", (done) ->
-			@settings = {filestore:{}}
-			@requires =
-				"./S3PersistorManager": @S3PersistorManager
-				"settings-sharelatex": @settings
-				"logger-sharelatex":
-					log:->
-					err:->
-			@PersistorManager = SandboxedModule.require modulePath, requires: @requires
-			@PersistorManager.should.respondTo("getFileStream")
-			@PersistorManager.getFileStream()
-			@S3PersistorManager.getFileStream.calledOnce.should.equal true
-			done()
-
-	describe "test invalid mixins", ->
-		it "should not load an invalid wrapper", (done) ->
-			@settings =
-				filestore:
-					backend:"magic"
-			@requires =
-				"./S3PersistorManager": @S3PersistorManager
-				"settings-sharelatex": @settings
-				"logger-sharelatex":
-					log:->
-					err:->
-			@fsWrapper=null
-			try
-				@PersistorManager=SandboxedModule.require modulePath, requires: @requires
-			catch error
-				assert.equal("Unknown filestore backend: magic",error.message)
-			assert.isNull(@fsWrapper)
-			done()
+	return describe("test invalid mixins", () => it("should not load an invalid wrapper", function(done) {
+        this.settings = {
+            filestore: {
+                backend:"magic"
+            }
+        };
+        this.requires = {
+            "./S3PersistorManager": this.S3PersistorManager,
+            "settings-sharelatex": this.settings,
+            "logger-sharelatex": {
+                log() {},
+                err() {}
+            }
+        };
+        this.fsWrapper=null;
+        try {
+            this.PersistorManager=SandboxedModule.require(modulePath, {requires: this.requires});
+        } catch (error) {
+            assert.equal("Unknown filestore backend: magic",error.message);
+        }
+        assert.isNull(this.fsWrapper);
+        return done();
+    }));
+});
 
 

+ 438 - 334
services/filestore/test/unit/coffee/S3PersistorManagerTests.js

@@ -1,343 +1,447 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/S3PersistorManager.js"
-SandboxedModule = require('sandboxed-module')
-
-describe "S3PersistorManagerTests", ->
-
-	beforeEach ->
-		@settings =
-			filestore:
-				backend: "s3"
-				s3:
-					secret: "secret"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/S3PersistorManager.js";
+const SandboxedModule = require('sandboxed-module');
+
+describe("S3PersistorManagerTests", function() {
+
+	beforeEach(function() {
+		this.settings = {
+			filestore: {
+				backend: "s3",
+				s3: {
+					secret: "secret",
 					key: "this_key"
-				stores:
+				},
+				stores: {
 					user_files:"sl_user_files"
-		@knoxClient =
-			putFile:sinon.stub()
-			copyFile:sinon.stub()
-			list: sinon.stub()
-			deleteMultiple: sinon.stub()
+				}
+			}
+		};
+		this.knoxClient = {
+			putFile:sinon.stub(),
+			copyFile:sinon.stub(),
+			list: sinon.stub(),
+			deleteMultiple: sinon.stub(),
 			get: sinon.stub()
-		@knox =
-			createClient: sinon.stub().returns(@knoxClient)
-		@s3EventHandlers = {}
-		@s3Request =
-			on: sinon.stub().callsFake (event, callback) =>
-				@s3EventHandlers[event] = callback
+		};
+		this.knox =
+			{createClient: sinon.stub().returns(this.knoxClient)};
+		this.s3EventHandlers = {};
+		this.s3Request = {
+			on: sinon.stub().callsFake((event, callback) => {
+				return this.s3EventHandlers[event] = callback;
+			}),
 			send: sinon.stub()
-		@s3Response =
-			httpResponse:
+		};
+		this.s3Response = {
+			httpResponse: {
 				createUnbufferedStream: sinon.stub()
-		@s3Client =
-			copyObject: sinon.stub()
-			headObject: sinon.stub()
-			getObject: sinon.stub().returns(@s3Request)
-		@awsS3 = sinon.stub().returns(@s3Client)
-		@LocalFileWriter =
-			writeStream: sinon.stub()
+			}
+		};
+		this.s3Client = {
+			copyObject: sinon.stub(),
+			headObject: sinon.stub(),
+			getObject: sinon.stub().returns(this.s3Request)
+		};
+		this.awsS3 = sinon.stub().returns(this.s3Client);
+		this.LocalFileWriter = {
+			writeStream: sinon.stub(),
 			deleteFile: sinon.stub()
-		@request = sinon.stub()
-		@requires =
-			"knox": @knox
-			"aws-sdk/clients/s3": @awsS3
-			"settings-sharelatex": @settings
-			"./LocalFileWriter":@LocalFileWriter
-			"logger-sharelatex":
-				log:->
-				err:->
-			"request": @request
-			"./Errors": @Errors =
-				NotFoundError: sinon.stub()
-		@key = "my/key"
-		@bucketName = "my-bucket"
-		@error = "my errror"
-		@S3PersistorManager = SandboxedModule.require modulePath, requires: @requires
-
-	describe "getFileStream", ->
-		describe "success", ->
-			beforeEach () ->
-				@expectedStream = { expectedStream: true }
-				@expectedStream.on = sinon.stub()
-				@s3Request.send.callsFake () =>
-					@s3EventHandlers.httpHeaders(200, {}, @s3Response, "OK")
-				@s3Response.httpResponse.createUnbufferedStream.returns(@expectedStream)
-
-			it "returns a stream", (done) ->
-				@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
-					if err?
-						return done(err)
-					expect(stream).to.equal(@expectedStream)
-					done()
-
-			it "sets the AWS client up with credentials from settings", (done) ->
-				@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
-					if err?
-						return done(err)
-					expect(@awsS3.lastCall.args).to.deep.equal([{
-						credentials:
-							accessKeyId: @settings.filestore.s3.key
-							secretAccessKey: @settings.filestore.s3.secret
-					}])
-					done()
-
-			it "fetches the right key from the right bucket", (done) ->
-				@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
-					if err?
-						return done(err)
-					expect(@s3Client.getObject.lastCall.args).to.deep.equal([{
-						Bucket: @bucketName,
-						Key: @key
-					}])
-					done()
-
-			it "accepts alternative credentials", (done) ->
-				accessKeyId = "that_key"
-				secret = "that_secret"
-				opts = {
-					credentials:
-						auth_key: accessKeyId
+		};
+		this.request = sinon.stub();
+		this.requires = {
+			"knox": this.knox,
+			"aws-sdk/clients/s3": this.awsS3,
+			"settings-sharelatex": this.settings,
+			"./LocalFileWriter":this.LocalFileWriter,
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			},
+			"request": this.request,
+			"./Errors": (this.Errors =
+				{NotFoundError: sinon.stub()})
+		};
+		this.key = "my/key";
+		this.bucketName = "my-bucket";
+		this.error = "my errror";
+		return this.S3PersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
+	});
+
+	describe("getFileStream", function() {
+		describe("success", function() {
+			beforeEach(function() {
+				this.expectedStream = { expectedStream: true };
+				this.expectedStream.on = sinon.stub();
+				this.s3Request.send.callsFake(() => {
+					return this.s3EventHandlers.httpHeaders(200, {}, this.s3Response, "OK");
+				});
+				return this.s3Response.httpResponse.createUnbufferedStream.returns(this.expectedStream);
+			});
+
+			it("returns a stream", function(done) {
+				return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
+					if (err != null) {
+						return done(err);
+					}
+					expect(stream).to.equal(this.expectedStream);
+					return done();
+				});
+			});
+
+			it("sets the AWS client up with credentials from settings", function(done) {
+				return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
+					if (err != null) {
+						return done(err);
+					}
+					expect(this.awsS3.lastCall.args).to.deep.equal([{
+						credentials: {
+							accessKeyId: this.settings.filestore.s3.key,
+							secretAccessKey: this.settings.filestore.s3.secret
+						}
+					}]);
+					return done();
+				});
+			});
+
+			it("fetches the right key from the right bucket", function(done) {
+				return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
+					if (err != null) {
+						return done(err);
+					}
+					expect(this.s3Client.getObject.lastCall.args).to.deep.equal([{
+						Bucket: this.bucketName,
+						Key: this.key
+					}]);
+					return done();
+				});
+			});
+
+			it("accepts alternative credentials", function(done) {
+				const accessKeyId = "that_key";
+				const secret = "that_secret";
+				const opts = {
+					credentials: {
+						auth_key: accessKeyId,
 						auth_secret: secret
-				}
-				@S3PersistorManager.getFileStream @bucketName, @key, opts, (err, stream) =>
-					if err?
-						return done(err)
-					expect(@awsS3.lastCall.args).to.deep.equal([{
-						credentials:
-							accessKeyId: accessKeyId
+					}
+				};
+				return this.S3PersistorManager.getFileStream(this.bucketName, this.key, opts, (err, stream) => {
+					if (err != null) {
+						return done(err);
+					}
+					expect(this.awsS3.lastCall.args).to.deep.equal([{
+						credentials: {
+							accessKeyId,
 							secretAccessKey: secret
-					}])
-					expect(stream).to.equal(@expectedStream)
-					done()
-
-			it "accepts byte range", (done) ->
-				start = 0
-				end = 8
-				opts = { start: start, end: end }
-				@S3PersistorManager.getFileStream @bucketName, @key, opts, (err, stream) =>
-					if err?
-						return done(err)
-					expect(@s3Client.getObject.lastCall.args).to.deep.equal([{
-						Bucket: @bucketName
-						Key: @key
-						Range: "bytes=#{start}-#{end}"
-					}])
-					expect(stream).to.equal(@expectedStream)
-					done()
-
-		describe "errors", ->
-			describe "when the file doesn't exist", ->
-				beforeEach ->
-					@s3Request.send.callsFake () =>
-						@s3EventHandlers.httpHeaders(404, {}, @s3Response, "Not found")
-
-				it "returns a NotFoundError that indicates the bucket and key", (done) ->
-					@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
-						expect(err).to.be.instanceof(@Errors.NotFoundError)
-						errMsg = @Errors.NotFoundError.lastCall.args[0]
-						expect(errMsg).to.match(new RegExp(".*#{@bucketName}.*"))
-						expect(errMsg).to.match(new RegExp(".*#{@key}.*"))
-						done()
-
-			describe "when S3 encounters an unkown error", ->
-				beforeEach ->
-					@s3Request.send.callsFake () =>
-						@s3EventHandlers.httpHeaders(500, {}, @s3Response, "Internal server error")
-
-				it "returns an error", (done) ->
-					@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
-						expect(err).to.be.instanceof(Error)
-						done()
-
-			describe "when the S3 request errors out before receiving HTTP headers", ->
-				beforeEach ->
-					@s3Request.send.callsFake () =>
-						@s3EventHandlers.error(new Error("connection failed"))
-
-				it "returns an error", (done) ->
-					@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
-						expect(err).to.be.instanceof(Error)
-						done()
-
-	describe "getFileSize", ->
-		it "should obtain the file size from S3", (done) ->
-			expectedFileSize = 123
-			@s3Client.headObject.yields(new Error(
+						}
+					}]);
+					expect(stream).to.equal(this.expectedStream);
+					return done();
+				});
+			});
+
+			return it("accepts byte range", function(done) {
+				const start = 0;
+				const end = 8;
+				const opts = { start, end };
+				return this.S3PersistorManager.getFileStream(this.bucketName, this.key, opts, (err, stream) => {
+					if (err != null) {
+						return done(err);
+					}
+					expect(this.s3Client.getObject.lastCall.args).to.deep.equal([{
+						Bucket: this.bucketName,
+						Key: this.key,
+						Range: `bytes=${start}-${end}`
+					}]);
+					expect(stream).to.equal(this.expectedStream);
+					return done();
+				});
+			});
+		});
+
+		return describe("errors", function() {
+			describe("when the file doesn't exist", function() {
+				beforeEach(function() {
+					return this.s3Request.send.callsFake(() => {
+						return this.s3EventHandlers.httpHeaders(404, {}, this.s3Response, "Not found");
+					});
+				});
+
+				return it("returns a NotFoundError that indicates the bucket and key", function(done) {
+					return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
+						expect(err).to.be.instanceof(this.Errors.NotFoundError);
+						const errMsg = this.Errors.NotFoundError.lastCall.args[0];
+						expect(errMsg).to.match(new RegExp(`.*${this.bucketName}.*`));
+						expect(errMsg).to.match(new RegExp(`.*${this.key}.*`));
+						return done();
+					});
+				});
+			});
+
+			describe("when S3 encounters an unkown error", function() {
+				beforeEach(function() {
+					return this.s3Request.send.callsFake(() => {
+						return this.s3EventHandlers.httpHeaders(500, {}, this.s3Response, "Internal server error");
+					});
+				});
+
+				return it("returns an error", function(done) {
+					return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
+						expect(err).to.be.instanceof(Error);
+						return done();
+					});
+				});
+			});
+
+			return describe("when the S3 request errors out before receiving HTTP headers", function() {
+				beforeEach(function() {
+					return this.s3Request.send.callsFake(() => {
+						return this.s3EventHandlers.error(new Error("connection failed"));
+					});
+				});
+
+				return it("returns an error", function(done) {
+					return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
+						expect(err).to.be.instanceof(Error);
+						return done();
+					});
+				});
+			});
+		});
+	});
+
+	describe("getFileSize", function() {
+		it("should obtain the file size from S3", function(done) {
+			const expectedFileSize = 123;
+			this.s3Client.headObject.yields(new Error(
 				"s3Client.headObject got unexpected arguments"
-			))
-			@s3Client.headObject.withArgs({
-				Bucket: @bucketName
-				Key: @key
-			}).yields(null, { ContentLength: expectedFileSize })
-
-			@S3PersistorManager.getFileSize @bucketName, @key, (err, fileSize) =>
-				if err?
-					return done(err)
-				expect(fileSize).to.equal(expectedFileSize)
-				done()
-
-		[403, 404].forEach (statusCode) ->
-			it "should throw NotFoundError when S3 responds with #{statusCode}", (done) ->
-				error = new Error()
-				error.statusCode = statusCode
-				@s3Client.headObject.yields(error)
-
-				@S3PersistorManager.getFileSize @bucketName, @key, (err, fileSize) =>
-					expect(err).to.be.an.instanceof(@Errors.NotFoundError)
-					done()
-
-		it "should rethrow any other error", (done) ->
-			error = new Error()
-			@s3Client.headObject.yields(error)
-			@s3Client.headObject.yields(error)
-
-			@S3PersistorManager.getFileSize @bucketName, @key, (err, fileSize) =>
-				expect(err).to.equal(error)
-				done()
-
-	describe "sendFile", ->
-
-		beforeEach ->
-			@knoxClient.putFile.returns on:->
-
-		it "should put file with knox", (done)->
-			@LocalFileWriter.deleteFile.callsArgWith(1)
-			@knoxClient.putFile.callsArgWith(2, @error)
-			@S3PersistorManager.sendFile @bucketName, @key, @fsPath, (err)=>
-				@knoxClient.putFile.calledWith(@fsPath, @key).should.equal true
-				err.should.equal @error
-				done()
-
-		it "should delete the file and pass the error with it", (done)->
-			@LocalFileWriter.deleteFile.callsArgWith(1)
-			@knoxClient.putFile.callsArgWith(2, @error)
-			@S3PersistorManager.sendFile @bucketName, @key, @fsPath, (err)=>
-				@knoxClient.putFile.calledWith(@fsPath, @key).should.equal true
-				err.should.equal @error
-				done()
-
-	describe "sendStream", ->
-		beforeEach ->
-			@fsPath = "to/some/where"
-			@origin =
-				on:->
-			@S3PersistorManager.sendFile = sinon.stub().callsArgWith(3)
-
-		it "should send stream to LocalFileWriter", (done)->
-			@LocalFileWriter.deleteFile.callsArgWith(1)
-			@LocalFileWriter.writeStream.callsArgWith(2, null, @fsPath)
-			@S3PersistorManager.sendStream @bucketName, @key, @origin, =>
-				@LocalFileWriter.writeStream.calledWith(@origin).should.equal true
-				done()
-
-		it "should return the error from LocalFileWriter", (done)->
-			@LocalFileWriter.deleteFile.callsArgWith(1)
-			@LocalFileWriter.writeStream.callsArgWith(2, @error)
-			@S3PersistorManager.sendStream @bucketName, @key, @origin, (err)=>
-				err.should.equal @error
-				done()
-
-		it "should send the file to the filestore", (done)->
-			@LocalFileWriter.deleteFile.callsArgWith(1)
-			@LocalFileWriter.writeStream.callsArgWith(2)
-			@S3PersistorManager.sendStream @bucketName, @key, @origin, (err)=>
-				@S3PersistorManager.sendFile.called.should.equal true
-				done()
-
-	describe "copyFile", ->
-		beforeEach ->
-			@sourceKey = "my/key"
-			@destKey = "my/dest/key"
-
-		it "should use AWS SDK to copy file", (done)->
-			@s3Client.copyObject.callsArgWith(1, @error)
-			@S3PersistorManager.copyFile @bucketName, @sourceKey, @destKey, (err)=>
-				err.should.equal @error
-				@s3Client.copyObject.calledWith({Bucket: @bucketName, Key: @destKey, CopySource: @bucketName + '/' + @key}).should.equal true
-				done()
-
-		it "should return a NotFoundError object if the original file does not exist", (done)->
-			NoSuchKeyError = {code: "NoSuchKey"}
-			@s3Client.copyObject.callsArgWith(1, NoSuchKeyError)
-			@S3PersistorManager.copyFile @bucketName, @sourceKey, @destKey, (err)=>
-				expect(err instanceof @Errors.NotFoundError).to.equal true
-				done()
-
-	describe "deleteDirectory", ->
-
-		it "should list the contents passing them onto multi delete", (done)->
-			data =
-				Contents: [{Key:"1234"}, {Key: "456"}]
-			@knoxClient.list.callsArgWith(1, null, data)
-			@knoxClient.deleteMultiple.callsArgWith(1)
-			@S3PersistorManager.deleteDirectory @bucketName, @key, (err)=>
-				@knoxClient.deleteMultiple.calledWith(["1234","456"]).should.equal true
-				done()
-
-	describe "deleteFile", ->
-
-		it "should use correct options", (done)->
-			@request.callsArgWith(1)
-
-			@S3PersistorManager.deleteFile @bucketName, @key, (err)=>
-				opts = @request.args[0][0]
-				assert.deepEqual(opts.aws, {key:@settings.filestore.s3.key, secret:@settings.filestore.s3.secret, bucket:@bucketName})
-				opts.method.should.equal "delete"
-				opts.timeout.should.equal (30*1000)
-				opts.uri.should.equal "https://#{@bucketName}.s3.amazonaws.com/#{@key}"
-				done()
-
-		it "should return the error", (done)->
-			@request.callsArgWith(1, @error)
-
-			@S3PersistorManager.deleteFile @bucketName, @key, (err)=>
-				err.should.equal @error
-				done()
-
-	describe "checkIfFileExists", ->
-
-		it "should use correct options", (done)->
-			@request.callsArgWith(1,  null, statusCode:200)
-
-			@S3PersistorManager.checkIfFileExists @bucketName, @key, (err)=>
-				opts = @request.args[0][0]
-				assert.deepEqual(opts.aws, {key:@settings.filestore.s3.key, secret:@settings.filestore.s3.secret, bucket:@bucketName})
-				opts.method.should.equal "head"
-				opts.timeout.should.equal (30*1000)
-				opts.uri.should.equal "https://#{@bucketName}.s3.amazonaws.com/#{@key}"
-				done()
-
-		it "should return true for a 200", (done)->
-			@request.callsArgWith(1, null, statusCode:200)
-
-			@S3PersistorManager.checkIfFileExists @bucketName, @key, (err, exists)=>
-				exists.should.equal true
-				done()
-
-		it "should return false for a non 200", (done)->
-			@request.callsArgWith(1, null, statusCode:404)
-
-			@S3PersistorManager.checkIfFileExists @bucketName, @key, (err, exists)=>
-				exists.should.equal false
-				done()
-
-		it "should return the error", (done)->
-			@request.callsArgWith(1, @error, {})
-
-			@S3PersistorManager.checkIfFileExists @bucketName, @key, (err)=>
-				err.should.equal @error
-				done()
-
-	describe "directorySize", ->
-
-		it "should sum directory files size", (done) ->
-			data =
-				Contents: [ {Size: 1024}, {Size: 2048} ]
-			@knoxClient.list.callsArgWith(1, null, data)
-			@S3PersistorManager.directorySize @bucketName, @key, (err, totalSize)=>
-				totalSize.should.equal 3072
-				done()
+			));
+			this.s3Client.headObject.withArgs({
+				Bucket: this.bucketName,
+				Key: this.key
+			}).yields(null, { ContentLength: expectedFileSize });
+
+			return this.S3PersistorManager.getFileSize(this.bucketName, this.key, (err, fileSize) => {
+				if (err != null) {
+					return done(err);
+				}
+				expect(fileSize).to.equal(expectedFileSize);
+				return done();
+			});
+		});
+
+		[403, 404].forEach(statusCode => it(`should throw NotFoundError when S3 responds with ${statusCode}`, function(done) {
+            const error = new Error();
+            error.statusCode = statusCode;
+            this.s3Client.headObject.yields(error);
+
+            return this.S3PersistorManager.getFileSize(this.bucketName, this.key, (err, fileSize) => {
+                expect(err).to.be.an.instanceof(this.Errors.NotFoundError);
+                return done();
+            });
+        }));
+
+		return it("should rethrow any other error", function(done) {
+			const error = new Error();
+			this.s3Client.headObject.yields(error);
+			this.s3Client.headObject.yields(error);
+
+			return this.S3PersistorManager.getFileSize(this.bucketName, this.key, (err, fileSize) => {
+				expect(err).to.equal(error);
+				return done();
+			});
+		});
+	});
+
+	describe("sendFile", function() {
+
+		beforeEach(function() {
+			return this.knoxClient.putFile.returns({on() {}});
+		});
+
+		it("should put file with knox", function(done){
+			this.LocalFileWriter.deleteFile.callsArgWith(1);
+			this.knoxClient.putFile.callsArgWith(2, this.error);
+			return this.S3PersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err=> {
+				this.knoxClient.putFile.calledWith(this.fsPath, this.key).should.equal(true);
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+
+		return it("should delete the file and pass the error with it", function(done){
+			this.LocalFileWriter.deleteFile.callsArgWith(1);
+			this.knoxClient.putFile.callsArgWith(2, this.error);
+			return this.S3PersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err=> {
+				this.knoxClient.putFile.calledWith(this.fsPath, this.key).should.equal(true);
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	describe("sendStream", function() {
+		beforeEach(function() {
+			this.fsPath = "to/some/where";
+			this.origin =
+				{on() {}};
+			return this.S3PersistorManager.sendFile = sinon.stub().callsArgWith(3);
+		});
+
+		it("should send stream to LocalFileWriter", function(done){
+			this.LocalFileWriter.deleteFile.callsArgWith(1);
+			this.LocalFileWriter.writeStream.callsArgWith(2, null, this.fsPath);
+			return this.S3PersistorManager.sendStream(this.bucketName, this.key, this.origin, () => {
+				this.LocalFileWriter.writeStream.calledWith(this.origin).should.equal(true);
+				return done();
+			});
+		});
+
+		it("should return the error from LocalFileWriter", function(done){
+			this.LocalFileWriter.deleteFile.callsArgWith(1);
+			this.LocalFileWriter.writeStream.callsArgWith(2, this.error);
+			return this.S3PersistorManager.sendStream(this.bucketName, this.key, this.origin, err=> {
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+
+		return it("should send the file to the filestore", function(done){
+			this.LocalFileWriter.deleteFile.callsArgWith(1);
+			this.LocalFileWriter.writeStream.callsArgWith(2);
+			return this.S3PersistorManager.sendStream(this.bucketName, this.key, this.origin, err=> {
+				this.S3PersistorManager.sendFile.called.should.equal(true);
+				return done();
+			});
+		});
+	});
+
+	describe("copyFile", function() {
+		beforeEach(function() {
+			this.sourceKey = "my/key";
+			return this.destKey = "my/dest/key";
+		});
+
+		it("should use AWS SDK to copy file", function(done){
+			this.s3Client.copyObject.callsArgWith(1, this.error);
+			return this.S3PersistorManager.copyFile(this.bucketName, this.sourceKey, this.destKey, err=> {
+				err.should.equal(this.error);
+				this.s3Client.copyObject.calledWith({Bucket: this.bucketName, Key: this.destKey, CopySource: this.bucketName + '/' + this.key}).should.equal(true);
+				return done();
+			});
+		});
+
+		return it("should return a NotFoundError object if the original file does not exist", function(done){
+			const NoSuchKeyError = {code: "NoSuchKey"};
+			this.s3Client.copyObject.callsArgWith(1, NoSuchKeyError);
+			return this.S3PersistorManager.copyFile(this.bucketName, this.sourceKey, this.destKey, err=> {
+				expect(err instanceof this.Errors.NotFoundError).to.equal(true);
+				return done();
+			});
+		});
+	});
+
+	describe("deleteDirectory", () => it("should list the contents passing them onto multi delete", function(done){
+        const data =
+            {Contents: [{Key:"1234"}, {Key: "456"}]};
+        this.knoxClient.list.callsArgWith(1, null, data);
+        this.knoxClient.deleteMultiple.callsArgWith(1);
+        return this.S3PersistorManager.deleteDirectory(this.bucketName, this.key, err=> {
+            this.knoxClient.deleteMultiple.calledWith(["1234","456"]).should.equal(true);
+            return done();
+        });
+    }));
+
+	describe("deleteFile", function() {
+
+		it("should use correct options", function(done){
+			this.request.callsArgWith(1);
+
+			return this.S3PersistorManager.deleteFile(this.bucketName, this.key, err=> {
+				const opts = this.request.args[0][0];
+				assert.deepEqual(opts.aws, {key:this.settings.filestore.s3.key, secret:this.settings.filestore.s3.secret, bucket:this.bucketName});
+				opts.method.should.equal("delete");
+				opts.timeout.should.equal((30*1000));
+				opts.uri.should.equal(`https://${this.bucketName}.s3.amazonaws.com/${this.key}`);
+				return done();
+			});
+		});
+
+		return it("should return the error", function(done){
+			this.request.callsArgWith(1, this.error);
+
+			return this.S3PersistorManager.deleteFile(this.bucketName, this.key, err=> {
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	describe("checkIfFileExists", function() {
+
+		it("should use correct options", function(done){
+			this.request.callsArgWith(1,  null, {statusCode:200});
+
+			return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, err=> {
+				const opts = this.request.args[0][0];
+				assert.deepEqual(opts.aws, {key:this.settings.filestore.s3.key, secret:this.settings.filestore.s3.secret, bucket:this.bucketName});
+				opts.method.should.equal("head");
+				opts.timeout.should.equal((30*1000));
+				opts.uri.should.equal(`https://${this.bucketName}.s3.amazonaws.com/${this.key}`);
+				return done();
+			});
+		});
+
+		it("should return true for a 200", function(done){
+			this.request.callsArgWith(1, null, {statusCode:200});
+
+			return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists)=> {
+				exists.should.equal(true);
+				return done();
+			});
+		});
+
+		it("should return false for a non 200", function(done){
+			this.request.callsArgWith(1, null, {statusCode:404});
+
+			return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists)=> {
+				exists.should.equal(false);
+				return done();
+			});
+		});
+
+		return it("should return the error", function(done){
+			this.request.callsArgWith(1, this.error, {});
+
+			return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, err=> {
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	return describe("directorySize", () => it("should sum directory files size", function(done) {
+        const data =
+            {Contents: [ {Size: 1024}, {Size: 2048} ]};
+        this.knoxClient.list.callsArgWith(1, null, data);
+        return this.S3PersistorManager.directorySize(this.bucketName, this.key, (err, totalSize)=> {
+            totalSize.should.equal(3072);
+            return done();
+        });
+    }));
+});

+ 75 - 50
services/filestore/test/unit/coffee/SafeExecTests.js

@@ -1,50 +1,75 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/SafeExec.js"
-SandboxedModule = require('sandboxed-module')
-
-describe "SafeExec", ->
-
-	beforeEach ->
-		@settings = 
-			enableConversions:true
-		@safe_exec = SandboxedModule.require modulePath, requires:
-			"logger-sharelatex":
-				log:->
-				err:->
-			"settings-sharelatex": @settings
-		@options = {timeout: 10*1000, killSignal: "SIGTERM" }
-
-	describe "safe_exec", ->
-
-		it "should execute a valid command", (done) ->
-			@safe_exec ["/bin/echo", "hello"], @options, (err, stdout, stderr) =>
-				stdout.should.equal "hello\n"
-				should.not.exist(err)
-				done()
-
-		it "should error when conversions are disabled", (done) ->
-			@settings.enableConversions = false
-			@safe_exec ["/bin/echo", "hello"], @options, (err, stdout, stderr) =>
-				expect(err).to.exist
-				done()
-
-		it "should execute a command with non-zero exit status", (done) ->
-			@safe_exec ["/usr/bin/env", "false"], @options, (err, stdout, stderr) =>
-				stdout.should.equal ""
-				stderr.should.equal ""
-				err.message.should.equal "exit status 1"
-				done()
-
-		it "should handle an invalid command", (done) ->
-			@safe_exec ["/bin/foobar"], @options, (err, stdout, stderr) =>
-				err.code.should.equal "ENOENT"
-				done()
-
-		it "should handle a command that runs too long", (done) ->
-			@safe_exec ["/bin/sleep", "10"], {timeout: 500, killSignal: "SIGTERM"}, (err, stdout, stderr) =>
-				err.should.equal "SIGTERM"
-				done()
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/SafeExec.js";
+const SandboxedModule = require('sandboxed-module');
+
+describe("SafeExec", function() {
+
+	beforeEach(function() {
+		this.settings = 
+			{enableConversions:true};
+		this.safe_exec = SandboxedModule.require(modulePath, { requires: {
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			},
+			"settings-sharelatex": this.settings
+		}
+	}
+		);
+		return this.options = {timeout: 10*1000, killSignal: "SIGTERM" };});
+
+	return describe("safe_exec", function() {
+
+		it("should execute a valid command", function(done) {
+			return this.safe_exec(["/bin/echo", "hello"], this.options, (err, stdout, stderr) => {
+				stdout.should.equal("hello\n");
+				should.not.exist(err);
+				return done();
+			});
+		});
+
+		it("should error when conversions are disabled", function(done) {
+			this.settings.enableConversions = false;
+			return this.safe_exec(["/bin/echo", "hello"], this.options, (err, stdout, stderr) => {
+				expect(err).to.exist;
+				return done();
+			});
+		});
+
+		it("should execute a command with non-zero exit status", function(done) {
+			return this.safe_exec(["/usr/bin/env", "false"], this.options, (err, stdout, stderr) => {
+				stdout.should.equal("");
+				stderr.should.equal("");
+				err.message.should.equal("exit status 1");
+				return done();
+			});
+		});
+
+		it("should handle an invalid command", function(done) {
+			return this.safe_exec(["/bin/foobar"], this.options, (err, stdout, stderr) => {
+				err.code.should.equal("ENOENT");
+				return done();
+			});
+		});
+
+		return it("should handle a command that runs too long", function(done) {
+			return this.safe_exec(["/bin/sleep", "10"], {timeout: 500, killSignal: "SIGTERM"}, (err, stdout, stderr) => {
+				err.should.equal("SIGTERM");
+				return done();
+			});
+		});
+	});
+});

+ 27 - 17
services/filestore/test/unit/coffee/SettingsTests.js

@@ -1,19 +1,29 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/BucketController.js"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/BucketController.js";
 
-describe "Settings", ->
-	describe "s3", ->
-		it "should use JSONified env var if present", (done)->
-			s3_settings =
-				bucket1:
-					auth_key: 'bucket1_key'
-					auth_secret: 'bucket1_secret'
-			process.env['S3_BUCKET_CREDENTIALS'] = JSON.stringify s3_settings
+describe("Settings", () => describe("s3", () => it("should use JSONified env var if present", function(done){
+    const s3_settings = {
+        bucket1: {
+            auth_key: 'bucket1_key',
+            auth_secret: 'bucket1_secret'
+        }
+    };
+    process.env['S3_BUCKET_CREDENTIALS'] = JSON.stringify(s3_settings);
 
-			settings = require("settings-sharelatex")
-			expect(settings.filestore.s3BucketCreds).to.deep.equal s3_settings
-			done()
+    const settings = require("settings-sharelatex");
+    expect(settings.filestore.s3BucketCreds).to.deep.equal(s3_settings);
+    return done();
+})));