overleaf/services/document-updater/test/unit/coffee/PersistenceManager/PersistenceManagerTests.js

304 lines
10 KiB
JavaScript

/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS206: Consider reworking classes to avoid initClass
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const modulePath = "../../../../app/js/PersistenceManager.js";
const SandboxedModule = require('sandboxed-module');
const Errors = require("../../../../app/js/Errors");
describe("PersistenceManager", function() {
beforeEach(function() {
let Timer;
this.request = sinon.stub();
this.request.defaults = () => this.request;
this.PersistenceManager = SandboxedModule.require(modulePath, { requires: {
"requestretry": this.request,
"settings-sharelatex": (this.Settings = {}),
"./Metrics": (this.Metrics = {
Timer: (Timer = (function() {
Timer = class Timer {
static initClass() {
this.prototype.done = sinon.stub();
}
};
Timer.initClass();
return Timer;
})()),
inc: sinon.stub()
}),
"logger-sharelatex": (this.logger = {log: sinon.stub(), err: sinon.stub()})
}
});
this.project_id = "project-id-123";
this.projectHistoryId = "history-id-123";
this.doc_id = "doc-id-123";
this.lines = ["one", "two", "three"];
this.version = 42;
this.callback = sinon.stub();
this.ranges = { comments: "mock", entries: "mock" };
this.pathname = '/a/b/c.tex';
this.lastUpdatedAt = Date.now();
this.lastUpdatedBy = 'last-author-id';
return this.Settings.apis = {
web: {
url: (this.url = "www.example.com"),
user: (this.user = "sharelatex"),
pass: (this.pass = "password")
}
};
});
describe("getDoc", function() {
beforeEach(function() {
return this.webResponse = {
lines: this.lines,
version: this.version,
ranges: this.ranges,
pathname: this.pathname,
projectHistoryId: this.projectHistoryId
};});
describe("with a successful response from the web api", function() {
beforeEach(function() {
this.request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(this.webResponse));
return this.PersistenceManager.getDoc(this.project_id, this.doc_id, this.callback);
});
it("should call the web api", function() {
return this.request
.calledWith({
url: `${this.url}/project/${this.project_id}/doc/${this.doc_id}`,
method: "GET",
headers: {
"accept": "application/json"
},
auth: {
user: this.user,
pass: this.pass,
sendImmediately: true
},
jar: false,
timeout: 5000
})
.should.equal(true);
});
it("should call the callback with the doc lines, version and ranges", function() {
return this.callback
.calledWith(null, this.lines, this.version, this.ranges, this.pathname, this.projectHistoryId)
.should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("getDoc", 1, {status: 200}).should.equal(true);
});
});
describe("when request returns an error", function() {
beforeEach(function() {
this.error = new Error("oops");
this.error.code = "EOOPS";
this.request.callsArgWith(1, this.error, null, null);
return this.PersistenceManager.getDoc(this.project_id, this.doc_id, this.callback);
});
it("should return the error", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("getDoc", 1, {status: "EOOPS"}).should.equal(true);
});
});
describe("when the request returns 404", function() {
beforeEach(function() {
this.request.callsArgWith(1, null, {statusCode: 404}, "");
return this.PersistenceManager.getDoc(this.project_id, this.doc_id, this.callback);
});
it("should return a NotFoundError", function() {
return this.callback.calledWith(new Errors.NotFoundError("not found")).should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("getDoc", 1, {status: 404}).should.equal(true);
});
});
describe("when the request returns an error status code", function() {
beforeEach(function() {
this.request.callsArgWith(1, null, {statusCode: 500}, "");
return this.PersistenceManager.getDoc(this.project_id, this.doc_id, this.callback);
});
it("should return an error", function() {
return this.callback.calledWith(new Error("web api error")).should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("getDoc", 1, {status: 500}).should.equal(true);
});
});
describe("when request returns an doc without lines", function() {
beforeEach(function() {
delete this.webResponse.lines;
this.request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(this.webResponse));
return this.PersistenceManager.getDoc(this.project_id, this.doc_id, this.callback);
});
return it("should return and error", function() {
return this.callback.calledWith(new Error("web API response had no doc lines")).should.equal(true);
});
});
describe("when request returns an doc without a version", function() {
beforeEach(function() {
delete this.webResponse.version;
this.request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(this.webResponse));
return this.PersistenceManager.getDoc(this.project_id, this.doc_id, this.callback);
});
return it("should return and error", function() {
return this.callback.calledWith(new Error("web API response had no valid doc version")).should.equal(true);
});
});
return describe("when request returns an doc without a pathname", function() {
beforeEach(function() {
delete this.webResponse.pathname;
this.request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(this.webResponse));
return this.PersistenceManager.getDoc(this.project_id, this.doc_id, this.callback);
});
return it("should return and error", function() {
return this.callback.calledWith(new Error("web API response had no valid doc pathname")).should.equal(true);
});
});
});
return describe("setDoc", function() {
describe("with a successful response from the web api", function() {
beforeEach(function() {
this.request.callsArgWith(1, null, {statusCode: 200});
return this.PersistenceManager.setDoc(this.project_id, this.doc_id, this.lines, this.version, this.ranges, this.lastUpdatedAt, this.lastUpdatedBy, this.callback);
});
it("should call the web api", function() {
return this.request
.calledWith({
url: `${this.url}/project/${this.project_id}/doc/${this.doc_id}`,
json: {
lines: this.lines,
version: this.version,
ranges: this.ranges,
lastUpdatedAt: this.lastUpdatedAt,
lastUpdatedBy: this.lastUpdatedBy
},
method: "POST",
auth: {
user: this.user,
pass: this.pass,
sendImmediately: true
},
jar: false,
timeout: 5000
})
.should.equal(true);
});
it("should call the callback without error", function() {
return this.callback.calledWith(null).should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("setDoc", 1, {status: 200}).should.equal(true);
});
});
describe("when request returns an error", function() {
beforeEach(function() {
this.error = new Error("oops");
this.error.code = "EOOPS";
this.request.callsArgWith(1, this.error, null, null);
return this.PersistenceManager.setDoc(this.project_id, this.doc_id, this.lines, this.version, this.ranges, this.lastUpdatedAt, this.lastUpdatedBy, this.callback);
});
it("should return the error", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("setDoc", 1, {status: "EOOPS"}).should.equal(true);
});
});
describe("when the request returns 404", function() {
beforeEach(function() {
this.request.callsArgWith(1, null, {statusCode: 404}, "");
return this.PersistenceManager.setDoc(this.project_id, this.doc_id, this.lines, this.version, this.ranges, this.lastUpdatedAt, this.lastUpdatedBy, this.callback);
});
it("should return a NotFoundError", function() {
return this.callback.calledWith(new Errors.NotFoundError("not found")).should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("setDoc", 1, {status: 404}).should.equal(true);
});
});
return describe("when the request returns an error status code", function() {
beforeEach(function() {
this.request.callsArgWith(1, null, {statusCode: 500}, "");
return this.PersistenceManager.setDoc(this.project_id, this.doc_id, this.lines, this.version, this.ranges, this.lastUpdatedAt, this.lastUpdatedBy, this.callback);
});
it("should return an error", function() {
return this.callback.calledWith(new Error("web api error")).should.equal(true);
});
it("should time the execution", function() {
return this.Metrics.Timer.prototype.done.called.should.equal(true);
});
return it("should increment the metric", function() {
return this.Metrics.inc.calledWith("setDoc", 1, {status: 500}).should.equal(true);
});
});
});
});