| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /* eslint-disable
- no-return-assign,
- no-unused-vars,
- */
- // TODO: This file was created by bulk-decaffeinate.
- // Fix any style issues and re-enable lint.
- /*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
- const sinon = require('sinon');
- const chai = require('chai');
- const should = chai.should();
- const modulePath = "../../../../app/js/ShareJsUpdateManager.js";
- const SandboxedModule = require('sandboxed-module');
- const crypto = require('crypto');
- describe("ShareJsUpdateManager", function() {
- beforeEach(function() {
- let Model;
- this.project_id = "project-id-123";
- this.doc_id = "document-id-123";
- this.callback = sinon.stub();
- return this.ShareJsUpdateManager = SandboxedModule.require(modulePath, {
- requires: {
- "./sharejs/server/model":
- (Model = class Model {
- constructor(db) {
- this.db = db;
- }
- }),
- "./ShareJsDB" : (this.ShareJsDB = { mockDB: true }),
- "redis-sharelatex" : { createClient: () => { return this.rclient = {auth() {}}; }
- },
- "logger-sharelatex": (this.logger = { log: sinon.stub() }),
- "./RealTimeRedisManager": (this.RealTimeRedisManager = {}),
- "./Metrics": (this.metrics = { inc: sinon.stub() })
- },
- globals: {
- clearTimeout: (this.clearTimeout = sinon.stub())
- }
- }
- );
- });
- describe("applyUpdate", function() {
- beforeEach(function() {
- this.lines = ["one", "two"];
- this.version = 34;
- this.updatedDocLines = ["onefoo", "two"];
- const content = this.updatedDocLines.join("\n");
- this.hash = crypto.createHash('sha1').update("blob " + content.length + "\x00").update(content, 'utf8').digest('hex');
- this.update = {p: 4, t: "foo", v:this.version, hash:this.hash};
- this.model = {
- applyOp: sinon.stub().callsArg(2),
- getSnapshot: sinon.stub(),
- db: {
- appliedOps: {}
- }
- };
- this.ShareJsUpdateManager.getNewShareJsModel = sinon.stub().returns(this.model);
- this.ShareJsUpdateManager._listenForOps = sinon.stub();
- return this.ShareJsUpdateManager.removeDocFromCache = sinon.stub().callsArg(1);
- });
- describe("successfully", function() {
- beforeEach(function(done) {
- this.model.getSnapshot.callsArgWith(1, null, {snapshot: this.updatedDocLines.join("\n"), v: this.version});
- this.model.db.appliedOps[`${this.project_id}:${this.doc_id}`] = (this.appliedOps = ["mock-ops"]);
- return this.ShareJsUpdateManager.applyUpdate(this.project_id, this.doc_id, this.update, this.lines, this.version, (err, docLines, version, appliedOps) => {
- this.callback(err, docLines, version, appliedOps);
- return done();
- });
- });
- it("should create a new ShareJs model", function() {
- return this.ShareJsUpdateManager.getNewShareJsModel
- .calledWith(this.project_id, this.doc_id, this.lines, this.version)
- .should.equal(true);
- });
- it("should listen for ops on the model", function() {
- return this.ShareJsUpdateManager._listenForOps
- .calledWith(this.model)
- .should.equal(true);
- });
- it("should send the update to ShareJs", function() {
- return this.model.applyOp
- .calledWith(`${this.project_id}:${this.doc_id}`, this.update)
- .should.equal(true);
- });
- it("should get the updated doc lines", function() {
- return this.model.getSnapshot
- .calledWith(`${this.project_id}:${this.doc_id}`)
- .should.equal(true);
- });
- return it("should return the updated doc lines, version and ops", function() {
- return this.callback.calledWith(null, this.updatedDocLines, this.version, this.appliedOps).should.equal(true);
- });
- });
- describe("when applyOp fails", function() {
- beforeEach(function(done) {
- this.error = new Error("Something went wrong");
- this.model.applyOp = sinon.stub().callsArgWith(2, this.error);
- return this.ShareJsUpdateManager.applyUpdate(this.project_id, this.doc_id, this.update, this.lines, this.version, (err, docLines, version) => {
- this.callback(err, docLines, version);
- return done();
- });
- });
- return it("should call the callback with the error", function() {
- return this.callback.calledWith(this.error).should.equal(true);
- });
- });
- describe("when getSnapshot fails", function() {
- beforeEach(function(done) {
- this.error = new Error("Something went wrong");
- this.model.getSnapshot.callsArgWith(1, this.error);
- return this.ShareJsUpdateManager.applyUpdate(this.project_id, this.doc_id, this.update, this.lines, this.version, (err, docLines, version) => {
- this.callback(err, docLines, version);
- return done();
- });
- });
- return it("should call the callback with the error", function() {
- return this.callback.calledWith(this.error).should.equal(true);
- });
- });
- return describe("with an invalid hash", function() {
- beforeEach(function(done) {
- this.error = new Error("invalid hash");
- this.model.getSnapshot.callsArgWith(1, null, {snapshot: "unexpected content", v: this.version});
- this.model.db.appliedOps[`${this.project_id}:${this.doc_id}`] = (this.appliedOps = ["mock-ops"]);
- return this.ShareJsUpdateManager.applyUpdate(this.project_id, this.doc_id, this.update, this.lines, this.version, (err, docLines, version, appliedOps) => {
- this.callback(err, docLines, version, appliedOps);
- return done();
- });
- });
- return it("should call the callback with the error", function() {
- return this.callback.calledWith(this.error).should.equal(true);
- });
- });
- });
- return describe("_listenForOps", function() {
- beforeEach(function() {
- this.model = { on: (event, callback) => {
- return this.callback = callback;
- }
- };
- sinon.spy(this.model, "on");
- return this.ShareJsUpdateManager._listenForOps(this.model);
- });
- it("should listen to the model for updates", function() {
- return this.model.on.calledWith("applyOp")
- .should.equal(true);
- });
- return describe("the callback", function() {
- beforeEach(function() {
- this.opData = {
- op: {t: "foo", p: 1},
- meta: { source: "bar"
- }
- };
- this.RealTimeRedisManager.sendData = sinon.stub();
- return this.callback(`${this.project_id}:${this.doc_id}`, this.opData);
- });
- return it("should publish the op to redis", function() {
- return this.RealTimeRedisManager.sendData
- .calledWith({project_id: this.project_id, doc_id: this.doc_id, op: this.opData})
- .should.equal(true);
- });
- });
- });
- });
|