Просмотр исходного кода

decaffeinate: Convert DocArchiveManagerTests.coffee and 4 other files to JS

decaffeinate 6 лет назад
Родитель
Сommit
06bdba5c14

+ 399 - 311
services/docstore/test/unit/coffee/DocArchiveManagerTests.js

@@ -1,356 +1,444 @@
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/DocArchiveManager.js"
-SandboxedModule = require('sandboxed-module')
-ObjectId = require("mongojs").ObjectId
-Errors = require "../../../app/js/Errors"
-crypto = require("crypto")
-
-describe "DocArchiveManager", ->
-
-	beforeEach ->
-
-		@settings =
-			docstore:
-				s3:
-					secret: "secret"
-					key: "this_key"
+/*
+ * decaffeinate suggestions:
+ * DS101: Remove unnecessary use of Array.from
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const modulePath = "../../../app/js/DocArchiveManager.js";
+const SandboxedModule = require('sandboxed-module');
+const {
+    ObjectId
+} = require("mongojs");
+const Errors = require("../../../app/js/Errors");
+const crypto = require("crypto");
+
+describe("DocArchiveManager", function() {
+
+	beforeEach(function() {
+
+		this.settings = {
+			docstore: {
+				s3: {
+					secret: "secret",
+					key: "this_key",
 					bucket:"doc-archive-unit-test"
+				}
+			}
+		};
 
-		@request = 
-			put: {}
-			get: {}
+		this.request = { 
+			put: {},
+			get: {},
 			del: {}
+		};
 
-		@archivedDocs = [{
-			_id: ObjectId()
-			inS3:true
+		this.archivedDocs = [{
+			_id: ObjectId(),
+			inS3:true,
 			rev: 2
 		}, {
-			_id: ObjectId()
-			inS3:true
+			_id: ObjectId(),
+			inS3:true,
 			rev: 4
 		}, {
-			_id: ObjectId()
-			inS3:true
+			_id: ObjectId(),
+			inS3:true,
 			rev: 6
-		}]
+		}];
 
-		@mongoDocs = [{
-			_id: ObjectId()
-			lines: ["one", "two", "three"]
+		this.mongoDocs = [{
+			_id: ObjectId(),
+			lines: ["one", "two", "three"],
 			rev: 2
 		}, {
-			_id: ObjectId()
-			lines: ["aaa", "bbb", "ccc"]
+			_id: ObjectId(),
+			lines: ["aaa", "bbb", "ccc"],
 			rev: 4
 		}, {
-			_id: ObjectId()
-			inS3: true
+			_id: ObjectId(),
+			inS3: true,
 			rev: 6
 		}, {
-			_id: ObjectId()
-			inS3: true
+			_id: ObjectId(),
+			inS3: true,
 			rev: 6
 		}, {
-			_id: ObjectId()
-			lines: ["111", "222", "333"]
+			_id: ObjectId(),
+			lines: ["111", "222", "333"],
 			rev: 6
-		}]
+		}];
 
-		@unarchivedDocs = [{
-			_id: ObjectId()
-			lines: ["wombat", "potato", "banana"]
+		this.unarchivedDocs = [{
+			_id: ObjectId(),
+			lines: ["wombat", "potato", "banana"],
 			rev: 2
 		}, {
-			_id: ObjectId()
-			lines: ["llama", "turnip", "apple"]
+			_id: ObjectId(),
+			lines: ["llama", "turnip", "apple"],
 			rev: 4
 		}, {
-			_id: ObjectId()
-			lines: ["elephant", "swede", "nectarine"]
+			_id: ObjectId(),
+			lines: ["elephant", "swede", "nectarine"],
 			rev: 6
-		}]
-
-		@mixedDocs = @archivedDocs.concat(@unarchivedDocs)
-
-		@MongoManager =
-			markDocAsArchived: sinon.stub().callsArgWith(2, null)
-			upsertIntoDocCollection: sinon.stub().callsArgWith(3, null)
-			getProjectsDocs: sinon.stub().callsArgWith(3, null, @mongoDocs)
-			getArchivedProjectDocs: sinon.stub().callsArgWith(2, null, @mongoDocs)
-
-		@requires = 
-			"settings-sharelatex": @settings
-			"./MongoManager": @MongoManager
-			"request": @request
-			"./RangeManager": @RangeManager = {}
-			"logger-sharelatex":
-				log:->
-				err:->
-		@globals =
-			JSON: JSON
-
-		@error = "my errror"
-		@project_id = ObjectId().toString()
-		@stubbedError = new Errors.NotFoundError("Error in S3 request")
-		@DocArchiveManager = SandboxedModule.require modulePath, requires: @requires, globals: @globals
-
-	describe "archiveDoc", ->
-
-		it "should use correct options", (done)->
-			@request.put = sinon.stub().callsArgWith(1,  null, {statusCode:200,headers:{etag:""}})
-			@DocArchiveManager.archiveDoc @project_id, @mongoDocs[0], (err)=>
-				opts = @request.put.args[0][0]
-				assert.deepEqual(opts.aws, {key:@settings.docstore.s3.key, secret:@settings.docstore.s3.secret, bucket:@settings.docstore.s3.bucket})
-				opts.body.should.equal JSON.stringify(
-					lines: @mongoDocs[0].lines
-					ranges: @mongoDocs[0].ranges
+		}];
+
+		this.mixedDocs = this.archivedDocs.concat(this.unarchivedDocs);
+
+		this.MongoManager = {
+			markDocAsArchived: sinon.stub().callsArgWith(2, null),
+			upsertIntoDocCollection: sinon.stub().callsArgWith(3, null),
+			getProjectsDocs: sinon.stub().callsArgWith(3, null, this.mongoDocs),
+			getArchivedProjectDocs: sinon.stub().callsArgWith(2, null, this.mongoDocs)
+		};
+
+		this.requires = { 
+			"settings-sharelatex": this.settings,
+			"./MongoManager": this.MongoManager,
+			"request": this.request,
+			"./RangeManager": (this.RangeManager = {}),
+			"logger-sharelatex": {
+				log() {},
+				err() {}
+			}
+		};
+		this.globals =
+			{JSON};
+
+		this.error = "my errror";
+		this.project_id = ObjectId().toString();
+		this.stubbedError = new Errors.NotFoundError("Error in S3 request");
+		return this.DocArchiveManager = SandboxedModule.require(modulePath, {requires: this.requires, globals: this.globals});
+	});
+
+	describe("archiveDoc", function() {
+
+		it("should use correct options", function(done){
+			this.request.put = sinon.stub().callsArgWith(1,  null, {statusCode:200,headers:{etag:""}});
+			return this.DocArchiveManager.archiveDoc(this.project_id, this.mongoDocs[0], err=> {
+				const opts = this.request.put.args[0][0];
+				assert.deepEqual(opts.aws, {key:this.settings.docstore.s3.key, secret:this.settings.docstore.s3.secret, bucket:this.settings.docstore.s3.bucket});
+				opts.body.should.equal(JSON.stringify({
+					lines: this.mongoDocs[0].lines,
+					ranges: this.mongoDocs[0].ranges,
 					schema_v: 1
-				)
-				opts.timeout.should.equal (30*1000)
-				opts.uri.should.equal "https://#{@settings.docstore.s3.bucket}.s3.amazonaws.com/#{@project_id}/#{@mongoDocs[0]._id}"
-				done()
-
-		it "should return no md5 error", (done)->
-			data = JSON.stringify(
-				lines: @mongoDocs[0].lines
-				ranges: @mongoDocs[0].ranges
+				})
+				);
+				opts.timeout.should.equal((30*1000));
+				opts.uri.should.equal(`https://${this.settings.docstore.s3.bucket}.s3.amazonaws.com/${this.project_id}/${this.mongoDocs[0]._id}`);
+				return done();
+			});
+		});
+
+		it("should return no md5 error", function(done){
+			const data = JSON.stringify({
+				lines: this.mongoDocs[0].lines,
+				ranges: this.mongoDocs[0].ranges,
 				schema_v: 1
-			)
-			@md5 = crypto.createHash("md5").update(data).digest("hex")
-			@request.put = sinon.stub().callsArgWith(1,  null, {statusCode:200,headers:{etag:@md5}})
-			@DocArchiveManager.archiveDoc @project_id, @mongoDocs[0], (err)=>
-				should.not.exist err
-				done()
-
-		it "should return the error", (done)->
-			@request.put = sinon.stub().callsArgWith(1, @stubbedError, {statusCode:400,headers:{etag:""}})
-			@DocArchiveManager.archiveDoc @project_id, @mongoDocs[0], (err)=>
-				should.exist err
-				done()
-
-	describe "unarchiveDoc", ->
-
-		it "should use correct options", (done)->
-			@request.get = sinon.stub().callsArgWith(1, null, statusCode:200, @mongoDocs[0].lines)
-			@request.del = sinon.stub().callsArgWith(1, null, statusCode:204, {})
-			@DocArchiveManager.unarchiveDoc @project_id, @mongoDocs[0]._id, (err)=>
-				opts = @request.get.args[0][0]
-				assert.deepEqual(opts.aws, {key:@settings.docstore.s3.key, secret:@settings.docstore.s3.secret, bucket:@settings.docstore.s3.bucket})
-				opts.json.should.equal true
-				opts.timeout.should.equal (30*1000)
-				opts.uri.should.equal "https://#{@settings.docstore.s3.bucket}.s3.amazonaws.com/#{@project_id}/#{@mongoDocs[0]._id}"
-				done()
-
-		it "should return the error", (done)->
-			@request.get = sinon.stub().callsArgWith(1, @stubbedError, {}, {})
-			@DocArchiveManager.unarchiveDoc @project_id, @mongoDocs[0], (err)=>
-				should.exist err
-				done()
-
-		it "should error if the doc lines are a string not an array", (done)->
-			@request.get = sinon.stub().callsArgWith(1, null, statusCode:200, "this is a string")
-			@request.del = sinon.stub()
-			@DocArchiveManager.unarchiveDoc @project_id, @mongoDocs[0], (err)=>
-				should.exist err
-				@request.del.called.should.equal false
-				done()
-
-	describe "archiveAllDocs", ->
-
-		it "should archive all project docs which are not in s3", (done)->
-			@MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, @mongoDocs)
-			@DocArchiveManager.archiveDoc = sinon.stub().callsArgWith(2, null)
-
-			@DocArchiveManager.archiveAllDocs @project_id, (err)=>
-				@DocArchiveManager.archiveDoc.calledWith(@project_id, @mongoDocs[0]).should.equal true
-				@DocArchiveManager.archiveDoc.calledWith(@project_id, @mongoDocs[1]).should.equal true
-				@DocArchiveManager.archiveDoc.calledWith(@project_id, @mongoDocs[4]).should.equal true
-
-				@DocArchiveManager.archiveDoc.calledWith(@project_id, @mongoDocs[2]).should.equal false
-				@DocArchiveManager.archiveDoc.calledWith(@project_id, @mongoDocs[3]).should.equal false
+			});
+			this.md5 = crypto.createHash("md5").update(data).digest("hex");
+			this.request.put = sinon.stub().callsArgWith(1,  null, {statusCode:200,headers:{etag:this.md5}});
+			return this.DocArchiveManager.archiveDoc(this.project_id, this.mongoDocs[0], err=> {
+				should.not.exist(err);
+				return done();
+			});
+		});
+
+		return it("should return the error", function(done){
+			this.request.put = sinon.stub().callsArgWith(1, this.stubbedError, {statusCode:400,headers:{etag:""}});
+			return this.DocArchiveManager.archiveDoc(this.project_id, this.mongoDocs[0], err=> {
+				should.exist(err);
+				return done();
+			});
+		});
+	});
+
+	describe("unarchiveDoc", function() {
+
+		it("should use correct options", function(done){
+			this.request.get = sinon.stub().callsArgWith(1, null, {statusCode:200}, this.mongoDocs[0].lines);
+			this.request.del = sinon.stub().callsArgWith(1, null, {statusCode:204}, {});
+			return this.DocArchiveManager.unarchiveDoc(this.project_id, this.mongoDocs[0]._id, err=> {
+				const opts = this.request.get.args[0][0];
+				assert.deepEqual(opts.aws, {key:this.settings.docstore.s3.key, secret:this.settings.docstore.s3.secret, bucket:this.settings.docstore.s3.bucket});
+				opts.json.should.equal(true);
+				opts.timeout.should.equal((30*1000));
+				opts.uri.should.equal(`https://${this.settings.docstore.s3.bucket}.s3.amazonaws.com/${this.project_id}/${this.mongoDocs[0]._id}`);
+				return done();
+			});
+		});
+
+		it("should return the error", function(done){
+			this.request.get = sinon.stub().callsArgWith(1, this.stubbedError, {}, {});
+			return this.DocArchiveManager.unarchiveDoc(this.project_id, this.mongoDocs[0], err=> {
+				should.exist(err);
+				return done();
+			});
+		});
+
+		return it("should error if the doc lines are a string not an array", function(done){
+			this.request.get = sinon.stub().callsArgWith(1, null, {statusCode:200}, "this is a string");
+			this.request.del = sinon.stub();
+			return this.DocArchiveManager.unarchiveDoc(this.project_id, this.mongoDocs[0], err=> {
+				should.exist(err);
+				this.request.del.called.should.equal(false);
+				return done();
+			});
+		});
+	});
+
+	describe("archiveAllDocs", function() {
+
+		it("should archive all project docs which are not in s3", function(done){
+			this.MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, this.mongoDocs);
+			this.DocArchiveManager.archiveDoc = sinon.stub().callsArgWith(2, null);
+
+			return this.DocArchiveManager.archiveAllDocs(this.project_id, err=> {
+				this.DocArchiveManager.archiveDoc.calledWith(this.project_id, this.mongoDocs[0]).should.equal(true);
+				this.DocArchiveManager.archiveDoc.calledWith(this.project_id, this.mongoDocs[1]).should.equal(true);
+				this.DocArchiveManager.archiveDoc.calledWith(this.project_id, this.mongoDocs[4]).should.equal(true);
+
+				this.DocArchiveManager.archiveDoc.calledWith(this.project_id, this.mongoDocs[2]).should.equal(false);
+				this.DocArchiveManager.archiveDoc.calledWith(this.project_id, this.mongoDocs[3]).should.equal(false);
 				
-				should.not.exist err
-				done()
-
-		it "should return error if have no docs", (done)->
-			@MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, null)
-
-			@DocArchiveManager.archiveAllDocs @project_id, (err)=>
-				should.exist err
-				done()
-
-		it "should return the error", (done)->
-			@MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, @error, null)
-
-			@DocArchiveManager.archiveAllDocs @project_id, (err)=>
-				err.should.equal @error
-				done()
-
-		describe "when most have been already put in s3", ->
-
-			beforeEach ->
-				numberOfDocs = 10 * 1000
-				@mongoDocs = []
-				while --numberOfDocs != 0
-					@mongoDocs.push({inS3:true, _id: ObjectId()})
-
-				@MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, @mongoDocs)
-				@DocArchiveManager.archiveDoc = sinon.stub().callsArgWith(2, null)	
-
-			it "should not throw and error", (done)->
-				@DocArchiveManager.archiveAllDocs @project_id, (err)=>
-					should.not.exist err
-					done()
-
-
-	describe "unArchiveAllDocs", ->
-
-		it "should unarchive all inS3 docs", (done)->
-			@MongoManager.getArchivedProjectDocs = sinon.stub().callsArgWith(1, null, @archivedDocs)
-			@DocArchiveManager.unarchiveDoc = sinon.stub().callsArgWith(2, null)
-			@DocArchiveManager.unArchiveAllDocs @project_id, (err)=>
-				for doc in @archivedDocs
-					@DocArchiveManager.unarchiveDoc.calledWith(@project_id, doc._id).should.equal true
-				should.not.exist err
-				done()
-
-		it "should return error if have no docs", (done)->
-			@MongoManager.getArchivedProjectDocs = sinon.stub().callsArgWith(1, null, null)
-			@DocArchiveManager.unArchiveAllDocs @project_id, (err)=>
-				should.exist err
-				done()
-
-		it "should return the error", (done)->
-			@MongoManager.getArchivedProjectDocs = sinon.stub().callsArgWith(1, @error, null)
-			@DocArchiveManager.unArchiveAllDocs @project_id, (err)=>
-				err.should.equal @error
-				done()
-
-	describe "destroyAllDocs", ->
-		beforeEach ->
-			@request.del = sinon.stub().callsArgWith(1, null, statusCode:204, {})
-			@MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, @mixedDocs)
-			@MongoManager.findDoc = sinon.stub().callsArgWith(3, null, null)
-			@MongoManager.destroyDoc = sinon.stub().yields()
-			for doc in @mixedDocs
-				@MongoManager.findDoc.withArgs(@project_id, doc._id).callsArgWith(3, null, doc)
-
-		it "should destroy all the docs", (done)->
-			@DocArchiveManager.destroyDoc = sinon.stub().callsArgWith(2, null)
-			@DocArchiveManager.destroyAllDocs @project_id, (err)=>
-				for doc in @mixedDocs
-					@DocArchiveManager.destroyDoc.calledWith(@project_id, doc._id).should.equal true
-				should.not.exist err
-				done()
-
-		it "should only the s3 docs from s3", (done)->
-			docOpts = (doc) =>
-				JSON.parse(JSON.stringify({
-					aws: {key:@settings.docstore.s3.key, secret:@settings.docstore.s3.secret, bucket:@settings.docstore.s3.bucket},
+				should.not.exist(err);
+				return done();
+			});
+		});
+
+		it("should return error if have no docs", function(done){
+			this.MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, null);
+
+			return this.DocArchiveManager.archiveAllDocs(this.project_id, err=> {
+				should.exist(err);
+				return done();
+			});
+		});
+
+		it("should return the error", function(done){
+			this.MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, this.error, null);
+
+			return this.DocArchiveManager.archiveAllDocs(this.project_id, err=> {
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+
+		return describe("when most have been already put in s3", function() {
+
+			beforeEach(function() {
+				let numberOfDocs = 10 * 1000;
+				this.mongoDocs = [];
+				while (--numberOfDocs !== 0) {
+					this.mongoDocs.push({inS3:true, _id: ObjectId()});
+				}
+
+				this.MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, this.mongoDocs);
+				return this.DocArchiveManager.archiveDoc = sinon.stub().callsArgWith(2, null);
+			});	
+
+			return it("should not throw and error", function(done){
+				return this.DocArchiveManager.archiveAllDocs(this.project_id, err=> {
+					should.not.exist(err);
+					return done();
+				});
+			});
+		});
+	});
+
+
+	describe("unArchiveAllDocs", function() {
+
+		it("should unarchive all inS3 docs", function(done){
+			this.MongoManager.getArchivedProjectDocs = sinon.stub().callsArgWith(1, null, this.archivedDocs);
+			this.DocArchiveManager.unarchiveDoc = sinon.stub().callsArgWith(2, null);
+			return this.DocArchiveManager.unArchiveAllDocs(this.project_id, err=> {
+				for (let doc of Array.from(this.archivedDocs)) {
+					this.DocArchiveManager.unarchiveDoc.calledWith(this.project_id, doc._id).should.equal(true);
+				}
+				should.not.exist(err);
+				return done();
+			});
+		});
+
+		it("should return error if have no docs", function(done){
+			this.MongoManager.getArchivedProjectDocs = sinon.stub().callsArgWith(1, null, null);
+			return this.DocArchiveManager.unArchiveAllDocs(this.project_id, err=> {
+				should.exist(err);
+				return done();
+			});
+		});
+
+		return it("should return the error", function(done){
+			this.MongoManager.getArchivedProjectDocs = sinon.stub().callsArgWith(1, this.error, null);
+			return this.DocArchiveManager.unArchiveAllDocs(this.project_id, err=> {
+				err.should.equal(this.error);
+				return done();
+			});
+		});
+	});
+
+	describe("destroyAllDocs", function() {
+		beforeEach(function() {
+			this.request.del = sinon.stub().callsArgWith(1, null, {statusCode:204}, {});
+			this.MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, this.mixedDocs);
+			this.MongoManager.findDoc = sinon.stub().callsArgWith(3, null, null);
+			this.MongoManager.destroyDoc = sinon.stub().yields();
+			return Array.from(this.mixedDocs).map((doc) =>
+				this.MongoManager.findDoc.withArgs(this.project_id, doc._id).callsArgWith(3, null, doc));
+		});
+
+		it("should destroy all the docs", function(done){
+			this.DocArchiveManager.destroyDoc = sinon.stub().callsArgWith(2, null);
+			return this.DocArchiveManager.destroyAllDocs(this.project_id, err=> {
+				for (let doc of Array.from(this.mixedDocs)) {
+					this.DocArchiveManager.destroyDoc.calledWith(this.project_id, doc._id).should.equal(true);
+				}
+				should.not.exist(err);
+				return done();
+			});
+		});
+
+		it("should only the s3 docs from s3", function(done){
+			const docOpts = doc => {
+				return JSON.parse(JSON.stringify({
+					aws: {key:this.settings.docstore.s3.key, secret:this.settings.docstore.s3.secret, bucket:this.settings.docstore.s3.bucket},
 					json: true,
-					timeout: 30 * 1000
-					uri:"https://#{@settings.docstore.s3.bucket}.s3.amazonaws.com/#{@project_id}/#{doc._id}"
-				}))
-
-			@DocArchiveManager.destroyAllDocs @project_id, (err)=>
-				expect(err).not.to.exist
-
-				for doc in @archivedDocs
-					sinon.assert.calledWith(@request.del, docOpts(doc))
-				for doc in @unarchivedDocs
-					expect(@request.del.calledWith(docOpts(doc))).to.equal false  # no notCalledWith
-
-				done()
-
-		it "should remove the docs from mongo", (done)->
-			@DocArchiveManager.destroyAllDocs @project_id, (err)=>
-				expect(err).not.to.exist
-
-			for doc in @mixedDocs
-				sinon.assert.calledWith(@MongoManager.destroyDoc, doc._id)
-
-			done()
+					timeout: 30 * 1000,
+					uri:`https://${this.settings.docstore.s3.bucket}.s3.amazonaws.com/${this.project_id}/${doc._id}`
+				}));
+			};
+
+			return this.DocArchiveManager.destroyAllDocs(this.project_id, err=> {
+				let doc;
+				expect(err).not.to.exist;
+
+				for (doc of Array.from(this.archivedDocs)) {
+					sinon.assert.calledWith(this.request.del, docOpts(doc));
+				}
+				for (doc of Array.from(this.unarchivedDocs)) {
+					expect(this.request.del.calledWith(docOpts(doc))).to.equal(false);
+				}  // no notCalledWith
+
+				return done();
+			});
+		});
+
+		return it("should remove the docs from mongo", function(done){
+			this.DocArchiveManager.destroyAllDocs(this.project_id, err=> {
+				return expect(err).not.to.exist;
+			});
+
+			for (let doc of Array.from(this.mixedDocs)) {
+				sinon.assert.calledWith(this.MongoManager.destroyDoc, doc._id);
+			}
+
+			return done();
+		});
+	});
 	
-	describe "_s3DocToMongoDoc", ->
-		describe "with the old schema", ->
-			it "should return the docs lines", (done) ->
-				@DocArchiveManager._s3DocToMongoDoc ["doc", "lines"], (error, doc) ->
-					expect(doc).to.deep.equal {
-						lines: ["doc", "lines"]
-					}
-					done()
+	describe("_s3DocToMongoDoc", function() {
+		describe("with the old schema", () => it("should return the docs lines", function(done) {
+            return this.DocArchiveManager._s3DocToMongoDoc(["doc", "lines"], function(error, doc) {
+                expect(doc).to.deep.equal({
+                    lines: ["doc", "lines"]
+                });
+                return done();
+            });
+        }));
 		
-		describe "with the new schema", ->
-			it "should return the doc lines and ranges", (done) ->
-				@RangeManager.jsonRangesToMongo = sinon.stub().returns {"mongo": "ranges"}
-				@DocArchiveManager._s3DocToMongoDoc {
-					lines: ["doc", "lines"]
-					ranges: {"json": "ranges"}
+		describe("with the new schema", function() {
+			it("should return the doc lines and ranges", function(done) {
+				this.RangeManager.jsonRangesToMongo = sinon.stub().returns({"mongo": "ranges"});
+				return this.DocArchiveManager._s3DocToMongoDoc({
+					lines: ["doc", "lines"],
+					ranges: {"json": "ranges"},
 					schema_v: 1
-				}, (error, doc) ->
-					expect(doc).to.deep.equal {
-						lines: ["doc", "lines"]
+				}, function(error, doc) {
+					expect(doc).to.deep.equal({
+						lines: ["doc", "lines"],
 						ranges: {"mongo": "ranges"}
-					}
-					done()
+					});
+					return done();
+				});
+			});
 					
-			it "should return just the doc lines when there are no ranges", (done) ->
-				@DocArchiveManager._s3DocToMongoDoc {
-					lines: ["doc", "lines"]
+			return it("should return just the doc lines when there are no ranges", function(done) {
+				return this.DocArchiveManager._s3DocToMongoDoc({
+					lines: ["doc", "lines"],
 					schema_v: 1
-				}, (error, doc) ->
-					expect(doc).to.deep.equal {
+				}, function(error, doc) {
+					expect(doc).to.deep.equal({
 						lines: ["doc", "lines"]
-					}
-					done()
+					});
+					return done();
+				});
+			});
+		});
 		
-		describe "with an unrecognised schema", ->
-			it "should return an error", (done) ->
-				@DocArchiveManager._s3DocToMongoDoc {
-					schema_v: 2
-				}, (error, doc) ->
-					expect(error).to.exist
-					done()
+		return describe("with an unrecognised schema", () => it("should return an error", function(done) {
+            return this.DocArchiveManager._s3DocToMongoDoc({
+                schema_v: 2
+            }, function(error, doc) {
+                expect(error).to.exist;
+                return done();
+            });
+        }));
+	});
 	
-	describe "_mongoDocToS3Doc", ->
-		describe "with a valid doc", ->
-			it "should return the json version", (done) ->
-				@DocArchiveManager._mongoDocToS3Doc doc = {
-					lines: ["doc", "lines"]
-					ranges: { "mock": "ranges" }
-				}, (err, s3_doc) ->
-					expect(s3_doc).to.equal JSON.stringify({
-						lines: ["doc", "lines"]
-						ranges: { "mock": "ranges" }
-						schema_v: 1
-					})
-					done()
+	return describe("_mongoDocToS3Doc", function() {
+		describe("with a valid doc", () => it("should return the json version", function(done) {
+            let doc;
+            return this.DocArchiveManager._mongoDocToS3Doc((doc = {
+                lines: ["doc", "lines"],
+                ranges: { "mock": "ranges" }
+            }), function(err, s3_doc) {
+                expect(s3_doc).to.equal(JSON.stringify({
+                    lines: ["doc", "lines"],
+                    ranges: { "mock": "ranges" },
+                    schema_v: 1
+                })
+                );
+                return done();
+            });
+        }));
 			
-		describe "with null bytes in the result", ->
-			beforeEach ->
-				@_stringify = JSON.stringify
-				JSON.stringify = sinon.stub().returns '{"bad": "\u0000"}'
+		describe("with null bytes in the result", function() {
+			beforeEach(function() {
+				this._stringify = JSON.stringify;
+				return JSON.stringify = sinon.stub().returns('{"bad": "\u0000"}');
+			});
 			
-			afterEach ->
-				JSON.stringify = @_stringify
+			afterEach(function() {
+				return JSON.stringify = this._stringify;
+			});
 				
-			it "should return an error", (done) ->
-				@DocArchiveManager._mongoDocToS3Doc {
-					lines: ["doc", "lines"]
+			return it("should return an error", function(done) {
+				return this.DocArchiveManager._mongoDocToS3Doc({
+					lines: ["doc", "lines"],
 					ranges: { "mock": "ranges" }
-				}, (err, s3_doc) ->
-					expect(err).to.exist
-					done()
+				}, function(err, s3_doc) {
+					expect(err).to.exist;
+					return done();
+				});
+			});
+		});
 		
-		describe "without doc lines", ->
-			it "should return an error", (done) ->
-				@DocArchiveManager._mongoDocToS3Doc {}, (err, s3_doc) ->
-					expect(err).to.exist
-					done()
+		return describe("without doc lines", () => it("should return an error", function(done) {
+            return this.DocArchiveManager._mongoDocToS3Doc({}, function(err, s3_doc) {
+                expect(err).to.exist;
+                return done();
+            });
+        }));
+	});
+});
 			
 			

+ 518 - 388
services/docstore/test/unit/coffee/DocManagerTests.js

@@ -1,407 +1,537 @@
-SandboxedModule = require('sandboxed-module')
-sinon = require('sinon')
-chai = require('chai')
-assert = require("chai").assert
-chai.should()
-expect = chai.expect
-modulePath = require('path').join __dirname, '../../../app/js/DocManager'
-ObjectId = require("mongojs").ObjectId
-Errors = require "../../../app/js/Errors"
-
-describe "DocManager", ->
-	beforeEach ->
-		@DocManager = SandboxedModule.require modulePath, requires:
-			"./MongoManager": @MongoManager = {}
-			"./DocArchiveManager": @DocArchiveManager = {}
-			"./RangeManager": @RangeManager = {
-				jsonRangesToMongo: (r) -> r
-				shouldUpdateRanges: sinon.stub().returns false
-			}
-			"logger-sharelatex": @logger = 
-				log: sinon.stub()
-				warn:->
-				err:->
-		@doc_id = ObjectId().toString()
-		@project_id = ObjectId().toString()
-		@another_project_id = ObjectId().toString()
-		@callback = sinon.stub()
-		@stubbedError = new Error("blew up")
-
-
-	describe "checkDocExists", ->
-		beforeEach ->
-			@DocManager._getDoc = sinon.stub()
-
-		it "should call get doc with a quick filter", (done)->
-			@DocManager._getDoc.callsArgWith(3, null, {_id:@doc_id})
-			@DocManager.checkDocExists @project_id, @doc_id, (err, exist)=>
-				exist.should.equal true
-				@DocManager._getDoc.calledWith(@project_id, @doc_id, {_id:1, inS3:true}).should.equal true
-				done()
-
-		it "should return false when doc is not there", (done)->
-			@DocManager._getDoc.callsArgWith(3, null)
-			@DocManager.checkDocExists @project_id, @doc_id, (err, exist)=>
-				exist.should.equal false
-				done()
-
-		it "should return error when get doc errors", (done)->
-			@DocManager._getDoc.callsArgWith(3, "error")
-			@DocManager.checkDocExists @project_id, @doc_id, (err, exist)=>
-				err.should.equal "error"
-				done()
-
-	describe "getFullDoc", ->
-		beforeEach ->
-			@DocManager._getDoc = sinon.stub()
-			@doc = 
-				_id: @doc_id
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const SandboxedModule = require('sandboxed-module');
+const sinon = require('sinon');
+const chai = require('chai');
+const {
+    assert
+} = require("chai");
+chai.should();
+const {
+    expect
+} = chai;
+const modulePath = require('path').join(__dirname, '../../../app/js/DocManager');
+const {
+    ObjectId
+} = require("mongojs");
+const Errors = require("../../../app/js/Errors");
+
+describe("DocManager", function() {
+	beforeEach(function() {
+		this.DocManager = SandboxedModule.require(modulePath, { requires: {
+			"./MongoManager": (this.MongoManager = {}),
+			"./DocArchiveManager": (this.DocArchiveManager = {}),
+			"./RangeManager": (this.RangeManager = {
+				jsonRangesToMongo(r) { return r; },
+				shouldUpdateRanges: sinon.stub().returns(false)
+			}),
+			"logger-sharelatex": (this.logger = { 
+				log: sinon.stub(),
+				warn() {},
+				err() {}
+			})
+		}
+	}
+		);
+		this.doc_id = ObjectId().toString();
+		this.project_id = ObjectId().toString();
+		this.another_project_id = ObjectId().toString();
+		this.callback = sinon.stub();
+		return this.stubbedError = new Error("blew up");
+	});
+
+
+	describe("checkDocExists", function() {
+		beforeEach(function() {
+			return this.DocManager._getDoc = sinon.stub();
+		});
+
+		it("should call get doc with a quick filter", function(done){
+			this.DocManager._getDoc.callsArgWith(3, null, {_id:this.doc_id});
+			return this.DocManager.checkDocExists(this.project_id, this.doc_id, (err, exist)=> {
+				exist.should.equal(true);
+				this.DocManager._getDoc.calledWith(this.project_id, this.doc_id, {_id:1, inS3:true}).should.equal(true);
+				return done();
+			});
+		});
+
+		it("should return false when doc is not there", function(done){
+			this.DocManager._getDoc.callsArgWith(3, null);
+			return this.DocManager.checkDocExists(this.project_id, this.doc_id, (err, exist)=> {
+				exist.should.equal(false);
+				return done();
+			});
+		});
+
+		return it("should return error when get doc errors", function(done){
+			this.DocManager._getDoc.callsArgWith(3, "error");
+			return this.DocManager.checkDocExists(this.project_id, this.doc_id, (err, exist)=> {
+				err.should.equal("error");
+				return done();
+			});
+		});
+	});
+
+	describe("getFullDoc", function() {
+		beforeEach(function() {
+			this.DocManager._getDoc = sinon.stub();
+			return this.doc = { 
+				_id: this.doc_id,
 				lines:["2134"]
-
-		it "should call get doc with a quick filter", (done)->
-			@DocManager._getDoc.callsArgWith(3, null, @doc)
-			@DocManager.getFullDoc @project_id, @doc_id, (err, doc)=>
-				doc.should.equal @doc
-				@DocManager._getDoc.calledWith(@project_id, @doc_id, {lines: true, rev: true, deleted: true, version: true, ranges: true, inS3:true}).should.equal true
-				done()
+			};});
+
+		it("should call get doc with a quick filter", function(done){
+			this.DocManager._getDoc.callsArgWith(3, null, this.doc);
+			return this.DocManager.getFullDoc(this.project_id, this.doc_id, (err, doc)=> {
+				doc.should.equal(this.doc);
+				this.DocManager._getDoc.calledWith(this.project_id, this.doc_id, {lines: true, rev: true, deleted: true, version: true, ranges: true, inS3:true}).should.equal(true);
+				return done();
+			});
+		});
 	
-		it "should return error when get doc errors", (done)->
-			@DocManager._getDoc.callsArgWith(3, "error")
-			@DocManager.getFullDoc @project_id, @doc_id, (err, exist)=>
-				err.should.equal "error"
-				done()
-
-	describe "getRawDoc", ->
-
-		beforeEach ->
-			@DocManager._getDoc = sinon.stub()
-			@doc = 
-				lines:["2134"]
-
-		it "should call get doc with a quick filter", (done)->
-			@DocManager._getDoc.callsArgWith(3, null, @doc)
-			@DocManager.getDocLines @project_id, @doc_id, (err, doc)=>
-				doc.should.equal @doc
-				@DocManager._getDoc.calledWith(@project_id, @doc_id, {lines: true, inS3:true}).should.equal true
-				done()
+		return it("should return error when get doc errors", function(done){
+			this.DocManager._getDoc.callsArgWith(3, "error");
+			return this.DocManager.getFullDoc(this.project_id, this.doc_id, (err, exist)=> {
+				err.should.equal("error");
+				return done();
+			});
+		});
+	});
+
+	describe("getRawDoc", function() {
+
+		beforeEach(function() {
+			this.DocManager._getDoc = sinon.stub();
+			return this.doc = 
+				{lines:["2134"]};});
+
+		it("should call get doc with a quick filter", function(done){
+			this.DocManager._getDoc.callsArgWith(3, null, this.doc);
+			return this.DocManager.getDocLines(this.project_id, this.doc_id, (err, doc)=> {
+				doc.should.equal(this.doc);
+				this.DocManager._getDoc.calledWith(this.project_id, this.doc_id, {lines: true, inS3:true}).should.equal(true);
+				return done();
+			});
+		});
 	
-		it "should return error when get doc errors", (done)->
-			@DocManager._getDoc.callsArgWith(3, "error")
-			@DocManager.getDocLines @project_id, @doc_id, (err, exist)=>
-				err.should.equal "error"
-				done()
-
-
-
-	describe "getDoc", ->
-		beforeEach ->
-			@project = { name: "mock-project" }
-			@doc = { _id: @doc_id, project_id: @project_id, lines: ["mock-lines"] }
-			@version = 42
-			@MongoManager.findDoc = sinon.stub()
-			@MongoManager.getDocVersion = sinon.stub().yields(null, @version)
-
-		describe "when using a filter", ->
-			beforeEach ->
-				@MongoManager.findDoc.yields(null, @doc)
-
-			it "should error if inS3 is not set to true", (done)->
-				@DocManager._getDoc @project_id, @doc_id, {inS3: false}, (err)->
-					expect(err).to.exist
-					done()
-
-			it "should always get inS3 even when no filter is passed", (done)->
-				@DocManager._getDoc @project_id, @doc_id, undefined, (err)=>
-					@MongoManager.findDoc.called.should.equal false
-					expect(err).to.exist
-					done()
-
-			it "should not error if inS3 is set to true", (done)->
-				@DocManager._getDoc @project_id, @doc_id, {inS3: true}, (err)->
-					expect(err).to.not.exist
-					done()
-
-		describe "when the doc is in the doc collection", ->
-			beforeEach ->
-				@MongoManager.findDoc.yields(null, @doc)
-				@DocManager._getDoc @project_id, @doc_id, {version: true, inS3:true}, @callback
-
-			it "should get the doc from the doc collection", ->
-				@MongoManager.findDoc
-					.calledWith(@project_id, @doc_id)
-					.should.equal true
-
-			it "should get the doc version from the docOps collection", ->
-				@MongoManager.getDocVersion
-					.calledWith(@doc_id)
-					.should.equal true
+		return it("should return error when get doc errors", function(done){
+			this.DocManager._getDoc.callsArgWith(3, "error");
+			return this.DocManager.getDocLines(this.project_id, this.doc_id, (err, exist)=> {
+				err.should.equal("error");
+				return done();
+			});
+		});
+	});
+
+
+
+	describe("getDoc", function() {
+		beforeEach(function() {
+			this.project = { name: "mock-project" };
+			this.doc = { _id: this.doc_id, project_id: this.project_id, lines: ["mock-lines"] };
+			this.version = 42;
+			this.MongoManager.findDoc = sinon.stub();
+			return this.MongoManager.getDocVersion = sinon.stub().yields(null, this.version);
+		});
+
+		describe("when using a filter", function() {
+			beforeEach(function() {
+				return this.MongoManager.findDoc.yields(null, this.doc);
+			});
+
+			it("should error if inS3 is not set to true", function(done){
+				return this.DocManager._getDoc(this.project_id, this.doc_id, {inS3: false}, function(err){
+					expect(err).to.exist;
+					return done();
+				});
+			});
+
+			it("should always get inS3 even when no filter is passed", function(done){
+				return this.DocManager._getDoc(this.project_id, this.doc_id, undefined, err=> {
+					this.MongoManager.findDoc.called.should.equal(false);
+					expect(err).to.exist;
+					return done();
+				});
+			});
+
+			return it("should not error if inS3 is set to true", function(done){
+				return this.DocManager._getDoc(this.project_id, this.doc_id, {inS3: true}, function(err){
+					expect(err).to.not.exist;
+					return done();
+				});
+			});
+		});
+
+		describe("when the doc is in the doc collection", function() {
+			beforeEach(function() {
+				this.MongoManager.findDoc.yields(null, this.doc);
+				return this.DocManager._getDoc(this.project_id, this.doc_id, {version: true, inS3:true}, this.callback);
+			});
+
+			it("should get the doc from the doc collection", function() {
+				return this.MongoManager.findDoc
+					.calledWith(this.project_id, this.doc_id)
+					.should.equal(true);
+			});
+
+			it("should get the doc version from the docOps collection", function() {
+				return this.MongoManager.getDocVersion
+					.calledWith(this.doc_id)
+					.should.equal(true);
+			});
 			
-			it "should return the callback with the doc with the version", ->
-				@callback.called.should.equal true
-				doc = @callback.args[0][1]
-				doc.lines.should.equal @doc.lines
-				doc.version.should.equal @version
-
-		describe "without the version filter", ->
-			beforeEach ->
-				@MongoManager.findDoc.yields(null, @doc)
-				@DocManager._getDoc @project_id, @doc_id, {version: false, inS3:true}, @callback
-
-			it "should not get the doc version from the docOps collection", ->
-				@MongoManager.getDocVersion.called.should.equal false
+			return it("should return the callback with the doc with the version", function() {
+				this.callback.called.should.equal(true);
+				const doc = this.callback.args[0][1];
+				doc.lines.should.equal(this.doc.lines);
+				return doc.version.should.equal(this.version);
+			});
+		});
+
+		describe("without the version filter", function() {
+			beforeEach(function() {
+				this.MongoManager.findDoc.yields(null, this.doc);
+				return this.DocManager._getDoc(this.project_id, this.doc_id, {version: false, inS3:true}, this.callback);
+			});
+
+			return it("should not get the doc version from the docOps collection", function() {
+				return this.MongoManager.getDocVersion.called.should.equal(false);
+			});
+		});
 		
-		describe "when MongoManager.findDoc errors", ->
-			beforeEach ->
-				@MongoManager.findDoc.yields(@stubbedError)
-				@DocManager._getDoc @project_id, @doc_id, {version: true, inS3:true}, @callback
-
-			it "should return the error", ->
-				@callback.calledWith(@stubbedError).should.equal true
-
-		describe "when the doc is archived", ->
-			beforeEach -> 
-				@doc = { _id: @doc_id, project_id: @project_id, lines: ["mock-lines"], inS3: true }
-				@MongoManager.findDoc.yields(null, @doc)
-				@DocArchiveManager.unarchiveDoc = (project_id, doc_id, callback) =>
-					@doc.inS3 = false
-					callback()
-				sinon.spy @DocArchiveManager, "unarchiveDoc"
-				@DocManager._getDoc @project_id, @doc_id, {version: true, inS3:true}, @callback
-
-			it "should call the DocArchive to unarchive the doc", ->
-				@DocArchiveManager.unarchiveDoc.calledWith(@project_id, @doc_id).should.equal true
+		describe("when MongoManager.findDoc errors", function() {
+			beforeEach(function() {
+				this.MongoManager.findDoc.yields(this.stubbedError);
+				return this.DocManager._getDoc(this.project_id, this.doc_id, {version: true, inS3:true}, this.callback);
+			});
+
+			return it("should return the error", function() {
+				return this.callback.calledWith(this.stubbedError).should.equal(true);
+			});
+		});
+
+		describe("when the doc is archived", function() {
+			beforeEach(function() { 
+				this.doc = { _id: this.doc_id, project_id: this.project_id, lines: ["mock-lines"], inS3: true };
+				this.MongoManager.findDoc.yields(null, this.doc);
+				this.DocArchiveManager.unarchiveDoc = (project_id, doc_id, callback) => {
+					this.doc.inS3 = false;
+					return callback();
+				};
+				sinon.spy(this.DocArchiveManager, "unarchiveDoc");
+				return this.DocManager._getDoc(this.project_id, this.doc_id, {version: true, inS3:true}, this.callback);
+			});
+
+			it("should call the DocArchive to unarchive the doc", function() {
+				return this.DocArchiveManager.unarchiveDoc.calledWith(this.project_id, this.doc_id).should.equal(true);
+			});
 			
-			it "should look up the doc twice", ->
-				@MongoManager.findDoc.calledTwice.should.equal true
-
-			it "should return the doc", ->
-				@callback.calledWith(null, @doc).should.equal true
-
-		describe "when the doc does not exist in the docs collection", ->
-			beforeEach -> 
-				@MongoManager.findDoc = sinon.stub().yields(null, null)
-				@DocManager._getDoc @project_id, @doc_id, {version: true, inS3:true}, @callback
-
-			it "should return a NotFoundError", ->
-				@callback
-					.calledWith(sinon.match.has('message', "No such doc: #{@doc_id} in project #{@project_id}"))
-					.should.equal true
-
-	describe "getAllNonDeletedDocs", ->
-		describe "when the project exists", ->
-			beforeEach -> 
-				@docs = [{ _id: @doc_id, project_id: @project_id, lines: ["mock-lines"] }]
-				@MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, @docs)
-				@DocArchiveManager.unArchiveAllDocs = sinon.stub().callsArgWith(1, null, @docs)
-				@filter = { lines: true }
-				@DocManager.getAllNonDeletedDocs @project_id, @filter, @callback
-
-			it "should get the project from the database", ->
-				@MongoManager.getProjectsDocs
-					.calledWith(@project_id, {include_deleted: false}, @filter)
-					.should.equal true
-
-			it "should return the docs", ->
-				@callback.calledWith(null, @docs).should.equal true
-
-		describe "when there are no docs for the project", ->
-			beforeEach -> 
-				@MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, null)
-				@DocArchiveManager.unArchiveAllDocs = sinon.stub().callsArgWith(1, null)
-				@DocManager.getAllNonDeletedDocs @project_id, @filter, @callback
-
-			it "should return a NotFoundError", ->
-				@callback
-					.calledWith(sinon.match.has('message', "No docs for project #{@project_id}"))
-					.should.equal true
-
-	describe "deleteDoc", ->
-		describe "when the doc exists", ->
-			beforeEach ->
-				@lines = ["mock", "doc", "lines"]
-				@rev = 77
-				@DocManager.checkDocExists = sinon.stub().callsArgWith(2, null, true)
-				@MongoManager.markDocAsDeleted = sinon.stub().callsArg(2)
-				@DocManager.deleteDoc @project_id, @doc_id, @callback
-
-			it "should get the doc", ->
-				@DocManager.checkDocExists
-					.calledWith(@project_id, @doc_id)
-					.should.equal true
-
-			it "should mark doc as deleted", ->
-				@MongoManager.markDocAsDeleted
-					.calledWith(@project_id, @doc_id)
-					.should.equal true
-
-			it "should return the callback", ->
-				@callback.called.should.equal true
-
-		describe "when the doc does not exist", ->
-			beforeEach -> 
-				@DocManager.checkDocExists = sinon.stub().callsArgWith(2, null, false)
-				@DocManager.deleteDoc @project_id, @doc_id, @callback
-
-			it "should return a NotFoundError", ->
-				@callback
-					.calledWith(sinon.match.has('message', "No such project/doc to delete: #{@project_id}/#{@doc_id}"))
-					.should.equal true
-
-	describe "updateDoc", ->
-		beforeEach ->
-			@oldDocLines = ["old", "doc", "lines"]
-			@newDocLines = ["new", "doc", "lines"]
-			@originalRanges = {
+			it("should look up the doc twice", function() {
+				return this.MongoManager.findDoc.calledTwice.should.equal(true);
+			});
+
+			return it("should return the doc", function() {
+				return this.callback.calledWith(null, this.doc).should.equal(true);
+			});
+		});
+
+		return describe("when the doc does not exist in the docs collection", function() {
+			beforeEach(function() { 
+				this.MongoManager.findDoc = sinon.stub().yields(null, null);
+				return this.DocManager._getDoc(this.project_id, this.doc_id, {version: true, inS3:true}, this.callback);
+			});
+
+			return it("should return a NotFoundError", function() {
+				return this.callback
+					.calledWith(sinon.match.has('message', `No such doc: ${this.doc_id} in project ${this.project_id}`))
+					.should.equal(true);
+			});
+		});
+	});
+
+	describe("getAllNonDeletedDocs", function() {
+		describe("when the project exists", function() {
+			beforeEach(function() { 
+				this.docs = [{ _id: this.doc_id, project_id: this.project_id, lines: ["mock-lines"] }];
+				this.MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, this.docs);
+				this.DocArchiveManager.unArchiveAllDocs = sinon.stub().callsArgWith(1, null, this.docs);
+				this.filter = { lines: true };
+				return this.DocManager.getAllNonDeletedDocs(this.project_id, this.filter, this.callback);
+			});
+
+			it("should get the project from the database", function() {
+				return this.MongoManager.getProjectsDocs
+					.calledWith(this.project_id, {include_deleted: false}, this.filter)
+					.should.equal(true);
+			});
+
+			return it("should return the docs", function() {
+				return this.callback.calledWith(null, this.docs).should.equal(true);
+			});
+		});
+
+		return describe("when there are no docs for the project", function() {
+			beforeEach(function() { 
+				this.MongoManager.getProjectsDocs = sinon.stub().callsArgWith(3, null, null);
+				this.DocArchiveManager.unArchiveAllDocs = sinon.stub().callsArgWith(1, null);
+				return this.DocManager.getAllNonDeletedDocs(this.project_id, this.filter, this.callback);
+			});
+
+			return it("should return a NotFoundError", function() {
+				return this.callback
+					.calledWith(sinon.match.has('message', `No docs for project ${this.project_id}`))
+					.should.equal(true);
+			});
+		});
+	});
+
+	describe("deleteDoc", function() {
+		describe("when the doc exists", function() {
+			beforeEach(function() {
+				this.lines = ["mock", "doc", "lines"];
+				this.rev = 77;
+				this.DocManager.checkDocExists = sinon.stub().callsArgWith(2, null, true);
+				this.MongoManager.markDocAsDeleted = sinon.stub().callsArg(2);
+				return this.DocManager.deleteDoc(this.project_id, this.doc_id, this.callback);
+			});
+
+			it("should get the doc", function() {
+				return this.DocManager.checkDocExists
+					.calledWith(this.project_id, this.doc_id)
+					.should.equal(true);
+			});
+
+			it("should mark doc as deleted", function() {
+				return this.MongoManager.markDocAsDeleted
+					.calledWith(this.project_id, this.doc_id)
+					.should.equal(true);
+			});
+
+			return it("should return the callback", function() {
+				return this.callback.called.should.equal(true);
+			});
+		});
+
+		return describe("when the doc does not exist", function() {
+			beforeEach(function() { 
+				this.DocManager.checkDocExists = sinon.stub().callsArgWith(2, null, false);
+				return this.DocManager.deleteDoc(this.project_id, this.doc_id, this.callback);
+			});
+
+			return it("should return a NotFoundError", function() {
+				return this.callback
+					.calledWith(sinon.match.has('message', `No such project/doc to delete: ${this.project_id}/${this.doc_id}`))
+					.should.equal(true);
+			});
+		});
+	});
+
+	return describe("updateDoc", function() {
+		beforeEach(function() {
+			this.oldDocLines = ["old", "doc", "lines"];
+			this.newDocLines = ["new", "doc", "lines"];
+			this.originalRanges = {
 				changes: [{
-					id: ObjectId().toString()
-					op: { i: "foo", p: 3 }
-					meta:
-						user_id: ObjectId().toString()
+					id: ObjectId().toString(),
+					op: { i: "foo", p: 3 },
+					meta: {
+						user_id: ObjectId().toString(),
 						ts: new Date().toString()
+					}
 				}]
-			}
-			@newRanges = {
+			};
+			this.newRanges = {
 				changes: [{
-					id: ObjectId().toString()
-					op: { i: "bar", p: 6 }
-					meta:
-						user_id: ObjectId().toString()
+					id: ObjectId().toString(),
+					op: { i: "bar", p: 6 },
+					meta: {
+						user_id: ObjectId().toString(),
 						ts: new Date().toString()
+					}
 				}]
-			}
-			@version = 42
-			@doc = { _id: @doc_id, project_id: @project_id, lines: @oldDocLines, rev: @rev = 5, version: @version, ranges: @originalRanges }
-
-			@MongoManager.upsertIntoDocCollection = sinon.stub().callsArg(3)
-			@MongoManager.setDocVersion = sinon.stub().yields()
-			@DocManager._getDoc = sinon.stub()
-
-		describe "when only the doc lines have changed", ->
-			beforeEach ->
-				@DocManager._getDoc = sinon.stub().callsArgWith(3, null, @doc)
-				@DocManager.updateDoc @project_id, @doc_id, @newDocLines, @version, @originalRanges, @callback
-
-			it "should get the existing doc", ->
-				@DocManager._getDoc
-					.calledWith(@project_id, @doc_id, {version: true, rev: true, lines: true, version: true, ranges: true, inS3:true})
-					.should.equal true
-
-			it "should upsert the document to the doc collection", ->
-				@MongoManager.upsertIntoDocCollection
-					.calledWith(@project_id, @doc_id, {lines: @newDocLines})
-					.should.equal true
+			};
+			this.version = 42;
+			this.doc = { _id: this.doc_id, project_id: this.project_id, lines: this.oldDocLines, rev: (this.rev = 5), version: this.version, ranges: this.originalRanges };
+
+			this.MongoManager.upsertIntoDocCollection = sinon.stub().callsArg(3);
+			this.MongoManager.setDocVersion = sinon.stub().yields();
+			return this.DocManager._getDoc = sinon.stub();
+		});
+
+		describe("when only the doc lines have changed", function() {
+			beforeEach(function() {
+				this.DocManager._getDoc = sinon.stub().callsArgWith(3, null, this.doc);
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.newDocLines, this.version, this.originalRanges, this.callback);
+			});
+
+			it("should get the existing doc", function() {
+				return this.DocManager._getDoc
+					.calledWith(this.project_id, this.doc_id, {version: true, rev: true, lines: true, version: true, ranges: true, inS3:true})
+					.should.equal(true);
+			});
+
+			it("should upsert the document to the doc collection", function() {
+				return this.MongoManager.upsertIntoDocCollection
+					.calledWith(this.project_id, this.doc_id, {lines: this.newDocLines})
+					.should.equal(true);
+			});
 			
-			it "should not update the version", ->
-				@MongoManager.setDocVersion.called.should.equal false
-
-			it "should return the callback with the new rev", ->
-				@callback.calledWith(null, true, @rev + 1).should.equal true
-
-		describe "when the doc ranges have changed", ->
-			beforeEach ->
-				@DocManager._getDoc = sinon.stub().callsArgWith(3, null, @doc)
-				@RangeManager.shouldUpdateRanges.returns true
-				@DocManager.updateDoc @project_id, @doc_id, @oldDocLines, @version, @newRanges, @callback
-
-			it "should upsert the ranges", ->
-				@MongoManager.upsertIntoDocCollection
-					.calledWith(@project_id, @doc_id, {ranges: @newRanges})
-					.should.equal true
+			it("should not update the version", function() {
+				return this.MongoManager.setDocVersion.called.should.equal(false);
+			});
+
+			return it("should return the callback with the new rev", function() {
+				return this.callback.calledWith(null, true, this.rev + 1).should.equal(true);
+			});
+		});
+
+		describe("when the doc ranges have changed", function() {
+			beforeEach(function() {
+				this.DocManager._getDoc = sinon.stub().callsArgWith(3, null, this.doc);
+				this.RangeManager.shouldUpdateRanges.returns(true);
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.oldDocLines, this.version, this.newRanges, this.callback);
+			});
+
+			it("should upsert the ranges", function() {
+				return this.MongoManager.upsertIntoDocCollection
+					.calledWith(this.project_id, this.doc_id, {ranges: this.newRanges})
+					.should.equal(true);
+			});
 			
-			it "should not update the version", ->
-				@MongoManager.setDocVersion.called.should.equal false
-
-			it "should return the callback with the new rev", ->
-				@callback.calledWith(null, true, @rev + 1).should.equal true
-
-		describe "when only the version has changed", ->
-			beforeEach ->
-				@DocManager._getDoc = sinon.stub().callsArgWith(3, null, @doc)
-				@DocManager.updateDoc @project_id, @doc_id, @oldDocLines, @version + 1, @originalRanges, @callback
-
-			it "should not change the lines or ranges", ->
-				@MongoManager.upsertIntoDocCollection.called.should.equal false
+			it("should not update the version", function() {
+				return this.MongoManager.setDocVersion.called.should.equal(false);
+			});
+
+			return it("should return the callback with the new rev", function() {
+				return this.callback.calledWith(null, true, this.rev + 1).should.equal(true);
+			});
+		});
+
+		describe("when only the version has changed", function() {
+			beforeEach(function() {
+				this.DocManager._getDoc = sinon.stub().callsArgWith(3, null, this.doc);
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.oldDocLines, this.version + 1, this.originalRanges, this.callback);
+			});
+
+			it("should not change the lines or ranges", function() {
+				return this.MongoManager.upsertIntoDocCollection.called.should.equal(false);
+			});
 			
-			it "should update the version", ->
-				@MongoManager.setDocVersion
-					.calledWith(@doc_id, @version + 1)
-					.should.equal true
-
-			it "should return the callback with the old rev", ->
-				@callback.calledWith(null, true, @rev).should.equal true
-
-		describe "when the doc has not changed at all", ->
-			beforeEach ->
-				@DocManager._getDoc = sinon.stub().callsArgWith(3, null, @doc)
-				@DocManager.updateDoc @project_id, @doc_id, @oldDocLines, @version, @originalRanges, @callback
-
-			it "should not update the ranges or lines", ->
-				@MongoManager.upsertIntoDocCollection.called.should.equal false
+			it("should update the version", function() {
+				return this.MongoManager.setDocVersion
+					.calledWith(this.doc_id, this.version + 1)
+					.should.equal(true);
+			});
+
+			return it("should return the callback with the old rev", function() {
+				return this.callback.calledWith(null, true, this.rev).should.equal(true);
+			});
+		});
+
+		describe("when the doc has not changed at all", function() {
+			beforeEach(function() {
+				this.DocManager._getDoc = sinon.stub().callsArgWith(3, null, this.doc);
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.oldDocLines, this.version, this.originalRanges, this.callback);
+			});
+
+			it("should not update the ranges or lines", function() {
+				return this.MongoManager.upsertIntoDocCollection.called.should.equal(false);
+			});
 			
-			it "should not update the version", ->
-				@MongoManager.setDocVersion.called.should.equal false
-
-			it "should return the callback with the old rev and modified == false", ->
-				@callback.calledWith(null, false, @rev).should.equal true
-
-		describe "when the version is null", ->
-			beforeEach ->
-				@DocManager.updateDoc @project_id, @doc_id, @newDocLines, null, @originalRanges, @callback
-
-			it "should return an error", ->
-				@callback.calledWith(sinon.match.has('message', "no lines, version or ranges provided")).should.equal true
-
-		describe "when the lines are null", ->
-			beforeEach ->
-				@DocManager.updateDoc @project_id, @doc_id, null, @version, @originalRanges, @callback
-
-			it "should return an error", ->
-				@callback.calledWith(sinon.match.has('message', "no lines, version or ranges provided")).should.equal true
-
-		describe "when the ranges are null", ->
-			beforeEach ->
-				@DocManager.updateDoc @project_id, @doc_id, @newDocLines, @version, null, @callback
-
-			it "should return an error", ->
-				@callback.calledWith(sinon.match.has('message', "no lines, version or ranges provided")).should.equal true
-
-		describe "when there is a generic error getting the doc", ->
-			beforeEach ->
-				@error =  new Error("doc could not be found")
-				@DocManager._getDoc = sinon.stub().callsArgWith(3, @error, null, null)
-				@DocManager.updateDoc @project_id, @doc_id, @newDocLines, @version, @originalRanges, @callback
+			it("should not update the version", function() {
+				return this.MongoManager.setDocVersion.called.should.equal(false);
+			});
+
+			return it("should return the callback with the old rev and modified == false", function() {
+				return this.callback.calledWith(null, false, this.rev).should.equal(true);
+			});
+		});
+
+		describe("when the version is null", function() {
+			beforeEach(function() {
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.newDocLines, null, this.originalRanges, this.callback);
+			});
+
+			return it("should return an error", function() {
+				return this.callback.calledWith(sinon.match.has('message', "no lines, version or ranges provided")).should.equal(true);
+			});
+		});
+
+		describe("when the lines are null", function() {
+			beforeEach(function() {
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, null, this.version, this.originalRanges, this.callback);
+			});
+
+			return it("should return an error", function() {
+				return this.callback.calledWith(sinon.match.has('message', "no lines, version or ranges provided")).should.equal(true);
+			});
+		});
+
+		describe("when the ranges are null", function() {
+			beforeEach(function() {
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.newDocLines, this.version, null, this.callback);
+			});
+
+			return it("should return an error", function() {
+				return this.callback.calledWith(sinon.match.has('message', "no lines, version or ranges provided")).should.equal(true);
+			});
+		});
+
+		describe("when there is a generic error getting the doc", function() {
+			beforeEach(function() {
+				this.error =  new Error("doc could not be found");
+				this.DocManager._getDoc = sinon.stub().callsArgWith(3, this.error, null, null);
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.newDocLines, this.version, this.originalRanges, this.callback);
+			});
 			
-			it "should not upsert the document to the doc collection", ->
-				@MongoManager.upsertIntoDocCollection.called.should.equal false
-
-			it "should return the callback with the error", ->
-				@callback.calledWith(@error).should.equal true
-
-		describe "when the doc lines have not changed", ->
-			beforeEach ->
-				@DocManager._getDoc = sinon.stub().callsArgWith(3, null, @doc)
-				@DocManager.updateDoc @project_id, @doc_id, @oldDocLines.slice(), @version, @originalRanges, @callback
-
-			it "should not update the doc", ->
-				@MongoManager.upsertIntoDocCollection.called.should.equal false
-
-			it "should return the callback with the existing rev", ->
-				@callback.calledWith(null, false, @rev).should.equal true
-
-		describe "when the doc does not exist", ->
-			beforeEach ->
-				@DocManager._getDoc = sinon.stub().callsArgWith(3, null, null, null)
-				@DocManager.updateDoc @project_id, @doc_id, @newDocLines, @version, @originalRanges, @callback
+			it("should not upsert the document to the doc collection", function() {
+				return this.MongoManager.upsertIntoDocCollection.called.should.equal(false);
+			});
+
+			return it("should return the callback with the error", function() {
+				return this.callback.calledWith(this.error).should.equal(true);
+			});
+		});
+
+		describe("when the doc lines have not changed", function() {
+			beforeEach(function() {
+				this.DocManager._getDoc = sinon.stub().callsArgWith(3, null, this.doc);
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.oldDocLines.slice(), this.version, this.originalRanges, this.callback);
+			});
+
+			it("should not update the doc", function() {
+				return this.MongoManager.upsertIntoDocCollection.called.should.equal(false);
+			});
+
+			return it("should return the callback with the existing rev", function() {
+				return this.callback.calledWith(null, false, this.rev).should.equal(true);
+			});
+		});
+
+		return describe("when the doc does not exist", function() {
+			beforeEach(function() {
+				this.DocManager._getDoc = sinon.stub().callsArgWith(3, null, null, null);
+				return this.DocManager.updateDoc(this.project_id, this.doc_id, this.newDocLines, this.version, this.originalRanges, this.callback);
+			});
 			
-			it "should upsert the document to the doc collection", ->
-				@MongoManager.upsertIntoDocCollection
-					.calledWith(@project_id, @doc_id, {lines: @newDocLines, ranges: @originalRanges})
-					.should.equal true
+			it("should upsert the document to the doc collection", function() {
+				return this.MongoManager.upsertIntoDocCollection
+					.calledWith(this.project_id, this.doc_id, {lines: this.newDocLines, ranges: this.originalRanges})
+					.should.equal(true);
+			});
 				
-			it "should set the version", ->
-				@MongoManager.setDocVersion
-					.calledWith(@doc_id, @version)
-					.should.equal true
-
-			it "should return the callback with the new rev", ->
-				@callback.calledWith(null, true, 1).should.equal true
+			it("should set the version", function() {
+				return this.MongoManager.setDocVersion
+					.calledWith(this.doc_id, this.version)
+					.should.equal(true);
+			});
+
+			return it("should return the callback with the new rev", function() {
+				return this.callback.calledWith(null, true, 1).should.equal(true);
+			});
+		});
+	});
+});

+ 412 - 325
services/docstore/test/unit/coffee/HttpControllerTests.js

@@ -1,357 +1,444 @@
-SandboxedModule = require('sandboxed-module')
-assert = require("chai").assert
-sinon = require('sinon')
-chai = require('chai')
-chai.should()
-expect = chai.expect
-modulePath = require('path').join __dirname, '../../../app/js/HttpController'
-ObjectId = require("mongojs").ObjectId
-
-describe "HttpController", ->
-	beforeEach ->
-		@HttpController = SandboxedModule.require modulePath, requires:
-			"./DocManager": @DocManager = {}
-			"./DocArchiveManager": @DocArchiveManager = {}
-			"logger-sharelatex": @logger = { log: sinon.stub(), error: 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 SandboxedModule = require('sandboxed-module');
+const {
+    assert
+} = require("chai");
+const sinon = require('sinon');
+const chai = require('chai');
+chai.should();
+const {
+    expect
+} = chai;
+const modulePath = require('path').join(__dirname, '../../../app/js/HttpController');
+const {
+    ObjectId
+} = require("mongojs");
+
+describe("HttpController", function() {
+	beforeEach(function() {
+		this.HttpController = SandboxedModule.require(modulePath, { requires: {
+			"./DocManager": (this.DocManager = {}),
+			"./DocArchiveManager": (this.DocArchiveManager = {}),
+			"logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }),
 			"./HealthChecker": {}
-		@res = { send: sinon.stub(), json: sinon.stub(), setHeader:sinon.stub() }
-		@res.status = sinon.stub().returns(@res)
-		@req = { query:{}}
-		@next = sinon.stub()
-		@project_id = "mock-project-id"
-		@doc_id = "mock-doc-id"
-		@doc = {
-			_id: @doc_id
-			lines: ["mock", "lines", " here", "", "", " spaces "]
-			version: 42
-			rev: 5
 		}
-		@deletedDoc = {
-			deleted:true
-			_id: @doc_id
-			lines: ["mock", "lines", " here", "", "", " spaces "]
-			version: 42
+	});
+		this.res = { send: sinon.stub(), json: sinon.stub(), setHeader:sinon.stub() };
+		this.res.status = sinon.stub().returns(this.res);
+		this.req = { query:{}};
+		this.next = sinon.stub();
+		this.project_id = "mock-project-id";
+		this.doc_id = "mock-doc-id";
+		this.doc = {
+			_id: this.doc_id,
+			lines: ["mock", "lines", " here", "", "", " spaces "],
+			version: 42,
 			rev: 5
-		}
-
-	describe "getDoc", ->
-
-		describe "without deleted docs", ->
-			beforeEach ->
-				@req.params =
-					project_id: @project_id
-					doc_id: @doc_id
-				@DocManager.getFullDoc = sinon.stub().callsArgWith(2, null, @doc)
-				@HttpController.getDoc @req, @res, @next
-
-			it "should get the document with the version (including deleted)", ->
-				@DocManager.getFullDoc
-					.calledWith(@project_id, @doc_id)
-					.should.equal true
-
-			it "should return the doc as JSON", ->
-				@res.json
+		};
+		return this.deletedDoc = {
+			deleted:true,
+			_id: this.doc_id,
+			lines: ["mock", "lines", " here", "", "", " spaces "],
+			version: 42,
+			rev: 5
+		};});
+
+	describe("getDoc", function() {
+
+		describe("without deleted docs", function() {
+			beforeEach(function() {
+				this.req.params = {
+					project_id: this.project_id,
+					doc_id: this.doc_id
+				};
+				this.DocManager.getFullDoc = sinon.stub().callsArgWith(2, null, this.doc);
+				return this.HttpController.getDoc(this.req, this.res, this.next);
+			});
+
+			it("should get the document with the version (including deleted)", function() {
+				return this.DocManager.getFullDoc
+					.calledWith(this.project_id, this.doc_id)
+					.should.equal(true);
+			});
+
+			return it("should return the doc as JSON", function() {
+				return this.res.json
 					.calledWith({
-						_id: @doc_id
-						lines: @doc.lines
-						rev: @doc.rev
-						version: @doc.version
+						_id: this.doc_id,
+						lines: this.doc.lines,
+						rev: this.doc.rev,
+						version: this.doc.version
 					})
-					.should.equal true
-
-		describe "which is deleted", ->
-			beforeEach ->
-				@req.params =
-					project_id: @project_id
-					doc_id: @doc_id
-				@DocManager.getFullDoc = sinon.stub().callsArgWith(2, null, @deletedDoc)
-
-			it "should get the doc from the doc manager", ->
-				@HttpController.getDoc @req, @res, @next
-				@DocManager.getFullDoc.calledWith(@project_id, @doc_id).should.equal true
-
-			it "should return 404 if the query string delete is not set ", ->
-				@HttpController.getDoc @req, @res, @next
-				@res.send.calledWith(404).should.equal true
-
-			it "should return the doc as JSON if include_deleted is set to true", ->
-				@req.query.include_deleted = "true"
-				@HttpController.getDoc @req, @res, @next
-				@res.json
+					.should.equal(true);
+			});
+		});
+
+		return describe("which is deleted", function() {
+			beforeEach(function() {
+				this.req.params = {
+					project_id: this.project_id,
+					doc_id: this.doc_id
+				};
+				return this.DocManager.getFullDoc = sinon.stub().callsArgWith(2, null, this.deletedDoc);
+			});
+
+			it("should get the doc from the doc manager", function() {
+				this.HttpController.getDoc(this.req, this.res, this.next);
+				return this.DocManager.getFullDoc.calledWith(this.project_id, this.doc_id).should.equal(true);
+			});
+
+			it("should return 404 if the query string delete is not set ", function() {
+				this.HttpController.getDoc(this.req, this.res, this.next);
+				return this.res.send.calledWith(404).should.equal(true);
+			});
+
+			return it("should return the doc as JSON if include_deleted is set to true", function() {
+				this.req.query.include_deleted = "true";
+				this.HttpController.getDoc(this.req, this.res, this.next);
+				return this.res.json
 					.calledWith({
-						_id: @doc_id
-						lines: @doc.lines
-						rev: @doc.rev
-						deleted: true
-						version: @doc.version
+						_id: this.doc_id,
+						lines: this.doc.lines,
+						rev: this.doc.rev,
+						deleted: true,
+						version: this.doc.version
 					})
-					.should.equal true
-
-	describe "getRawDoc", ->
-		beforeEach ->
-			@req.params =
-				project_id: @project_id
-				doc_id: @doc_id
-			@DocManager.getDocLines = sinon.stub().callsArgWith(2, null, @doc)
-			@HttpController.getRawDoc @req, @res, @next
-
-		it "should get the document without the version", ->
-			@DocManager.getDocLines
-				.calledWith(@project_id, @doc_id)
-				.should.equal true
-
-		it "should set the content type header", ->
-			@res.setHeader.calledWith('content-type', 'text/plain').should.equal true
-
-		it "should send the raw version of the doc", ->
-			assert.deepEqual @res.send.args[0][0], "#{@doc.lines[0]}\n#{@doc.lines[1]}\n#{@doc.lines[2]}\n#{@doc.lines[3]}\n#{@doc.lines[4]}\n#{@doc.lines[5]}"
-
-	describe "getAllDocs", ->
-		describe "normally", ->
-			beforeEach ->
-				@req.params =
-					project_id: @project_id
-				@docs = [{
-					_id: ObjectId()
-					lines: ["mock", "lines", "one"]
+					.should.equal(true);
+			});
+		});
+	});
+
+	describe("getRawDoc", function() {
+		beforeEach(function() {
+			this.req.params = {
+				project_id: this.project_id,
+				doc_id: this.doc_id
+			};
+			this.DocManager.getDocLines = sinon.stub().callsArgWith(2, null, this.doc);
+			return this.HttpController.getRawDoc(this.req, this.res, this.next);
+		});
+
+		it("should get the document without the version", function() {
+			return this.DocManager.getDocLines
+				.calledWith(this.project_id, this.doc_id)
+				.should.equal(true);
+		});
+
+		it("should set the content type header", function() {
+			return this.res.setHeader.calledWith('content-type', 'text/plain').should.equal(true);
+		});
+
+		return it("should send the raw version of the doc", function() {
+			return assert.deepEqual(this.res.send.args[0][0], `${this.doc.lines[0]}\n${this.doc.lines[1]}\n${this.doc.lines[2]}\n${this.doc.lines[3]}\n${this.doc.lines[4]}\n${this.doc.lines[5]}`);
+		});
+	});
+
+	describe("getAllDocs", function() {
+		describe("normally", function() {
+			beforeEach(function() {
+				this.req.params =
+					{project_id: this.project_id};
+				this.docs = [{
+					_id: ObjectId(),
+					lines: ["mock", "lines", "one"],
 					rev: 2
 				}, {
-					_id: ObjectId()
-					lines: ["mock", "lines", "two"]
+					_id: ObjectId(),
+					lines: ["mock", "lines", "two"],
 					rev: 4
-				}]
-				@DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, @docs)
-				@HttpController.getAllDocs @req, @res, @next
-
-			it "should get all the (non-deleted) docs", ->
-				@DocManager.getAllNonDeletedDocs
-					.calledWith(@project_id, {lines: true, rev: true})
-					.should.equal true
-
-			it "should return the doc as JSON", ->
-				@res.json
+				}];
+				this.DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, this.docs);
+				return this.HttpController.getAllDocs(this.req, this.res, this.next);
+			});
+
+			it("should get all the (non-deleted) docs", function() {
+				return this.DocManager.getAllNonDeletedDocs
+					.calledWith(this.project_id, {lines: true, rev: true})
+					.should.equal(true);
+			});
+
+			return it("should return the doc as JSON", function() {
+				return this.res.json
 					.calledWith([{
-						_id:   @docs[0]._id.toString()
-						lines: @docs[0].lines
-						rev:   @docs[0].rev
+						_id:   this.docs[0]._id.toString(),
+						lines: this.docs[0].lines,
+						rev:   this.docs[0].rev
 					}, {
-						_id:   @docs[1]._id.toString()
-						lines: @docs[1].lines
-						rev:   @docs[1].rev
+						_id:   this.docs[1]._id.toString(),
+						lines: this.docs[1].lines,
+						rev:   this.docs[1].rev
 					}])
-					.should.equal true
-
-		describe "with a null doc", ->
-			beforeEach ->
-				@req.params =
-					project_id: @project_id
-				@docs = [{
-					_id: ObjectId()
-					lines: ["mock", "lines", "one"]
+					.should.equal(true);
+			});
+		});
+
+		return describe("with a null doc", function() {
+			beforeEach(function() {
+				this.req.params =
+					{project_id: this.project_id};
+				this.docs = [{
+					_id: ObjectId(),
+					lines: ["mock", "lines", "one"],
 					rev: 2
 				},
 				null,
 				{
-					_id: ObjectId()
-					lines: ["mock", "lines", "two"]
+					_id: ObjectId(),
+					lines: ["mock", "lines", "two"],
 					rev: 4
-				}]
-				@DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, @docs)
-				@HttpController.getAllDocs @req, @res, @next
+				}];
+				this.DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, this.docs);
+				return this.HttpController.getAllDocs(this.req, this.res, this.next);
+			});
 
-			it "should return the non null docs as JSON", ->
-				@res.json
+			it("should return the non null docs as JSON", function() {
+				return this.res.json
 					.calledWith([{
-						_id:   @docs[0]._id.toString()
-						lines: @docs[0].lines
-						rev:   @docs[0].rev
+						_id:   this.docs[0]._id.toString(),
+						lines: this.docs[0].lines,
+						rev:   this.docs[0].rev
 					}, {
-						_id:   @docs[2]._id.toString()
-						lines: @docs[2].lines
-						rev:   @docs[2].rev
+						_id:   this.docs[2]._id.toString(),
+						lines: this.docs[2].lines,
+						rev:   this.docs[2].rev
 					}])
-					.should.equal true
+					.should.equal(true);
+			});
 
-			it "should log out an error", ->
-				@logger.error
-					.calledWith(
-						err: sinon.match.has('message', "null doc")
-						project_id: @project_id
+			return it("should log out an error", function() {
+				return this.logger.error
+					.calledWith({
+						err: sinon.match.has('message', "null doc"),
+						project_id: this.project_id
+					},
 						"encountered null doc"
 					)
-					.should.equal true
-
-	describe "getAllRanges", ->
-		describe "normally", ->
-			beforeEach ->
-				@req.params =
-					project_id: @project_id
-				@docs = [{
-					_id: ObjectId()
-					ranges: {"mock_ranges": "one"}
-				}, {
-					_id: ObjectId()
-					ranges: {"mock_ranges": "two"}
-				}]
-				@DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, @docs)
-				@HttpController.getAllRanges @req, @res, @next
-
-			it "should get all the (non-deleted) doc ranges", ->
-				@DocManager.getAllNonDeletedDocs
-					.calledWith(@project_id, {ranges: true})
-					.should.equal true
-
-			it "should return the doc as JSON", ->
-				@res.json
-					.calledWith([{
-						_id:    @docs[0]._id.toString()
-						ranges: @docs[0].ranges
-					}, {
-						_id:    @docs[1]._id.toString()
-						ranges: @docs[1].ranges
-					}])
-					.should.equal true
-
-	describe "updateDoc", ->
-		beforeEach ->
-			@req.params =
-				project_id: @project_id
-				doc_id: @doc_id
-
-		describe "when the doc lines exist and were updated", ->
-			beforeEach ->
-				@req.body =
-					lines: @lines = ["hello", "world"]
-					version: @version = 42
-					ranges: @ranges = { changes: "mock" }
-				@DocManager.updateDoc = sinon.stub().yields(null, true, @rev = 5)
-				@HttpController.updateDoc @req, @res, @next
-
-			it "should update the document", ->
-				@DocManager.updateDoc
-					.calledWith(@project_id, @doc_id, @lines, @version, @ranges)
-					.should.equal true
-
-			it "should return a modified status", ->
-				@res.json
-					.calledWith(modified: true, rev: @rev)
-					.should.equal true
-
-		describe "when the doc lines exist and were not updated", ->
-			beforeEach ->
-				@req.body =
-					lines: @lines = ["hello", "world"]
-					version: @version = 42
+					.should.equal(true);
+			});
+		});
+	});
+
+	describe("getAllRanges", () => describe("normally", function() {
+        beforeEach(function() {
+            this.req.params =
+                {project_id: this.project_id};
+            this.docs = [{
+                _id: ObjectId(),
+                ranges: {"mock_ranges": "one"}
+            }, {
+                _id: ObjectId(),
+                ranges: {"mock_ranges": "two"}
+            }];
+            this.DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, this.docs);
+            return this.HttpController.getAllRanges(this.req, this.res, this.next);
+        });
+
+        it("should get all the (non-deleted) doc ranges", function() {
+            return this.DocManager.getAllNonDeletedDocs
+                .calledWith(this.project_id, {ranges: true})
+                .should.equal(true);
+        });
+
+        return it("should return the doc as JSON", function() {
+            return this.res.json
+                .calledWith([{
+                    _id:    this.docs[0]._id.toString(),
+                    ranges: this.docs[0].ranges
+                }, {
+                    _id:    this.docs[1]._id.toString(),
+                    ranges: this.docs[1].ranges
+                }])
+                .should.equal(true);
+        });
+    }));
+
+	describe("updateDoc", function() {
+		beforeEach(function() {
+			return this.req.params = {
+				project_id: this.project_id,
+				doc_id: this.doc_id
+			};
+		});
+
+		describe("when the doc lines exist and were updated", function() {
+			beforeEach(function() {
+				this.req.body = {
+					lines: (this.lines = ["hello", "world"]),
+					version: (this.version = 42),
+					ranges: (this.ranges = { changes: "mock" })
+				};
+				this.DocManager.updateDoc = sinon.stub().yields(null, true, (this.rev = 5));
+				return this.HttpController.updateDoc(this.req, this.res, this.next);
+			});
+
+			it("should update the document", function() {
+				return this.DocManager.updateDoc
+					.calledWith(this.project_id, this.doc_id, this.lines, this.version, this.ranges)
+					.should.equal(true);
+			});
+
+			return it("should return a modified status", function() {
+				return this.res.json
+					.calledWith({modified: true, rev: this.rev})
+					.should.equal(true);
+			});
+		});
+
+		describe("when the doc lines exist and were not updated", function() {
+			beforeEach(function() {
+				this.req.body = {
+					lines: (this.lines = ["hello", "world"]),
+					version: (this.version = 42),
 					ranges: {}
-				@DocManager.updateDoc = sinon.stub().yields(null, false, @rev = 5)
-				@HttpController.updateDoc @req, @res, @next
-
-			it "should return a modified status", ->
-				@res.json
-					.calledWith(modified: false, rev: @rev)
-					.should.equal true
-
-		describe "when the doc lines are not provided", ->
-			beforeEach ->
-				@req.body = { version: 42, ranges: {} }
-				@DocManager.updateDoc = sinon.stub().yields(null, false)
-				@HttpController.updateDoc @req, @res, @next
-
-			it "should not update the document", ->
-				@DocManager.updateDoc.called.should.equal false
-
-			it "should return a 400 (bad request) response", ->
-				@res.send
+				};
+				this.DocManager.updateDoc = sinon.stub().yields(null, false, (this.rev = 5));
+				return this.HttpController.updateDoc(this.req, this.res, this.next);
+			});
+
+			return it("should return a modified status", function() {
+				return this.res.json
+					.calledWith({modified: false, rev: this.rev})
+					.should.equal(true);
+			});
+		});
+
+		describe("when the doc lines are not provided", function() {
+			beforeEach(function() {
+				this.req.body = { version: 42, ranges: {} };
+				this.DocManager.updateDoc = sinon.stub().yields(null, false);
+				return this.HttpController.updateDoc(this.req, this.res, this.next);
+			});
+
+			it("should not update the document", function() {
+				return this.DocManager.updateDoc.called.should.equal(false);
+			});
+
+			return it("should return a 400 (bad request) response", function() {
+				return this.res.send
 					.calledWith(400)
-					.should.equal true
-
-		describe "when the doc version are not provided", ->
-			beforeEach ->
-				@req.body = { version: 42, lines: ["hello world"] }
-				@DocManager.updateDoc = sinon.stub().yields(null, false)
-				@HttpController.updateDoc @req, @res, @next
-
-			it "should not update the document", ->
-				@DocManager.updateDoc.called.should.equal false
-
-			it "should return a 400 (bad request) response", ->
-				@res.send
+					.should.equal(true);
+			});
+		});
+
+		describe("when the doc version are not provided", function() {
+			beforeEach(function() {
+				this.req.body = { version: 42, lines: ["hello world"] };
+				this.DocManager.updateDoc = sinon.stub().yields(null, false);
+				return this.HttpController.updateDoc(this.req, this.res, this.next);
+			});
+
+			it("should not update the document", function() {
+				return this.DocManager.updateDoc.called.should.equal(false);
+			});
+
+			return it("should return a 400 (bad request) response", function() {
+				return this.res.send
 					.calledWith(400)
-					.should.equal true
-
-		describe "when the doc ranges is not provided", ->
-			beforeEach ->
-				@req.body = { lines : [ "foo" ], version: 42 }
-				@DocManager.updateDoc = sinon.stub().yields(null, false)
-				@HttpController.updateDoc @req, @res, @next
-
-			it "should not update the document", ->
-				@DocManager.updateDoc.called.should.equal false
-
-			it "should return a 400 (bad request) response", ->
-				@res.send
+					.should.equal(true);
+			});
+		});
+
+		describe("when the doc ranges is not provided", function() {
+			beforeEach(function() {
+				this.req.body = { lines : [ "foo" ], version: 42 };
+				this.DocManager.updateDoc = sinon.stub().yields(null, false);
+				return this.HttpController.updateDoc(this.req, this.res, this.next);
+			});
+
+			it("should not update the document", function() {
+				return this.DocManager.updateDoc.called.should.equal(false);
+			});
+
+			return it("should return a 400 (bad request) response", function() {
+				return this.res.send
 					.calledWith(400)
-					.should.equal true
-
-		describe "when the doc body is too large", ->
-			beforeEach ->
-				@req.body =
-					lines: @lines = Array(2049).fill('a'.repeat(1024))
-					version: @version = 42
-					ranges: @ranges = { changes: "mock" }
-				@HttpController.updateDoc @req, @res, @next
-
-			it "should return a 413 (too large) response", ->
-				sinon.assert.calledWith(@res.status, 413)
-
-			it "should report that the document body is too large", ->
-				sinon.assert.calledWith(@res.send, "document body too large")
-
-	describe "deleteDoc", ->
-		beforeEach ->
-			@req.params =
-				project_id: @project_id
-				doc_id: @doc_id
-			@DocManager.deleteDoc = sinon.stub().callsArg(2)
-			@HttpController.deleteDoc @req, @res, @next
-
-		it "should delete the document", ->
-			@DocManager.deleteDoc
-				.calledWith(@project_id, @doc_id)
-				.should.equal true
-
-		it "should return a 204 (No Content)", ->
-			@res.send
+					.should.equal(true);
+			});
+		});
+
+		return describe("when the doc body is too large", function() {
+			beforeEach(function() {
+				this.req.body = {
+					lines: (this.lines = Array(2049).fill('a'.repeat(1024))),
+					version: (this.version = 42),
+					ranges: (this.ranges = { changes: "mock" })
+				};
+				return this.HttpController.updateDoc(this.req, this.res, this.next);
+			});
+
+			it("should return a 413 (too large) response", function() {
+				return sinon.assert.calledWith(this.res.status, 413);
+			});
+
+			return it("should report that the document body is too large", function() {
+				return sinon.assert.calledWith(this.res.send, "document body too large");
+			});
+		});
+	});
+
+	describe("deleteDoc", function() {
+		beforeEach(function() {
+			this.req.params = {
+				project_id: this.project_id,
+				doc_id: this.doc_id
+			};
+			this.DocManager.deleteDoc = sinon.stub().callsArg(2);
+			return this.HttpController.deleteDoc(this.req, this.res, this.next);
+		});
+
+		it("should delete the document", function() {
+			return this.DocManager.deleteDoc
+				.calledWith(this.project_id, this.doc_id)
+				.should.equal(true);
+		});
+
+		return it("should return a 204 (No Content)", function() {
+			return this.res.send
 				.calledWith(204)
-				.should.equal true
-
-	describe "archiveAllDocs", ->
-		beforeEach ->
-			@req.params =
-				project_id: @project_id
-			@DocArchiveManager.archiveAllDocs = sinon.stub().callsArg(1)
-			@HttpController.archiveAllDocs @req, @res, @next
-
-		it "should archive the project", ->
-			@DocArchiveManager.archiveAllDocs
-				.calledWith(@project_id)
-				.should.equal true
-
-		it "should return a 204 (No Content)", ->
-			@res.send
+				.should.equal(true);
+		});
+	});
+
+	describe("archiveAllDocs", function() {
+		beforeEach(function() {
+			this.req.params =
+				{project_id: this.project_id};
+			this.DocArchiveManager.archiveAllDocs = sinon.stub().callsArg(1);
+			return this.HttpController.archiveAllDocs(this.req, this.res, this.next);
+		});
+
+		it("should archive the project", function() {
+			return this.DocArchiveManager.archiveAllDocs
+				.calledWith(this.project_id)
+				.should.equal(true);
+		});
+
+		return it("should return a 204 (No Content)", function() {
+			return this.res.send
 				.calledWith(204)
-				.should.equal true
-
-	describe "destroyAllDocs", ->
-		beforeEach ->
-			@req.params =
-				project_id: @project_id
-			@DocArchiveManager.destroyAllDocs = sinon.stub().callsArg(1)
-			@HttpController.destroyAllDocs @req, @res, @next
-
-		it "should destroy the docs", ->
-			sinon.assert.calledWith(@DocArchiveManager.destroyAllDocs, @project_id)
-
-		it "should return 204", ->
-			sinon.assert.calledWith(@res.send, 204)
+				.should.equal(true);
+		});
+	});
+
+	return describe("destroyAllDocs", function() {
+		beforeEach(function() {
+			this.req.params =
+				{project_id: this.project_id};
+			this.DocArchiveManager.destroyAllDocs = sinon.stub().callsArg(1);
+			return this.HttpController.destroyAllDocs(this.req, this.res, this.next);
+		});
+
+		it("should destroy the docs", function() {
+			return sinon.assert.calledWith(this.DocArchiveManager.destroyAllDocs, this.project_id);
+		});
+
+		return it("should return 204", function() {
+			return sinon.assert.calledWith(this.res.send, 204);
+		});
+	});
+});
 

+ 212 - 155
services/docstore/test/unit/coffee/MongoManagerTests.js

@@ -1,168 +1,225 @@
-SandboxedModule = require('sandboxed-module')
-sinon = require('sinon')
-require('chai').should()
-modulePath = require('path').join __dirname, '../../../app/js/MongoManager'
-ObjectId = require("mongojs").ObjectId
-assert = require("chai").assert
-
-describe "MongoManager", ->
-	beforeEach ->
-		@MongoManager = SandboxedModule.require modulePath, requires:
-			"./mongojs":
-				db: @db = { docs: {}, docOps: {} }
-				ObjectId: ObjectId
-			'metrics-sharelatex': {timeAsyncMethod: sinon.stub()}
-			'logger-sharelatex': {log: ()->}
-		@project_id = ObjectId().toString()
-		@doc_id = ObjectId().toString()
-		@callback = sinon.stub()
-		@stubbedErr = new Error("hello world")
-
-	describe "findDoc", ->
-		beforeEach ->
-			@doc = { name: "mock-doc"}
-			@db.docs.find = sinon.stub().callsArgWith(2, null, [@doc])
-			@filter = { lines: true }
-			@MongoManager.findDoc @project_id, @doc_id, @filter, @callback
-
-		it "should find the doc", ->
-			@db.docs.find
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const SandboxedModule = require('sandboxed-module');
+const sinon = require('sinon');
+require('chai').should();
+const modulePath = require('path').join(__dirname, '../../../app/js/MongoManager');
+const {
+    ObjectId
+} = require("mongojs");
+const {
+    assert
+} = require("chai");
+
+describe("MongoManager", function() {
+	beforeEach(function() {
+		this.MongoManager = SandboxedModule.require(modulePath, { requires: {
+			"./mongojs": {
+				db: (this.db = { docs: {}, docOps: {} }),
+				ObjectId
+			},
+			'metrics-sharelatex': {timeAsyncMethod: sinon.stub()},
+			'logger-sharelatex': {log(){}}
+		}
+	});
+		this.project_id = ObjectId().toString();
+		this.doc_id = ObjectId().toString();
+		this.callback = sinon.stub();
+		return this.stubbedErr = new Error("hello world");
+	});
+
+	describe("findDoc", function() {
+		beforeEach(function() {
+			this.doc = { name: "mock-doc"};
+			this.db.docs.find = sinon.stub().callsArgWith(2, null, [this.doc]);
+			this.filter = { lines: true };
+			return this.MongoManager.findDoc(this.project_id, this.doc_id, this.filter, this.callback);
+		});
+
+		it("should find the doc", function() {
+			return this.db.docs.find
 				.calledWith({
-					_id: ObjectId(@doc_id)
-					project_id: ObjectId(@project_id)
-				}, @filter)
-				.should.equal true
-
-		it "should call the callback with the doc", ->
-			@callback.calledWith(null, @doc).should.equal true
-
-	describe "getProjectsDocs", ->
-		beforeEach ->
-			@filter = {lines: true}
-			@doc1 = { name: "mock-doc1" }
-			@doc2 = { name: "mock-doc2" }
-			@doc3 = { name: "mock-doc3" }
-			@doc4 = { name: "mock-doc4" }
-			@db.docs.find = sinon.stub().callsArgWith(2, null, [@doc, @doc3, @doc4])
+					_id: ObjectId(this.doc_id),
+					project_id: ObjectId(this.project_id)
+				}, this.filter)
+				.should.equal(true);
+		});
+
+		return it("should call the callback with the doc", function() {
+			return this.callback.calledWith(null, this.doc).should.equal(true);
+		});
+	});
+
+	describe("getProjectsDocs", function() {
+		beforeEach(function() {
+			this.filter = {lines: true};
+			this.doc1 = { name: "mock-doc1" };
+			this.doc2 = { name: "mock-doc2" };
+			this.doc3 = { name: "mock-doc3" };
+			this.doc4 = { name: "mock-doc4" };
+			return this.db.docs.find = sinon.stub().callsArgWith(2, null, [this.doc, this.doc3, this.doc4]);
+		});
 		
-		describe "with included_deleted = false", ->
-			beforeEach -> 
-				@MongoManager.getProjectsDocs @project_id, include_deleted: false, @filter, @callback
+		describe("with included_deleted = false", function() {
+			beforeEach(function() { 
+				return this.MongoManager.getProjectsDocs(this.project_id, {include_deleted: false}, this.filter, this.callback);
+			});
 
-			it "should find the non-deleted docs via the project_id", ->
-				@db.docs.find
+			it("should find the non-deleted docs via the project_id", function() {
+				return this.db.docs.find
 					.calledWith({
-						project_id: ObjectId(@project_id)
+						project_id: ObjectId(this.project_id),
 						deleted: { $ne: true }
-					}, @filter)
-					.should.equal true
-
-			it "should call the callback with the docs", ->
-				@callback.calledWith(null, [@doc, @doc3, @doc4]).should.equal true
+					}, this.filter)
+					.should.equal(true);
+			});
+
+			return it("should call the callback with the docs", function() {
+				return this.callback.calledWith(null, [this.doc, this.doc3, this.doc4]).should.equal(true);
+			});
+		});
 				
-		describe "with included_deleted = true", ->
-			beforeEach ->
-				@MongoManager.getProjectsDocs @project_id, include_deleted: true, @filter, @callback
+		return describe("with included_deleted = true", function() {
+			beforeEach(function() {
+				return this.MongoManager.getProjectsDocs(this.project_id, {include_deleted: true}, this.filter, this.callback);
+			});
 
-			it "should find all via the project_id", ->
-				@db.docs.find
+			it("should find all via the project_id", function() {
+				return this.db.docs.find
 					.calledWith({
-						project_id: ObjectId(@project_id)
-					}, @filter)
-					.should.equal true
-
-			it "should call the callback with the docs", ->
-				@callback.calledWith(null, [@doc, @doc3, @doc4]).should.equal true
-
-	describe "upsertIntoDocCollection", ->
-		beforeEach ->
-			@db.docs.update = sinon.stub().callsArgWith(3, @stubbedErr)
-			@oldRev = 77
-
-		it "should upsert the document", (done)->	
-			@MongoManager.upsertIntoDocCollection @project_id, @doc_id, {@lines}, (err)=>
-				args = @db.docs.update.args[0]
-				assert.deepEqual args[0], {_id: ObjectId(@doc_id)}
-				assert.equal args[1]["$set"]["lines"], @lines
-				assert.equal args[1]["$inc"]["rev"], 1
-				assert.deepEqual args[1]["$set"]["project_id"], ObjectId(@project_id)
-				done()
-
-		it "should return the error", (done)->
-			@MongoManager.upsertIntoDocCollection @project_id, @doc_id, {@lines}, (err)=>
-				err.should.equal @stubbedErr
-				done()
-
-	describe "markDocAsDeleted", ->
-		beforeEach ->
-			@db.docs.update = sinon.stub().callsArgWith(2, @stubbedErr)
-			@oldRev = 77
-
-		it "should process the update", (done) ->
-			@MongoManager.markDocAsDeleted @project_id, @doc_id, (err)=>
-				args = @db.docs.update.args[0]
-				assert.deepEqual args[0], {_id: ObjectId(@doc_id), project_id: ObjectId(@project_id)}
-				assert.equal args[1]["$set"]["deleted"], true
-				done()
-
-		it "should return the error", (done)->
-			@MongoManager.markDocAsDeleted @project_id, @doc_id, (err)=>
-				err.should.equal @stubbedErr
-				done()
-
-	describe "destroyDoc", ->
-		beforeEach (done) ->
-			@db.docs.remove = sinon.stub().yields()
-			@db.docOps.remove = sinon.stub().yields()
-			@MongoManager.destroyDoc '123456789012', done
-
-		it "should destroy the doc", ->
-			sinon.assert.calledWith(@db.docs.remove, {_id: ObjectId('123456789012')})
-
-		it "should destroy the docOps", ->
-			sinon.assert.calledWith(@db.docOps.remove, {doc_id: ObjectId('123456789012')})
-
-	describe "getDocVersion", ->
-		describe "when the doc exists", ->
-			beforeEach ->
-				@doc =
-					version: @version = 42
-				@db.docOps.find = sinon.stub().callsArgWith(2, null, [@doc])
-				@MongoManager.getDocVersion @doc_id, @callback
-
-			it "should look for the doc in the database", ->
-				@db.docOps.find
-					.calledWith({ doc_id: ObjectId(@doc_id) }, {version: 1})
-					.should.equal true
-
-			it "should call the callback with the version", ->
-				@callback.calledWith(null, @version).should.equal true
-
-		describe "when the doc doesn't exist", ->
-			beforeEach ->
-				@db.docOps.find = sinon.stub().callsArgWith(2, null, [])
-				@MongoManager.getDocVersion @doc_id, @callback
-
-			it "should call the callback with 0", ->
-				@callback.calledWith(null, 0).should.equal true
-
-	describe "setDocVersion", ->
-		beforeEach ->
-			@version = 42
-			@db.docOps.update = sinon.stub().callsArg(3)
-			@MongoManager.setDocVersion @doc_id, @version, @callback
-
-		it "should update the doc version", ->
-			@db.docOps.update
+						project_id: ObjectId(this.project_id)
+					}, this.filter)
+					.should.equal(true);
+			});
+
+			return it("should call the callback with the docs", function() {
+				return this.callback.calledWith(null, [this.doc, this.doc3, this.doc4]).should.equal(true);
+			});
+		});
+	});
+
+	describe("upsertIntoDocCollection", function() {
+		beforeEach(function() {
+			this.db.docs.update = sinon.stub().callsArgWith(3, this.stubbedErr);
+			return this.oldRev = 77;
+		});
+
+		it("should upsert the document", function(done){	
+			return this.MongoManager.upsertIntoDocCollection(this.project_id, this.doc_id, {lines: this.lines}, err=> {
+				const args = this.db.docs.update.args[0];
+				assert.deepEqual(args[0], {_id: ObjectId(this.doc_id)});
+				assert.equal(args[1]["$set"]["lines"], this.lines);
+				assert.equal(args[1]["$inc"]["rev"], 1);
+				assert.deepEqual(args[1]["$set"]["project_id"], ObjectId(this.project_id));
+				return done();
+			});
+		});
+
+		return it("should return the error", function(done){
+			return this.MongoManager.upsertIntoDocCollection(this.project_id, this.doc_id, {lines: this.lines}, err=> {
+				err.should.equal(this.stubbedErr);
+				return done();
+			});
+		});
+	});
+
+	describe("markDocAsDeleted", function() {
+		beforeEach(function() {
+			this.db.docs.update = sinon.stub().callsArgWith(2, this.stubbedErr);
+			return this.oldRev = 77;
+		});
+
+		it("should process the update", function(done) {
+			return this.MongoManager.markDocAsDeleted(this.project_id, this.doc_id, err=> {
+				const args = this.db.docs.update.args[0];
+				assert.deepEqual(args[0], {_id: ObjectId(this.doc_id), project_id: ObjectId(this.project_id)});
+				assert.equal(args[1]["$set"]["deleted"], true);
+				return done();
+			});
+		});
+
+		return it("should return the error", function(done){
+			return this.MongoManager.markDocAsDeleted(this.project_id, this.doc_id, err=> {
+				err.should.equal(this.stubbedErr);
+				return done();
+			});
+		});
+	});
+
+	describe("destroyDoc", function() {
+		beforeEach(function(done) {
+			this.db.docs.remove = sinon.stub().yields();
+			this.db.docOps.remove = sinon.stub().yields();
+			return this.MongoManager.destroyDoc('123456789012', done);
+		});
+
+		it("should destroy the doc", function() {
+			return sinon.assert.calledWith(this.db.docs.remove, {_id: ObjectId('123456789012')});
+		});
+
+		return it("should destroy the docOps", function() {
+			return sinon.assert.calledWith(this.db.docOps.remove, {doc_id: ObjectId('123456789012')});
+		});
+	});
+
+	describe("getDocVersion", function() {
+		describe("when the doc exists", function() {
+			beforeEach(function() {
+				this.doc =
+					{version: (this.version = 42)};
+				this.db.docOps.find = sinon.stub().callsArgWith(2, null, [this.doc]);
+				return this.MongoManager.getDocVersion(this.doc_id, this.callback);
+			});
+
+			it("should look for the doc in the database", function() {
+				return this.db.docOps.find
+					.calledWith({ doc_id: ObjectId(this.doc_id) }, {version: 1})
+					.should.equal(true);
+			});
+
+			return it("should call the callback with the version", function() {
+				return this.callback.calledWith(null, this.version).should.equal(true);
+			});
+		});
+
+		return describe("when the doc doesn't exist", function() {
+			beforeEach(function() {
+				this.db.docOps.find = sinon.stub().callsArgWith(2, null, []);
+				return this.MongoManager.getDocVersion(this.doc_id, this.callback);
+			});
+
+			return it("should call the callback with 0", function() {
+				return this.callback.calledWith(null, 0).should.equal(true);
+			});
+		});
+	});
+
+	return describe("setDocVersion", function() {
+		beforeEach(function() {
+			this.version = 42;
+			this.db.docOps.update = sinon.stub().callsArg(3);
+			return this.MongoManager.setDocVersion(this.doc_id, this.version, this.callback);
+		});
+
+		it("should update the doc version", function() {
+			return this.db.docOps.update
 				.calledWith({
-					doc_id: ObjectId(@doc_id)
+					doc_id: ObjectId(this.doc_id)
 				}, {
-					$set:
-						version: @version
+					$set: {
+						version: this.version
+					}
 				}, {
 					upsert: true 
 				})
-				.should.equal true
-
-		it "should call the callback", ->
-			@callback.called.should.equal true
+				.should.equal(true);
+		});
+
+		return it("should call the callback", function() {
+			return this.callback.called.should.equal(true);
+		});
+	});
+});

+ 151 - 114
services/docstore/test/unit/coffee/RangeManagerTests.js

@@ -1,155 +1,192 @@
-SandboxedModule = require('sandboxed-module')
-sinon = require('sinon')
-require('chai').should()
-expect = require('chai').expect
-modulePath = require('path').join __dirname, '../../../app/js/RangeManager'
-ObjectId = require("mongojs").ObjectId
-assert = require("chai").assert
-_ = require "underscore"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const SandboxedModule = require('sandboxed-module');
+const sinon = require('sinon');
+require('chai').should();
+const {
+    expect
+} = require('chai');
+const modulePath = require('path').join(__dirname, '../../../app/js/RangeManager');
+const {
+    ObjectId
+} = require("mongojs");
+const {
+    assert
+} = require("chai");
+const _ = require("underscore");
 
-describe "RangeManager", ->
-	beforeEach ->
-		@RangeManager = SandboxedModule.require modulePath, requires:
-			"./mongojs":
-				ObjectId: ObjectId
+describe("RangeManager", function() {
+	beforeEach(function() {
+		return this.RangeManager = SandboxedModule.require(modulePath, { requires: {
+			"./mongojs": {
+				ObjectId
+			}
+		}
+	}
+		);
+	});
 
-	describe "jsonRangesToMongo", ->
-		it "should convert ObjectIds and dates to proper objects", ->
-			change_id = ObjectId().toString()
-			comment_id = ObjectId().toString()
-			user_id = ObjectId().toString()
-			thread_id = ObjectId().toString()
-			ts = new Date().toJSON()
-			@RangeManager.jsonRangesToMongo({
+	describe("jsonRangesToMongo", function() {
+		it("should convert ObjectIds and dates to proper objects", function() {
+			const change_id = ObjectId().toString();
+			const comment_id = ObjectId().toString();
+			const user_id = ObjectId().toString();
+			const thread_id = ObjectId().toString();
+			const ts = new Date().toJSON();
+			return this.RangeManager.jsonRangesToMongo({
 				changes: [{
-					id: change_id
-					op: { i: "foo", p: 3 }
-					metadata:
-						user_id: user_id
-						ts: ts
-				}]
+					id: change_id,
+					op: { i: "foo", p: 3 },
+					metadata: {
+						user_id,
+						ts
+					}
+				}],
 				comments: [{
-					id: comment_id
+					id: comment_id,
 					op: { c: "foo", p: 3, t: thread_id }
 				}]
-			}).should.deep.equal {
+			}).should.deep.equal({
 				changes: [{
-					id: ObjectId(change_id)
-					op: { i: "foo", p: 3 }
-					metadata:
-						user_id: ObjectId(user_id)
+					id: ObjectId(change_id),
+					op: { i: "foo", p: 3 },
+					metadata: {
+						user_id: ObjectId(user_id),
 						ts: new Date(ts)
-				}]
+					}
+				}],
 				comments: [{
-					id: ObjectId(comment_id)
+					id: ObjectId(comment_id),
 					op: { c: "foo", p: 3, t: ObjectId(thread_id) }
 				}]
-			}
+			});
+	});
 		
-		it "should leave malformed ObjectIds as they are", ->
-			change_id = "foo"
-			comment_id = "bar"
-			user_id = "baz"
-			@RangeManager.jsonRangesToMongo({
+		it("should leave malformed ObjectIds as they are", function() {
+			const change_id = "foo";
+			const comment_id = "bar";
+			const user_id = "baz";
+			return this.RangeManager.jsonRangesToMongo({
 				changes: [{
-					id: change_id
-					metadata:
-						user_id: user_id
-				}]
+					id: change_id,
+					metadata: {
+						user_id
+					}
+				}],
 				comments: [{
 					id: comment_id
 				}]
-			}).should.deep.equal {
+			}).should.deep.equal({
 				changes: [{
-					id: change_id
-					metadata:
-						user_id: user_id
-				}]
+					id: change_id,
+					metadata: {
+						user_id
+					}
+				}],
 				comments: [{
 					id: comment_id
 				}]
-			}
+			});
+	});
 		
-		it "should be consistent when transformed through json -> mongo -> json", ->
-			change_id = ObjectId().toString()
-			comment_id = ObjectId().toString()
-			user_id = ObjectId().toString()
-			thread_id = ObjectId().toString()
-			ts = new Date().toJSON()
-			ranges1 = {
+		return it("should be consistent when transformed through json -> mongo -> json", function() {
+			const change_id = ObjectId().toString();
+			const comment_id = ObjectId().toString();
+			const user_id = ObjectId().toString();
+			const thread_id = ObjectId().toString();
+			const ts = new Date().toJSON();
+			const ranges1 = {
 				changes: [{
-					id: change_id
-					op: { i: "foo", p: 3 }
-					metadata:
-						user_id: user_id
-						ts: ts
-				}]
+					id: change_id,
+					op: { i: "foo", p: 3 },
+					metadata: {
+						user_id,
+						ts
+					}
+				}],
 				comments: [{
-					id: comment_id
+					id: comment_id,
 					op: { c: "foo", p: 3, t: thread_id }
 				}]
-			}
-			ranges1_copy = JSON.parse(JSON.stringify(ranges1)) # jsonRangesToMongo modifies in place
-			ranges2 = JSON.parse(JSON.stringify(@RangeManager.jsonRangesToMongo(ranges1_copy)))
-			ranges1.should.deep.equal ranges2
+			};
+			const ranges1_copy = JSON.parse(JSON.stringify(ranges1)); // jsonRangesToMongo modifies in place
+			const ranges2 = JSON.parse(JSON.stringify(this.RangeManager.jsonRangesToMongo(ranges1_copy)));
+			return ranges1.should.deep.equal(ranges2);
+		});
+	});
 			
-	describe "shouldUpdateRanges", ->
-		beforeEach () ->
-			@ranges = {
+	return describe("shouldUpdateRanges", function() {
+		beforeEach(function() {
+			this.ranges = {
 				changes: [{
-					id: ObjectId()
-					op: { i: "foo", p: 3 }
-					metadata:
-						user_id: ObjectId()
+					id: ObjectId(),
+					op: { i: "foo", p: 3 },
+					metadata: {
+						user_id: ObjectId(),
 						ts: new Date()
-				}]
+					}
+				}],
 				comments: [{
-					id: ObjectId()
+					id: ObjectId(),
 					op: { c: "foo", p: 3, t: ObjectId() }
 				}]
-			}
-			@ranges_copy = @RangeManager.jsonRangesToMongo(JSON.parse(JSON.stringify(@ranges)))
+			};
+			return this.ranges_copy = this.RangeManager.jsonRangesToMongo(JSON.parse(JSON.stringify(this.ranges)));
+		});
 
-		describe "with a blank new range", ->
-			it "should throw an error", ->
-				expect(() =>
-					@RangeManager.shouldUpdateRanges(@ranges, null)
-				).to.throw(Error)
+		describe("with a blank new range", () => it("should throw an error", function() {
+            return expect(() => {
+                return this.RangeManager.shouldUpdateRanges(this.ranges, null);
+            }).to.throw(Error);
+        }));
 		
-		describe "with a blank old range", ->
-			it "should treat it like {}", ->
-				@RangeManager.shouldUpdateRanges(null, {}).should.equal false
-				@RangeManager.shouldUpdateRanges(null, @ranges).should.equal true
+		describe("with a blank old range", () => it("should treat it like {}", function() {
+            this.RangeManager.shouldUpdateRanges(null, {}).should.equal(false);
+            return this.RangeManager.shouldUpdateRanges(null, this.ranges).should.equal(true);
+        }));
 		
-		describe "with no changes", ->
-			it "should return false", ->
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal false
+		describe("with no changes", () => it("should return false", function() {
+            return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(false);
+        }));
 		
-		describe "with changes", ->
-			it "should return true when the change id changes", ->
-				@ranges_copy.changes[0].id = ObjectId()
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal true
+		return describe("with changes", function() {
+			it("should return true when the change id changes", function() {
+				this.ranges_copy.changes[0].id = ObjectId();
+				return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(true);
+			});
 
-			it "should return true when the change user id changes", ->
-				@ranges_copy.changes[0].metadata.user_id = ObjectId()
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal true
+			it("should return true when the change user id changes", function() {
+				this.ranges_copy.changes[0].metadata.user_id = ObjectId();
+				return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(true);
+			});
 
-			it "should return true when the change ts changes", ->
-				@ranges_copy.changes[0].metadata.ts = new Date(Date.now() + 1000)
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal true
+			it("should return true when the change ts changes", function() {
+				this.ranges_copy.changes[0].metadata.ts = new Date(Date.now() + 1000);
+				return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(true);
+			});
 
-			it "should return true when the change op changes", ->
-				@ranges_copy.changes[0].op.i = "bar"
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal true
+			it("should return true when the change op changes", function() {
+				this.ranges_copy.changes[0].op.i = "bar";
+				return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(true);
+			});
 
-			it "should return true when the comment id changes", ->
-				@ranges_copy.comments[0].id = ObjectId()
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal true
+			it("should return true when the comment id changes", function() {
+				this.ranges_copy.comments[0].id = ObjectId();
+				return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(true);
+			});
 
-			it "should return true when the comment offset changes", ->
-				@ranges_copy.comments[0].op.p = 17
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal true
+			it("should return true when the comment offset changes", function() {
+				this.ranges_copy.comments[0].op.p = 17;
+				return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(true);
+			});
 
-			it "should return true when the comment content changes", ->
-				@ranges_copy.comments[0].op.c = "bar"
-				@RangeManager.shouldUpdateRanges(@ranges, @ranges_copy).should.equal true
+			return it("should return true when the comment content changes", function() {
+				this.ranges_copy.comments[0].op.c = "bar";
+				return this.RangeManager.shouldUpdateRanges(this.ranges, this.ranges_copy).should.equal(true);
+			});
+		});
+	});
+});