prettier: convert test/unit decaffeinated files to Prettier format

This commit is contained in:
mserranom 2020-02-17 18:35:16 +01:00
parent 201bfbbf32
commit 7741730574
14 changed files with 5100 additions and 3792 deletions

View file

@ -10,393 +10,453 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/DiffGenerator.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/DiffGenerator.js'
const SandboxedModule = require('sandboxed-module')
describe("DiffGenerator", function() {
beforeEach(function() {
this.DiffGenerator = SandboxedModule.require(modulePath, { requires: {
"logger-sharelatex": { warn: sinon.stub() }
}
});
this.ts = Date.now();
this.user_id = "mock-user-id";
this.user_id_2 = "mock-user-id-2";
return this.meta = {
start_ts: this.ts, end_ts: this.ts, user_id: this.user_id
};});
describe('DiffGenerator', function() {
beforeEach(function() {
this.DiffGenerator = SandboxedModule.require(modulePath, {
requires: {
'logger-sharelatex': { warn: sinon.stub() }
}
})
this.ts = Date.now()
this.user_id = 'mock-user-id'
this.user_id_2 = 'mock-user-id-2'
return (this.meta = {
start_ts: this.ts,
end_ts: this.ts,
user_id: this.user_id
})
})
describe("rewindOp", function() {
describe("rewinding an insert", function() { return it("should undo the insert", function() {
const content = "hello world";
const rewoundContent = this.DiffGenerator.rewindOp(content, { p: 6, i: "wo" });
return rewoundContent.should.equal("hello rld");
}); }
);
describe('rewindOp', function() {
describe('rewinding an insert', function() {
return it('should undo the insert', function() {
const content = 'hello world'
const rewoundContent = this.DiffGenerator.rewindOp(content, {
p: 6,
i: 'wo'
})
return rewoundContent.should.equal('hello rld')
})
})
describe("rewinding a delete", function() { return it("should undo the delete", function() {
const content = "hello rld";
const rewoundContent = this.DiffGenerator.rewindOp(content, { p: 6, d: "wo" });
return rewoundContent.should.equal("hello world");
}); }
);
describe('rewinding a delete', function() {
return it('should undo the delete', function() {
const content = 'hello rld'
const rewoundContent = this.DiffGenerator.rewindOp(content, {
p: 6,
d: 'wo'
})
return rewoundContent.should.equal('hello world')
})
})
describe("with an inconsistent update", function() { return it("should throw an error", function() {
const content = "hello world";
return expect( () => {
return this.DiffGenerator.rewindOp(content, { p: 6, i: "foo" });
}).to.throw(this.DiffGenerator.ConsistencyError);
}); }
);
return describe("with an update which is beyond the length of the content", function() { return it("should undo the insert as if it were at the end of the content", function() {
const content = "foobar";
const rewoundContent = this.DiffGenerator.rewindOp(content, { p: 4, i: "bar" });
return rewoundContent.should.equal("foo");
}); }
);
});
describe('with an inconsistent update', function() {
return it('should throw an error', function() {
const content = 'hello world'
return expect(() => {
return this.DiffGenerator.rewindOp(content, { p: 6, i: 'foo' })
}).to.throw(this.DiffGenerator.ConsistencyError)
})
})
describe("rewindUpdate", function() { return it("should rewind ops in reverse", function() {
const content = "aaabbbccc";
const update =
{op: [{ p: 3, i: "bbb" }, { p: 6, i: "ccc" }]};
const rewoundContent = this.DiffGenerator.rewindUpdate(content, update);
return rewoundContent.should.equal("aaa");
}); }
);
return describe('with an update which is beyond the length of the content', function() {
return it('should undo the insert as if it were at the end of the content', function() {
const content = 'foobar'
const rewoundContent = this.DiffGenerator.rewindOp(content, {
p: 4,
i: 'bar'
})
return rewoundContent.should.equal('foo')
})
})
})
describe("rewindUpdates", function() { return it("should rewind updates in reverse", function() {
const content = "aaabbbccc";
const updates = [
{ op: [{ p: 3, i: "bbb" }] },
{ op: [{ p: 6, i: "ccc" }] }
];
const rewoundContent = this.DiffGenerator.rewindUpdates(content, updates);
return rewoundContent.should.equal("aaa");
}); }
);
describe('rewindUpdate', function() {
return it('should rewind ops in reverse', function() {
const content = 'aaabbbccc'
const update = {
op: [
{ p: 3, i: 'bbb' },
{ p: 6, i: 'ccc' }
]
}
const rewoundContent = this.DiffGenerator.rewindUpdate(content, update)
return rewoundContent.should.equal('aaa')
})
})
describe("buildDiff", function() {
beforeEach(function() {
this.diff = [ {u: "mock-diff"} ];
this.content = "Hello world";
this.updates = [
{ i: "mock-update-1" },
{ i: "mock-update-2" },
{ i: "mock-update-3" }
];
this.DiffGenerator.applyUpdateToDiff = sinon.stub().returns(this.diff);
this.DiffGenerator.compressDiff = sinon.stub().returns(this.diff);
return this.result = this.DiffGenerator.buildDiff(this.content, this.updates);
});
describe('rewindUpdates', function() {
return it('should rewind updates in reverse', function() {
const content = 'aaabbbccc'
const updates = [
{ op: [{ p: 3, i: 'bbb' }] },
{ op: [{ p: 6, i: 'ccc' }] }
]
const rewoundContent = this.DiffGenerator.rewindUpdates(content, updates)
return rewoundContent.should.equal('aaa')
})
})
it("should return the diff", function() {
return this.result.should.deep.equal(this.diff);
});
describe('buildDiff', function() {
beforeEach(function() {
this.diff = [{ u: 'mock-diff' }]
this.content = 'Hello world'
this.updates = [
{ i: 'mock-update-1' },
{ i: 'mock-update-2' },
{ i: 'mock-update-3' }
]
this.DiffGenerator.applyUpdateToDiff = sinon.stub().returns(this.diff)
this.DiffGenerator.compressDiff = sinon.stub().returns(this.diff)
return (this.result = this.DiffGenerator.buildDiff(
this.content,
this.updates
))
})
it("should build the content into an initial diff", function() {
return this.DiffGenerator.applyUpdateToDiff
.calledWith([{
u: this.content
}], this.updates[0])
.should.equal(true);
});
it('should return the diff', function() {
return this.result.should.deep.equal(this.diff)
})
it("should apply each update", function() {
return Array.from(this.updates).map((update) =>
this.DiffGenerator.applyUpdateToDiff
.calledWith(sinon.match.any, update)
.should.equal(true));
});
it('should build the content into an initial diff', function() {
return this.DiffGenerator.applyUpdateToDiff
.calledWith(
[
{
u: this.content
}
],
this.updates[0]
)
.should.equal(true)
})
return it("should compress the diff", function() {
return this.DiffGenerator.compressDiff
.calledWith(this.diff)
.should.equal(true);
});
});
it('should apply each update', function() {
return Array.from(this.updates).map(update =>
this.DiffGenerator.applyUpdateToDiff
.calledWith(sinon.match.any, update)
.should.equal(true)
)
})
describe("compressDiff", function() {
describe("with adjacent inserts with the same user_id", function() { return it("should create one update with combined meta data and min/max timestamps", function() {
const diff = this.DiffGenerator.compressDiff([
{ i: "foo", meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }},
{ i: "bar", meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id } }}
]);
return expect(diff).to.deep.equal([
{ i: "foobar", meta: { start_ts: 5, end_ts: 20, user: { id: this.user_id } }}
]);
}); }
);
return it('should compress the diff', function() {
return this.DiffGenerator.compressDiff
.calledWith(this.diff)
.should.equal(true)
})
})
describe("with adjacent inserts with different user_ids", function() { return it("should leave the inserts unchanged", function() {
const input = [
{ i: "foo", meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }},
{ i: "bar", meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id_2 } }}
];
const output = this.DiffGenerator.compressDiff(input);
return expect(output).to.deep.equal(input);
}); }
);
describe('compressDiff', function() {
describe('with adjacent inserts with the same user_id', function() {
return it('should create one update with combined meta data and min/max timestamps', function() {
const diff = this.DiffGenerator.compressDiff([
{
i: 'foo',
meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }
},
{
i: 'bar',
meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id } }
}
])
return expect(diff).to.deep.equal([
{
i: 'foobar',
meta: { start_ts: 5, end_ts: 20, user: { id: this.user_id } }
}
])
})
})
describe("with adjacent deletes with the same user_id", function() { return it("should create one update with combined meta data and min/max timestamps", function() {
const diff = this.DiffGenerator.compressDiff([
{ d: "foo", meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }},
{ d: "bar", meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id } }}
]);
return expect(diff).to.deep.equal([
{ d: "foobar", meta: { start_ts: 5, end_ts: 20, user: { id: this.user_id } }}
]);
}); }
);
describe('with adjacent inserts with different user_ids', function() {
return it('should leave the inserts unchanged', function() {
const input = [
{
i: 'foo',
meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }
},
{
i: 'bar',
meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id_2 } }
}
]
const output = this.DiffGenerator.compressDiff(input)
return expect(output).to.deep.equal(input)
})
})
return describe("with adjacent deletes with different user_ids", function() { return it("should leave the deletes unchanged", function() {
const input = [
{ d: "foo", meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }},
{ d: "bar", meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id_2 } }}
];
const output = this.DiffGenerator.compressDiff(input);
return expect(output).to.deep.equal(input);
}); }
);
});
describe('with adjacent deletes with the same user_id', function() {
return it('should create one update with combined meta data and min/max timestamps', function() {
const diff = this.DiffGenerator.compressDiff([
{
d: 'foo',
meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }
},
{
d: 'bar',
meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id } }
}
])
return expect(diff).to.deep.equal([
{
d: 'foobar',
meta: { start_ts: 5, end_ts: 20, user: { id: this.user_id } }
}
])
})
})
return describe("applyUpdateToDiff", function() {
describe("an insert", function() {
it("should insert into the middle of (u)nchanged text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobar" } ],
{ op: [{ p: 3, i: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "foo" },
{ i: "baz", meta: this.meta },
{ u: "bar" }
]);
});
return describe('with adjacent deletes with different user_ids', function() {
return it('should leave the deletes unchanged', function() {
const input = [
{
d: 'foo',
meta: { start_ts: 10, end_ts: 20, user: { id: this.user_id } }
},
{
d: 'bar',
meta: { start_ts: 5, end_ts: 15, user: { id: this.user_id_2 } }
}
]
const output = this.DiffGenerator.compressDiff(input)
return expect(output).to.deep.equal(input)
})
})
})
it("should insert into the start of (u)changed text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobar" } ],
{ op: [{ p: 0, i: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ i: "baz", meta: this.meta },
{ u: "foobar" }
]);
});
return describe('applyUpdateToDiff', function() {
describe('an insert', function() {
it('should insert into the middle of (u)nchanged text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff([{ u: 'foobar' }], {
op: [{ p: 3, i: 'baz' }],
meta: this.meta
})
return expect(diff).to.deep.equal([
{ u: 'foo' },
{ i: 'baz', meta: this.meta },
{ u: 'bar' }
])
})
it("should insert into the end of (u)changed text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobar" } ],
{ op: [{ p: 6, i: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "foobar" },
{ i: "baz", meta: this.meta }
]);
});
it('should insert into the start of (u)changed text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff([{ u: 'foobar' }], {
op: [{ p: 0, i: 'baz' }],
meta: this.meta
})
return expect(diff).to.deep.equal([
{ i: 'baz', meta: this.meta },
{ u: 'foobar' }
])
})
it("should insert into the middle of (i)inserted text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { i: "foobar", meta: this.meta } ],
{ op: [{ p: 3, i: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ i: "foo", meta: this.meta },
{ i: "baz", meta: this.meta },
{ i: "bar", meta: this.meta }
]);
});
it('should insert into the end of (u)changed text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff([{ u: 'foobar' }], {
op: [{ p: 6, i: 'baz' }],
meta: this.meta
})
return expect(diff).to.deep.equal([
{ u: 'foobar' },
{ i: 'baz', meta: this.meta }
])
})
return it("should not count deletes in the running length total", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[
{ d: "deleted", meta: this.meta },
{ u: "foobar" }
],
{ op: [{ p: 3, i: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ d: "deleted", meta: this.meta },
{ u: "foo" },
{ i: "baz", meta: this.meta },
{ u: "bar" }
]);
});
});
it('should insert into the middle of (i)inserted text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ i: 'foobar', meta: this.meta }],
{ op: [{ p: 3, i: 'baz' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ i: 'foo', meta: this.meta },
{ i: 'baz', meta: this.meta },
{ i: 'bar', meta: this.meta }
])
})
return describe("a delete", function() {
describe("deleting unchanged text", function() {
it("should delete from the middle of (u)nchanged text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobazbar" } ],
{ op: [{ p: 3, d: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "foo" },
{ d: "baz", meta: this.meta },
{ u: "bar" }
]);
});
return it('should not count deletes in the running length total', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ d: 'deleted', meta: this.meta }, { u: 'foobar' }],
{ op: [{ p: 3, i: 'baz' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ d: 'deleted', meta: this.meta },
{ u: 'foo' },
{ i: 'baz', meta: this.meta },
{ u: 'bar' }
])
})
})
it("should delete from the start of (u)nchanged text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobazbar" } ],
{ op: [{ p: 0, d: "foo" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ d: "foo", meta: this.meta },
{ u: "bazbar" }
]);
});
return describe('a delete', function() {
describe('deleting unchanged text', function() {
it('should delete from the middle of (u)nchanged text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ u: 'foobazbar' }],
{ op: [{ p: 3, d: 'baz' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ u: 'foo' },
{ d: 'baz', meta: this.meta },
{ u: 'bar' }
])
})
it("should delete from the end of (u)nchanged text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobazbar" } ],
{ op: [{ p: 6, d: "bar" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "foobaz" },
{ d: "bar", meta: this.meta }
]);
});
it('should delete from the start of (u)nchanged text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ u: 'foobazbar' }],
{ op: [{ p: 0, d: 'foo' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ d: 'foo', meta: this.meta },
{ u: 'bazbar' }
])
})
return it("should delete across multiple (u)changed text parts", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foo" }, { u: "baz" }, { u: "bar" } ],
{ op: [{ p: 2, d: "obazb" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "fo" },
{ d: "o", meta: this.meta },
{ d: "baz", meta: this.meta },
{ d: "b", meta: this.meta },
{ u: "ar" }
]);
});
});
it('should delete from the end of (u)nchanged text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ u: 'foobazbar' }],
{ op: [{ p: 6, d: 'bar' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ u: 'foobaz' },
{ d: 'bar', meta: this.meta }
])
})
describe("deleting inserts", function() {
it("should delete from the middle of (i)nserted text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { i: "foobazbar", meta: this.meta } ],
{ op: [{ p: 3, d: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ i: "foo", meta: this.meta },
{ i: "bar", meta: this.meta }
]);
});
return it('should delete across multiple (u)changed text parts', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ u: 'foo' }, { u: 'baz' }, { u: 'bar' }],
{ op: [{ p: 2, d: 'obazb' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ u: 'fo' },
{ d: 'o', meta: this.meta },
{ d: 'baz', meta: this.meta },
{ d: 'b', meta: this.meta },
{ u: 'ar' }
])
})
})
it("should delete from the start of (u)nchanged text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { i: "foobazbar", meta: this.meta } ],
{ op: [{ p: 0, d: "foo" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ i: "bazbar", meta: this.meta }
]);
});
describe('deleting inserts', function() {
it('should delete from the middle of (i)nserted text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ i: 'foobazbar', meta: this.meta }],
{ op: [{ p: 3, d: 'baz' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ i: 'foo', meta: this.meta },
{ i: 'bar', meta: this.meta }
])
})
it("should delete from the end of (u)nchanged text", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { i: "foobazbar", meta: this.meta } ],
{ op: [{ p: 6, d: "bar" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ i: "foobaz", meta: this.meta }
]);
});
it('should delete from the start of (u)nchanged text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ i: 'foobazbar', meta: this.meta }],
{ op: [{ p: 0, d: 'foo' }], meta: this.meta }
)
return expect(diff).to.deep.equal([{ i: 'bazbar', meta: this.meta }])
})
return it("should delete across multiple (u)changed and (i)nserted text parts", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foo" }, { i: "baz", meta: this.meta }, { u: "bar" } ],
{ op: [{ p: 2, d: "obazb" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "fo" },
{ d: "o", meta: this.meta },
{ d: "b", meta: this.meta },
{ u: "ar" }
]);
});
});
it('should delete from the end of (u)nchanged text', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ i: 'foobazbar', meta: this.meta }],
{ op: [{ p: 6, d: 'bar' }], meta: this.meta }
)
return expect(diff).to.deep.equal([{ i: 'foobaz', meta: this.meta }])
})
describe("deleting over existing deletes", function() { return it("should delete across multiple (u)changed and (d)deleted text parts", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foo" }, { d: "baz", meta: this.meta }, { u: "bar" } ],
{ op: [{ p: 2, d: "ob" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "fo" },
{ d: "o", meta: this.meta },
{ d: "baz", meta: this.meta },
{ d: "b", meta: this.meta },
{ u: "ar" }
]);
}); }
);
return it('should delete across multiple (u)changed and (i)nserted text parts', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ u: 'foo' }, { i: 'baz', meta: this.meta }, { u: 'bar' }],
{ op: [{ p: 2, d: 'obazb' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ u: 'fo' },
{ d: 'o', meta: this.meta },
{ d: 'b', meta: this.meta },
{ u: 'ar' }
])
})
})
describe("deleting when the text doesn't match", function() {
it("should throw an error when deleting from the middle of (u)nchanged text", function() {
return expect(
() => this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobazbar" } ],
{ op: [{ p: 3, d: "xxx" }], meta: this.meta }
)
).to.throw(this.DiffGenerator.ConsistencyError);
});
describe('deleting over existing deletes', function() {
return it('should delete across multiple (u)changed and (d)deleted text parts', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ u: 'foo' }, { d: 'baz', meta: this.meta }, { u: 'bar' }],
{ op: [{ p: 2, d: 'ob' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ u: 'fo' },
{ d: 'o', meta: this.meta },
{ d: 'baz', meta: this.meta },
{ d: 'b', meta: this.meta },
{ u: 'ar' }
])
})
})
it("should throw an error when deleting from the start of (u)nchanged text", function() {
return expect(
() => this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobazbar" } ],
{ op: [{ p: 0, d: "xxx" }], meta: this.meta }
)
).to.throw(this.DiffGenerator.ConsistencyError);
});
describe("deleting when the text doesn't match", function() {
it('should throw an error when deleting from the middle of (u)nchanged text', function() {
return expect(() =>
this.DiffGenerator.applyUpdateToDiff([{ u: 'foobazbar' }], {
op: [{ p: 3, d: 'xxx' }],
meta: this.meta
})
).to.throw(this.DiffGenerator.ConsistencyError)
})
return it("should throw an error when deleting from the end of (u)nchanged text", function() {
return expect(
() => this.DiffGenerator.applyUpdateToDiff(
[ { u: "foobazbar" } ],
{ op: [{ p: 6, d: "xxx" }] , meta: this.meta }
)
).to.throw(this.DiffGenerator.ConsistencyError);
});
});
it('should throw an error when deleting from the start of (u)nchanged text', function() {
return expect(() =>
this.DiffGenerator.applyUpdateToDiff([{ u: 'foobazbar' }], {
op: [{ p: 0, d: 'xxx' }],
meta: this.meta
})
).to.throw(this.DiffGenerator.ConsistencyError)
})
describe("when the last update in the existing diff is a delete", function() { return it("should insert the new update before the delete", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { u: "foo" }, { d: "bar", meta: this.meta } ],
{ op: [{ p: 3, i: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ u: "foo" },
{ i: "baz", meta: this.meta },
{ d: "bar", meta: this.meta }
]);
}); }
);
return describe("when the only update in the existing diff is a delete", function() { return it("should insert the new update after the delete", function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[ { d: "bar", meta: this.meta } ],
{ op: [{ p: 0, i: "baz" }], meta: this.meta }
);
return expect(diff).to.deep.equal([
{ d: "bar", meta: this.meta },
{ i: "baz", meta: this.meta }
]);
}); }
);
});
});
});
return it('should throw an error when deleting from the end of (u)nchanged text', function() {
return expect(() =>
this.DiffGenerator.applyUpdateToDiff([{ u: 'foobazbar' }], {
op: [{ p: 6, d: 'xxx' }],
meta: this.meta
})
).to.throw(this.DiffGenerator.ConsistencyError)
})
})
describe('when the last update in the existing diff is a delete', function() {
return it('should insert the new update before the delete', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ u: 'foo' }, { d: 'bar', meta: this.meta }],
{ op: [{ p: 3, i: 'baz' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ u: 'foo' },
{ i: 'baz', meta: this.meta },
{ d: 'bar', meta: this.meta }
])
})
})
return describe('when the only update in the existing diff is a delete', function() {
return it('should insert the new update after the delete', function() {
const diff = this.DiffGenerator.applyUpdateToDiff(
[{ d: 'bar', meta: this.meta }],
{ op: [{ p: 0, i: 'baz' }], meta: this.meta }
)
return expect(diff).to.deep.equal([
{ d: 'bar', meta: this.meta },
{ i: 'baz', meta: this.meta }
])
})
})
})
})
})

View file

@ -10,301 +10,439 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/DiffManager.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/DiffManager.js'
const SandboxedModule = require('sandboxed-module')
describe("DiffManager", function() {
beforeEach(function() {
this.DiffManager = SandboxedModule.require(modulePath, { requires: {
"logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub(), warn: sinon.stub() }),
"./UpdatesManager": (this.UpdatesManager = {}),
"./DocumentUpdaterManager": (this.DocumentUpdaterManager = {}),
"./DiffGenerator": (this.DiffGenerator = {})
}
});
this.callback = sinon.stub();
this.from = new Date();
this.to = new Date(Date.now() + 10000);
this.project_id = "mock-project-id";
return this.doc_id = "mock-doc-id";
});
describe('DiffManager', function() {
beforeEach(function() {
this.DiffManager = SandboxedModule.require(modulePath, {
requires: {
'logger-sharelatex': (this.logger = {
log: sinon.stub(),
error: sinon.stub(),
warn: sinon.stub()
}),
'./UpdatesManager': (this.UpdatesManager = {}),
'./DocumentUpdaterManager': (this.DocumentUpdaterManager = {}),
'./DiffGenerator': (this.DiffGenerator = {})
}
})
this.callback = sinon.stub()
this.from = new Date()
this.to = new Date(Date.now() + 10000)
this.project_id = 'mock-project-id'
return (this.doc_id = 'mock-doc-id')
})
describe("getLatestDocAndUpdates", function() {
beforeEach(function() {
this.content = "hello world";
this.version = 42;
this.updates = [ "mock-update-1", "mock-update-2" ];
describe('getLatestDocAndUpdates', function() {
beforeEach(function() {
this.content = 'hello world'
this.version = 42
this.updates = ['mock-update-1', 'mock-update-2']
this.DocumentUpdaterManager.getDocument = sinon.stub().callsArgWith(2, null, this.content, this.version);
return this.UpdatesManager.getDocUpdatesWithUserInfo = sinon.stub().callsArgWith(3, null, this.updates);
});
this.DocumentUpdaterManager.getDocument = sinon
.stub()
.callsArgWith(2, null, this.content, this.version)
return (this.UpdatesManager.getDocUpdatesWithUserInfo = sinon
.stub()
.callsArgWith(3, null, this.updates))
})
describe("with a fromVersion", function() {
beforeEach(function() {
return this.DiffManager.getLatestDocAndUpdates(this.project_id, this.doc_id, this.from, this.callback);
});
describe('with a fromVersion', function() {
beforeEach(function() {
return this.DiffManager.getLatestDocAndUpdates(
this.project_id,
this.doc_id,
this.from,
this.callback
)
})
it("should get the latest version of the doc", function() {
return this.DocumentUpdaterManager.getDocument
.calledWith(this.project_id, this.doc_id)
.should.equal(true);
});
it('should get the latest version of the doc', function() {
return this.DocumentUpdaterManager.getDocument
.calledWith(this.project_id, this.doc_id)
.should.equal(true)
})
it("should get the latest updates", function() {
return this.UpdatesManager.getDocUpdatesWithUserInfo
.calledWith(this.project_id, this.doc_id, {from: this.from})
.should.equal(true);
});
it('should get the latest updates', function() {
return this.UpdatesManager.getDocUpdatesWithUserInfo
.calledWith(this.project_id, this.doc_id, { from: this.from })
.should.equal(true)
})
return it("should call the callback with the content, version and updates", function() {
return this.callback.calledWith(null, this.content, this.version, this.updates).should.equal(true);
});
});
return it('should call the callback with the content, version and updates', function() {
return this.callback
.calledWith(null, this.content, this.version, this.updates)
.should.equal(true)
})
})
return describe("with no fromVersion", function() {
beforeEach(function() {
return this.DiffManager.getLatestDocAndUpdates(this.project_id, this.doc_id, null, this.callback);
});
return describe('with no fromVersion', function() {
beforeEach(function() {
return this.DiffManager.getLatestDocAndUpdates(
this.project_id,
this.doc_id,
null,
this.callback
)
})
it("should get the latest version of the doc", function() {
return this.DocumentUpdaterManager.getDocument
.calledWith(this.project_id, this.doc_id)
.should.equal(true);
});
it('should get the latest version of the doc', function() {
return this.DocumentUpdaterManager.getDocument
.calledWith(this.project_id, this.doc_id)
.should.equal(true)
})
it("should not get the latest updates", function() {
return this.UpdatesManager.getDocUpdatesWithUserInfo
.called.should.equal(false);
});
it('should not get the latest updates', function() {
return this.UpdatesManager.getDocUpdatesWithUserInfo.called.should.equal(
false
)
})
return it("should call the callback with the content, version and blank updates", function() {
return this.callback.calledWith(null, this.content, this.version, []).should.equal(true);
});
});
});
return it('should call the callback with the content, version and blank updates', function() {
return this.callback
.calledWith(null, this.content, this.version, [])
.should.equal(true)
})
})
})
describe("getDiff", function() {
beforeEach(function() {
this.content = "hello world";
// Op versions are the version they were applied to, so doc is always one version
// ahead.s
this.version = 43;
this.updates = [
{ op: "mock-4", v: 42, meta: { start_ts: new Date(this.to.getTime() + 20)} },
{ op: "mock-3", v: 41, meta: { start_ts: new Date(this.to.getTime() + 10)} },
{ op: "mock-2", v: 40, meta: { start_ts: new Date(this.to.getTime() - 10)} },
{ op: "mock-1", v: 39, meta: { start_ts: new Date(this.to.getTime() - 20)} }
];
this.fromVersion = 39;
this.toVersion = 40;
this.diffed_updates = this.updates.slice(2);
this.rewound_content = "rewound-content";
return this.diff = [ {u: "mock-diff"} ];});
describe("with matching versions", function() {
beforeEach(function() {
this.DiffManager.getDocumentBeforeVersion = sinon.stub().callsArgWith(3, null, this.rewound_content, this.updates);
this.DiffGenerator.buildDiff = sinon.stub().returns(this.diff);
return this.DiffManager.getDiff(this.project_id, this.doc_id, this.fromVersion, this.toVersion, this.callback);
});
describe('getDiff', function() {
beforeEach(function() {
this.content = 'hello world'
// Op versions are the version they were applied to, so doc is always one version
// ahead.s
this.version = 43
this.updates = [
{
op: 'mock-4',
v: 42,
meta: { start_ts: new Date(this.to.getTime() + 20) }
},
{
op: 'mock-3',
v: 41,
meta: { start_ts: new Date(this.to.getTime() + 10) }
},
{
op: 'mock-2',
v: 40,
meta: { start_ts: new Date(this.to.getTime() - 10) }
},
{
op: 'mock-1',
v: 39,
meta: { start_ts: new Date(this.to.getTime() - 20) }
}
]
this.fromVersion = 39
this.toVersion = 40
this.diffed_updates = this.updates.slice(2)
this.rewound_content = 'rewound-content'
return (this.diff = [{ u: 'mock-diff' }])
})
it("should get the latest doc and version with all recent updates", function() {
return this.DiffManager.getDocumentBeforeVersion
.calledWith(this.project_id, this.doc_id, this.fromVersion)
.should.equal(true);
});
describe('with matching versions', function() {
beforeEach(function() {
this.DiffManager.getDocumentBeforeVersion = sinon
.stub()
.callsArgWith(3, null, this.rewound_content, this.updates)
this.DiffGenerator.buildDiff = sinon.stub().returns(this.diff)
return this.DiffManager.getDiff(
this.project_id,
this.doc_id,
this.fromVersion,
this.toVersion,
this.callback
)
})
it("should generate the diff", function() {
return this.DiffGenerator.buildDiff
.calledWith(this.rewound_content, this.diffed_updates.slice().reverse())
.should.equal(true);
});
it('should get the latest doc and version with all recent updates', function() {
return this.DiffManager.getDocumentBeforeVersion
.calledWith(this.project_id, this.doc_id, this.fromVersion)
.should.equal(true)
})
return it("should call the callback with the diff", function() {
return this.callback.calledWith(null, this.diff).should.equal(true);
});
});
it('should generate the diff', function() {
return this.DiffGenerator.buildDiff
.calledWith(
this.rewound_content,
this.diffed_updates.slice().reverse()
)
.should.equal(true)
})
return describe("when the updates are inconsistent", function() {
beforeEach(function() {
this.DiffManager.getLatestDocAndUpdates = sinon.stub().callsArgWith(3, null, this.content, this.version, this.updates);
this.DiffGenerator.buildDiff = sinon.stub().throws(this.error = new Error("inconsistent!"));
return this.DiffManager.getDiff(this.project_id, this.doc_id, this.fromVersion, this.toVersion, this.callback);
});
return it('should call the callback with the diff', function() {
return this.callback.calledWith(null, this.diff).should.equal(true)
})
})
return it("should call the callback with an error", function() {
return this.callback
.calledWith(this.error)
.should.equal(true);
});
});
});
return describe('when the updates are inconsistent', function() {
beforeEach(function() {
this.DiffManager.getLatestDocAndUpdates = sinon
.stub()
.callsArgWith(3, null, this.content, this.version, this.updates)
this.DiffGenerator.buildDiff = sinon
.stub()
.throws((this.error = new Error('inconsistent!')))
return this.DiffManager.getDiff(
this.project_id,
this.doc_id,
this.fromVersion,
this.toVersion,
this.callback
)
})
describe("getDocumentBeforeVersion", function() {
beforeEach(function() {
this.DiffManager._tryGetDocumentBeforeVersion = sinon.stub();
this.document = "mock-documents";
return this.rewound_updates = "mock-rewound-updates";
});
return it('should call the callback with an error', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
})
describe("succesfully", function() {
beforeEach(function() {
this.DiffManager._tryGetDocumentBeforeVersion.yields(null, this.document, this.rewound_updates);
return this.DiffManager.getDocumentBeforeVersion(this.project_id, this.doc_id, this.version, this.callback);
});
it("should call _tryGetDocumentBeforeVersion", function() {
return this.DiffManager._tryGetDocumentBeforeVersion
.calledWith(this.project_id, this.doc_id, this.version)
.should.equal(true);
});
return it("should call the callback with the response", function() {
return this.callback.calledWith(null, this.document, this.rewound_updates).should.equal(true);
});
});
describe("with a retry needed", function() {
beforeEach(function() {
let retried = false;
this.DiffManager._tryGetDocumentBeforeVersion = (project_id, doc_id, version, callback) => {
if (!retried) {
retried = true;
const error = new Error();
error.retry = true;
return callback(error);
} else {
return callback(null, this.document, this.rewound_updates);
}
};
sinon.spy(this.DiffManager, "_tryGetDocumentBeforeVersion");
return this.DiffManager.getDocumentBeforeVersion(this.project_id, this.doc_id, this.version, this.callback);
});
it("should call _tryGetDocumentBeforeVersion twice", function() {
return this.DiffManager._tryGetDocumentBeforeVersion
.calledTwice
.should.equal(true);
});
return it("should call the callback with the response", function() {
return this.callback.calledWith(null, this.document, this.rewound_updates).should.equal(true);
});
});
describe("with a non-retriable error", function() {
beforeEach(function() {
this.error = new Error("oops");
this.DiffManager._tryGetDocumentBeforeVersion.yields(this.error);
return this.DiffManager.getDocumentBeforeVersion(this.project_id, this.doc_id, this.version, this.callback);
});
it("should call _tryGetDocumentBeforeVersion once", function() {
return this.DiffManager._tryGetDocumentBeforeVersion
.calledOnce
.should.equal(true);
});
return it("should call the callback with the error", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
});
return describe("when retry limit is matched", function() {
beforeEach(function() {
this.error = new Error("oops");
this.error.retry = true;
this.DiffManager._tryGetDocumentBeforeVersion.yields(this.error);
return this.DiffManager.getDocumentBeforeVersion(this.project_id, this.doc_id, this.version, this.callback);
});
it("should call _tryGetDocumentBeforeVersion three times (max retries)", function() {
return this.DiffManager._tryGetDocumentBeforeVersion
.calledThrice
.should.equal(true);
});
return it("should call the callback with the error", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
});
});
describe('getDocumentBeforeVersion', function() {
beforeEach(function() {
this.DiffManager._tryGetDocumentBeforeVersion = sinon.stub()
this.document = 'mock-documents'
return (this.rewound_updates = 'mock-rewound-updates')
})
return describe("_tryGetDocumentBeforeVersion", function() {
beforeEach(function() {
this.content = "hello world";
// Op versions are the version they were applied to, so doc is always one version
// ahead.s
this.version = 43;
this.updates = [
{ op: "mock-4", v: 42, meta: { start_ts: new Date(this.to.getTime() + 20)} },
{ op: "mock-3", v: 41, meta: { start_ts: new Date(this.to.getTime() + 10)} },
{ op: "mock-2", v: 40, meta: { start_ts: new Date(this.to.getTime() - 10)} },
{ op: "mock-1", v: 39, meta: { start_ts: new Date(this.to.getTime() - 20)} }
];
this.fromVersion = 39;
this.rewound_content = "rewound-content";
return this.diff = [ {u: "mock-diff"} ];});
describe("with matching versions", function() {
beforeEach(function() {
this.DiffManager.getLatestDocAndUpdates = sinon.stub().callsArgWith(3, null, this.content, this.version, this.updates);
this.DiffGenerator.rewindUpdates = sinon.spy((content, updates) => {
// the rewindUpdates method reverses the 'updates' array
updates.reverse();
return this.rewound_content;
});
this.rewindUpdatesWithArgs = this.DiffGenerator.rewindUpdates.withArgs(this.content, this.updates.slice().reverse());
return this.DiffManager._tryGetDocumentBeforeVersion(this.project_id, this.doc_id, this.fromVersion, this.callback);
});
describe('succesfully', function() {
beforeEach(function() {
this.DiffManager._tryGetDocumentBeforeVersion.yields(
null,
this.document,
this.rewound_updates
)
return this.DiffManager.getDocumentBeforeVersion(
this.project_id,
this.doc_id,
this.version,
this.callback
)
})
it("should get the latest doc and version with all recent updates", function() {
return this.DiffManager.getLatestDocAndUpdates
.calledWith(this.project_id, this.doc_id, this.fromVersion)
.should.equal(true);
});
it('should call _tryGetDocumentBeforeVersion', function() {
return this.DiffManager._tryGetDocumentBeforeVersion
.calledWith(this.project_id, this.doc_id, this.version)
.should.equal(true)
})
it("should rewind the diff", function() {
return sinon.assert.calledOnce(this.rewindUpdatesWithArgs);
});
return it('should call the callback with the response', function() {
return this.callback
.calledWith(null, this.document, this.rewound_updates)
.should.equal(true)
})
})
return it("should call the callback with the rewound document and updates", function() {
return this.callback.calledWith(null, this.rewound_content, this.updates).should.equal(true);
});
});
describe('with a retry needed', function() {
beforeEach(function() {
let retried = false
this.DiffManager._tryGetDocumentBeforeVersion = (
project_id,
doc_id,
version,
callback
) => {
if (!retried) {
retried = true
const error = new Error()
error.retry = true
return callback(error)
} else {
return callback(null, this.document, this.rewound_updates)
}
}
sinon.spy(this.DiffManager, '_tryGetDocumentBeforeVersion')
return this.DiffManager.getDocumentBeforeVersion(
this.project_id,
this.doc_id,
this.version,
this.callback
)
})
describe("with mismatching versions", function() {
beforeEach(function() {
this.version = 50;
this.updates = [ { op: "mock-1", v: 40 }, { op: "mock-1", v: 39 } ];
this.DiffManager.getLatestDocAndUpdates = sinon.stub().callsArgWith(3, null, this.content, this.version, this.updates);
return this.DiffManager._tryGetDocumentBeforeVersion(this.project_id, this.doc_id, this.fromVersion, this.callback);
});
it('should call _tryGetDocumentBeforeVersion twice', function() {
return this.DiffManager._tryGetDocumentBeforeVersion.calledTwice.should.equal(
true
)
})
return it("should call the callback with an error with retry = true set", function() {
this.callback.calledOnce.should.equal(true);
const error = this.callback.args[0][0];
return expect(error.retry).to.equal(true);
});
});
return it('should call the callback with the response', function() {
return this.callback
.calledWith(null, this.document, this.rewound_updates)
.should.equal(true)
})
})
return describe("when the updates are inconsistent", function() {
beforeEach(function() {
this.DiffManager.getLatestDocAndUpdates = sinon.stub().callsArgWith(3, null, this.content, this.version, this.updates);
this.DiffGenerator.rewindUpdates = sinon.stub().throws(this.error = new Error("inconsistent!"));
return this.DiffManager.getDocumentBeforeVersion(this.project_id, this.doc_id, this.fromVersion, this.callback);
});
describe('with a non-retriable error', function() {
beforeEach(function() {
this.error = new Error('oops')
this.DiffManager._tryGetDocumentBeforeVersion.yields(this.error)
return this.DiffManager.getDocumentBeforeVersion(
this.project_id,
this.doc_id,
this.version,
this.callback
)
})
return it("should call the callback with an error", function() {
return this.callback
.calledWith(this.error)
.should.equal(true);
});
});
});
});
it('should call _tryGetDocumentBeforeVersion once', function() {
return this.DiffManager._tryGetDocumentBeforeVersion.calledOnce.should.equal(
true
)
})
return it('should call the callback with the error', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
return describe('when retry limit is matched', function() {
beforeEach(function() {
this.error = new Error('oops')
this.error.retry = true
this.DiffManager._tryGetDocumentBeforeVersion.yields(this.error)
return this.DiffManager.getDocumentBeforeVersion(
this.project_id,
this.doc_id,
this.version,
this.callback
)
})
it('should call _tryGetDocumentBeforeVersion three times (max retries)', function() {
return this.DiffManager._tryGetDocumentBeforeVersion.calledThrice.should.equal(
true
)
})
return it('should call the callback with the error', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
})
return describe('_tryGetDocumentBeforeVersion', function() {
beforeEach(function() {
this.content = 'hello world'
// Op versions are the version they were applied to, so doc is always one version
// ahead.s
this.version = 43
this.updates = [
{
op: 'mock-4',
v: 42,
meta: { start_ts: new Date(this.to.getTime() + 20) }
},
{
op: 'mock-3',
v: 41,
meta: { start_ts: new Date(this.to.getTime() + 10) }
},
{
op: 'mock-2',
v: 40,
meta: { start_ts: new Date(this.to.getTime() - 10) }
},
{
op: 'mock-1',
v: 39,
meta: { start_ts: new Date(this.to.getTime() - 20) }
}
]
this.fromVersion = 39
this.rewound_content = 'rewound-content'
return (this.diff = [{ u: 'mock-diff' }])
})
describe('with matching versions', function() {
beforeEach(function() {
this.DiffManager.getLatestDocAndUpdates = sinon
.stub()
.callsArgWith(3, null, this.content, this.version, this.updates)
this.DiffGenerator.rewindUpdates = sinon.spy((content, updates) => {
// the rewindUpdates method reverses the 'updates' array
updates.reverse()
return this.rewound_content
})
this.rewindUpdatesWithArgs = this.DiffGenerator.rewindUpdates.withArgs(
this.content,
this.updates.slice().reverse()
)
return this.DiffManager._tryGetDocumentBeforeVersion(
this.project_id,
this.doc_id,
this.fromVersion,
this.callback
)
})
it('should get the latest doc and version with all recent updates', function() {
return this.DiffManager.getLatestDocAndUpdates
.calledWith(this.project_id, this.doc_id, this.fromVersion)
.should.equal(true)
})
it('should rewind the diff', function() {
return sinon.assert.calledOnce(this.rewindUpdatesWithArgs)
})
return it('should call the callback with the rewound document and updates', function() {
return this.callback
.calledWith(null, this.rewound_content, this.updates)
.should.equal(true)
})
})
describe('with mismatching versions', function() {
beforeEach(function() {
this.version = 50
this.updates = [
{ op: 'mock-1', v: 40 },
{ op: 'mock-1', v: 39 }
]
this.DiffManager.getLatestDocAndUpdates = sinon
.stub()
.callsArgWith(3, null, this.content, this.version, this.updates)
return this.DiffManager._tryGetDocumentBeforeVersion(
this.project_id,
this.doc_id,
this.fromVersion,
this.callback
)
})
return it('should call the callback with an error with retry = true set', function() {
this.callback.calledOnce.should.equal(true)
const error = this.callback.args[0][0]
return expect(error.retry).to.equal(true)
})
})
return describe('when the updates are inconsistent', function() {
beforeEach(function() {
this.DiffManager.getLatestDocAndUpdates = sinon
.stub()
.callsArgWith(3, null, this.content, this.version, this.updates)
this.DiffGenerator.rewindUpdates = sinon
.stub()
.throws((this.error = new Error('inconsistent!')))
return this.DiffManager.getDocumentBeforeVersion(
this.project_id,
this.doc_id,
this.fromVersion,
this.callback
)
})
return it('should call the callback with an error', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
})
})

View file

@ -9,88 +9,104 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const chai = require('chai');
chai.should();
const sinon = require("sinon");
const modulePath = "../../../../app/js/MongoAWS.js";
const SandboxedModule = require('sandboxed-module');
const {ObjectId} = require("mongojs");
const MemoryStream = require('memorystream');
const zlib = require("zlib");
const chai = require('chai')
chai.should()
const sinon = require('sinon')
const modulePath = '../../../../app/js/MongoAWS.js'
const SandboxedModule = require('sandboxed-module')
const { ObjectId } = require('mongojs')
const MemoryStream = require('memorystream')
const zlib = require('zlib')
describe("MongoAWS", function() {
beforeEach(function() {
this.MongoAWS = SandboxedModule.require(modulePath, { requires: {
"settings-sharelatex": (this.settings = {
trackchanges: {
s3: {
secret: "s3-secret",
key: "s3-key"
},
stores: {
doc_history: "s3-bucket"
}
}
}),
"child_process": (this.child_process = {}),
"mongo-uri": (this.mongouri = {}),
"logger-sharelatex": (this.logger = {log: sinon.stub(), error: sinon.stub(), err() {}}),
"aws-sdk": (this.awssdk = {}),
"fs": (this.fs = {}),
"s3-streams": (this.S3S = {}),
"./mongojs" : { db: (this.db = {}), ObjectId },
"JSONStream": (this.JSONStream = {}),
"readline-stream": (this.readline = sinon.stub()),
'metrics-sharelatex': {inc(){}}
}
});
describe('MongoAWS', function() {
beforeEach(function() {
this.MongoAWS = SandboxedModule.require(modulePath, {
requires: {
'settings-sharelatex': (this.settings = {
trackchanges: {
s3: {
secret: 's3-secret',
key: 's3-key'
},
stores: {
doc_history: 's3-bucket'
}
}
}),
child_process: (this.child_process = {}),
'mongo-uri': (this.mongouri = {}),
'logger-sharelatex': (this.logger = {
log: sinon.stub(),
error: sinon.stub(),
err() {}
}),
'aws-sdk': (this.awssdk = {}),
fs: (this.fs = {}),
's3-streams': (this.S3S = {}),
'./mongojs': { db: (this.db = {}), ObjectId },
JSONStream: (this.JSONStream = {}),
'readline-stream': (this.readline = sinon.stub()),
'metrics-sharelatex': { inc() {} }
}
})
this.project_id = ObjectId().toString();
this.doc_id = ObjectId().toString();
this.pack_id = ObjectId();
this.update = { v:123 };
return this.callback = sinon.stub();
});
this.project_id = ObjectId().toString()
this.doc_id = ObjectId().toString()
this.pack_id = ObjectId()
this.update = { v: 123 }
return (this.callback = sinon.stub())
})
describe("archivePack", function() {
describe('archivePack', function() {
beforeEach(function(done) {
this.awssdk.config = { update: sinon.stub() }
this.awssdk.S3 = sinon.stub()
this.S3S.WriteStream = () => MemoryStream.createWriteStream()
this.db.docHistory = {}
this.db.docHistory.findOne = sinon
.stub()
.callsArgWith(1, null, { pack: 'hello' })
beforeEach(function(done) {
this.awssdk.config = { update: sinon.stub() };
this.awssdk.S3 = sinon.stub();
this.S3S.WriteStream = () => MemoryStream.createWriteStream();
this.db.docHistory = {};
this.db.docHistory.findOne = sinon.stub().callsArgWith(1, null, {"pack":"hello"});
return this.MongoAWS.archivePack(
this.project_id,
this.doc_id,
this.pack_id,
(err, result) => {
this.callback()
return done()
}
)
})
return this.MongoAWS.archivePack(this.project_id, this.doc_id, this.pack_id, (err, result) => {
this.callback();
return done();
});
});
return it('should call the callback', function() {
return this.callback.called.should.equal(true)
})
})
return it("should call the callback", function() {
return this.callback.called.should.equal(true);
});
});
return describe('unArchivePack', function() {
beforeEach(function(done) {
return zlib.gzip('{"pack":"123"}', (err, zbuf) => {
this.awssdk.config = { update: sinon.stub() }
this.awssdk.S3 = sinon.stub()
this.S3S.ReadStream = () =>
MemoryStream.createReadStream(zbuf, { readable: true })
this.db.docHistory = {}
this.db.docHistory.insert = sinon.stub().callsArgWith(1, null, 'pack')
return describe("unArchivePack", function() {
return this.MongoAWS.unArchivePack(
this.project_id,
this.doc_id,
this.pack_id,
(err, result) => {
this.callback()
return done()
}
)
})
})
beforeEach(function(done) {
return zlib.gzip('{"pack":"123"}', (err, zbuf) => {
this.awssdk.config = { update: sinon.stub() };
this.awssdk.S3 = sinon.stub();
this.S3S.ReadStream = () => MemoryStream.createReadStream(zbuf, {readable:true});
this.db.docHistory = {};
this.db.docHistory.insert = sinon.stub().callsArgWith(1, null, "pack");
return this.MongoAWS.unArchivePack(this.project_id, this.doc_id, this.pack_id, (err, result) => {
this.callback();
return done();
});
});
});
return it("should call db.docHistory.insert", function() {
return this.db.docHistory.insert.called.should.equal(true);
});
});
});
return it('should call db.docHistory.insert', function() {
return this.db.docHistory.insert.called.should.equal(true)
})
})
})

View file

@ -9,127 +9,197 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/DocumentUpdaterManager.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/DocumentUpdaterManager.js'
const SandboxedModule = require('sandboxed-module')
describe("DocumentUpdaterManager", function() {
beforeEach(function() {
this.DocumentUpdaterManager = SandboxedModule.require(modulePath, { requires: {
"request": (this.request = {}),
"logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }),
'settings-sharelatex': (this.settings =
{apis : {documentupdater: {url : "http://example.com"}}})
}
}
);
this.callback = sinon.stub();
this.lines = ["one", "two", "three"];
return this.version = 42;
});
describe('DocumentUpdaterManager', function() {
beforeEach(function() {
this.DocumentUpdaterManager = SandboxedModule.require(modulePath, {
requires: {
request: (this.request = {}),
'logger-sharelatex': (this.logger = {
log: sinon.stub(),
error: sinon.stub()
}),
'settings-sharelatex': (this.settings = {
apis: { documentupdater: { url: 'http://example.com' } }
})
}
})
this.callback = sinon.stub()
this.lines = ['one', 'two', 'three']
return (this.version = 42)
})
describe("getDocument", function() {
describe("successfully", function() {
beforeEach(function() {
this.body = JSON.stringify({
lines: this.lines,
version: this.version,
ops: []});
this.request.get = sinon.stub().callsArgWith(1, null, {statusCode: 200}, this.body);
return this.DocumentUpdaterManager.getDocument(this.project_id, this.doc_id, this.callback);
});
describe('getDocument', function() {
describe('successfully', function() {
beforeEach(function() {
this.body = JSON.stringify({
lines: this.lines,
version: this.version,
ops: []
})
this.request.get = sinon
.stub()
.callsArgWith(1, null, { statusCode: 200 }, this.body)
return this.DocumentUpdaterManager.getDocument(
this.project_id,
this.doc_id,
this.callback
)
})
it('should get the document from the document updater', function() {
const url = `${this.settings.apis.documentupdater.url}/project/${this.project_id}/doc/${this.doc_id}`;
return this.request.get.calledWith(url).should.equal(true);
});
it('should get the document from the document updater', function() {
const url = `${this.settings.apis.documentupdater.url}/project/${this.project_id}/doc/${this.doc_id}`
return this.request.get.calledWith(url).should.equal(true)
})
return it("should call the callback with the content and version", function() {
return this.callback.calledWith(null, this.lines.join("\n"), this.version).should.equal(true);
});
});
return it('should call the callback with the content and version', function() {
return this.callback
.calledWith(null, this.lines.join('\n'), this.version)
.should.equal(true)
})
})
describe("when the document updater API returns an error", function() {
beforeEach(function() {
this.request.get = sinon.stub().callsArgWith(1, (this.error = new Error("something went wrong")), null, null);
return this.DocumentUpdaterManager.getDocument(this.project_id, this.doc_id, this.callback);
});
describe('when the document updater API returns an error', function() {
beforeEach(function() {
this.request.get = sinon
.stub()
.callsArgWith(
1,
(this.error = new Error('something went wrong')),
null,
null
)
return this.DocumentUpdaterManager.getDocument(
this.project_id,
this.doc_id,
this.callback
)
})
return it("should return an error to the callback", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
});
return it('should return an error to the callback', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
return describe("when the document updater returns a failure error code", function() {
beforeEach(function() {
this.request.get = sinon.stub().callsArgWith(1, null, { statusCode: 500 }, "");
return this.DocumentUpdaterManager.getDocument(this.project_id, this.doc_id, this.callback);
});
return describe('when the document updater returns a failure error code', function() {
beforeEach(function() {
this.request.get = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
return this.DocumentUpdaterManager.getDocument(
this.project_id,
this.doc_id,
this.callback
)
})
return it("should return the callback with an error", function() {
return this.callback
.calledWith(sinon.match.has('message', "doc updater returned a non-success status code: 500"))
.should.equal(true);
});
});
});
return it('should return the callback with an error', function() {
return this.callback
.calledWith(
sinon.match.has(
'message',
'doc updater returned a non-success status code: 500'
)
)
.should.equal(true)
})
})
})
return describe("setDocument", function() {
beforeEach(function() {
this.content = "mock content";
return this.user_id = "user-id-123";
});
return describe('setDocument', function() {
beforeEach(function() {
this.content = 'mock content'
return (this.user_id = 'user-id-123')
})
describe("successfully", function() {
beforeEach(function() {
this.request.post = sinon.stub().callsArgWith(1, null, {statusCode: 200});
return this.DocumentUpdaterManager.setDocument(this.project_id, this.doc_id, this.content, this.user_id, this.callback);
});
describe('successfully', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 200 })
return this.DocumentUpdaterManager.setDocument(
this.project_id,
this.doc_id,
this.content,
this.user_id,
this.callback
)
})
it('should set the document in the document updater', function() {
const url = `${this.settings.apis.documentupdater.url}/project/${this.project_id}/doc/${this.doc_id}`;
return this.request.post
.calledWith({
url,
json: {
lines: this.content.split("\n"),
source: "restore",
user_id: this.user_id,
undoing: true
}
}).should.equal(true);
});
it('should set the document in the document updater', function() {
const url = `${this.settings.apis.documentupdater.url}/project/${this.project_id}/doc/${this.doc_id}`
return this.request.post
.calledWith({
url,
json: {
lines: this.content.split('\n'),
source: 'restore',
user_id: this.user_id,
undoing: true
}
})
.should.equal(true)
})
return it("should call the callback", function() {
return this.callback.calledWith(null).should.equal(true);
});
});
return it('should call the callback', function() {
return this.callback.calledWith(null).should.equal(true)
})
})
describe("when the document updater API returns an error", function() {
beforeEach(function() {
this.request.post = sinon.stub().callsArgWith(1, (this.error = new Error("something went wrong")), null, null);
return this.DocumentUpdaterManager.setDocument(this.project_id, this.doc_id, this.content, this.user_id, this.callback);
});
describe('when the document updater API returns an error', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(
1,
(this.error = new Error('something went wrong')),
null,
null
)
return this.DocumentUpdaterManager.setDocument(
this.project_id,
this.doc_id,
this.content,
this.user_id,
this.callback
)
})
return it("should return an error to the callback", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
});
return it('should return an error to the callback', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
return describe("when the document updater returns a failure error code", function() {
beforeEach(function() {
this.request.post = sinon.stub().callsArgWith(1, null, { statusCode: 500 }, "");
return this.DocumentUpdaterManager.setDocument(this.project_id, this.doc_id, this.content, this.user_id, this.callback);
});
return describe('when the document updater returns a failure error code', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
return this.DocumentUpdaterManager.setDocument(
this.project_id,
this.doc_id,
this.content,
this.user_id,
this.callback
)
})
return it("should return the callback with an error", function() {
return this.callback
.calledWith(sinon.match.has('message', "doc updater returned a non-success status code: 500"))
.should.equal(true);
});
});
});
});
return it('should return the callback with an error', function() {
return this.callback
.calledWith(
sinon.match.has(
'message',
'doc updater returned a non-success status code: 500'
)
)
.should.equal(true)
})
})
})
})

View file

@ -9,175 +9,193 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/HttpController.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/HttpController.js'
const SandboxedModule = require('sandboxed-module')
describe("HttpController", function() {
beforeEach(function() {
this.HttpController = SandboxedModule.require(modulePath, { requires: {
"logger-sharelatex": { log: sinon.stub() },
"./UpdatesManager": (this.UpdatesManager = {}),
"./DiffManager": (this.DiffManager = {}),
"./RestoreManager": (this.RestoreManager = {}),
"./PackManager": (this.PackManager = {}),
"./DocArchiveManager": (this.DocArchiveManager = {}),
"./HealthChecker": (this.HealthChecker = {})
}
});
this.doc_id = "doc-id-123";
this.project_id = "project-id-123";
this.next = sinon.stub();
this.user_id = "mock-user-123";
return this.now = Date.now();
});
describe('HttpController', function() {
beforeEach(function() {
this.HttpController = SandboxedModule.require(modulePath, {
requires: {
'logger-sharelatex': { log: sinon.stub() },
'./UpdatesManager': (this.UpdatesManager = {}),
'./DiffManager': (this.DiffManager = {}),
'./RestoreManager': (this.RestoreManager = {}),
'./PackManager': (this.PackManager = {}),
'./DocArchiveManager': (this.DocArchiveManager = {}),
'./HealthChecker': (this.HealthChecker = {})
}
})
this.doc_id = 'doc-id-123'
this.project_id = 'project-id-123'
this.next = sinon.stub()
this.user_id = 'mock-user-123'
return (this.now = Date.now())
})
describe("flushDoc", function() {
beforeEach(function() {
this.req = {
params: {
doc_id: this.doc_id,
project_id: this.project_id
}
};
this.res =
{send: sinon.stub()};
this.UpdatesManager.processUncompressedUpdatesWithLock = sinon.stub().callsArg(2);
return this.HttpController.flushDoc(this.req, this.res, this.next);
});
describe('flushDoc', function() {
beforeEach(function() {
this.req = {
params: {
doc_id: this.doc_id,
project_id: this.project_id
}
}
this.res = { send: sinon.stub() }
this.UpdatesManager.processUncompressedUpdatesWithLock = sinon
.stub()
.callsArg(2)
return this.HttpController.flushDoc(this.req, this.res, this.next)
})
it("should process the updates", function() {
return this.UpdatesManager.processUncompressedUpdatesWithLock
.calledWith(this.project_id, this.doc_id)
.should.equal(true);
});
it('should process the updates', function() {
return this.UpdatesManager.processUncompressedUpdatesWithLock
.calledWith(this.project_id, this.doc_id)
.should.equal(true)
})
return it("should return a success code", function() {
return this.res.send.calledWith(204).should.equal(true);
});
});
return it('should return a success code', function() {
return this.res.send.calledWith(204).should.equal(true)
})
})
describe("flushProject", function() {
beforeEach(function() {
this.req = {
params: {
project_id: this.project_id
}
};
this.res =
{send: sinon.stub()};
this.UpdatesManager.processUncompressedUpdatesForProject = sinon.stub().callsArg(1);
return this.HttpController.flushProject(this.req, this.res, this.next);
});
describe('flushProject', function() {
beforeEach(function() {
this.req = {
params: {
project_id: this.project_id
}
}
this.res = { send: sinon.stub() }
this.UpdatesManager.processUncompressedUpdatesForProject = sinon
.stub()
.callsArg(1)
return this.HttpController.flushProject(this.req, this.res, this.next)
})
it("should process the updates", function() {
return this.UpdatesManager.processUncompressedUpdatesForProject
.calledWith(this.project_id)
.should.equal(true);
});
it('should process the updates', function() {
return this.UpdatesManager.processUncompressedUpdatesForProject
.calledWith(this.project_id)
.should.equal(true)
})
return it("should return a success code", function() {
return this.res.send.calledWith(204).should.equal(true);
});
});
return it('should return a success code', function() {
return this.res.send.calledWith(204).should.equal(true)
})
})
describe('getDiff', function() {
beforeEach(function() {
this.from = 42
this.to = 45
this.req = {
params: {
doc_id: this.doc_id,
project_id: this.project_id
},
query: {
from: this.from.toString(),
to: this.to.toString()
}
}
this.res = { json: sinon.stub() }
this.diff = [{ u: 'mock-diff' }]
this.DiffManager.getDiff = sinon.stub().callsArgWith(4, null, this.diff)
return this.HttpController.getDiff(this.req, this.res, this.next)
})
describe("getDiff", function() {
beforeEach(function() {
this.from = 42;
this.to = 45;
this.req = {
params: {
doc_id: this.doc_id,
project_id: this.project_id
},
query: {
from: this.from.toString(),
to: this.to.toString()
}
};
this.res =
{json: sinon.stub()};
this.diff = [ {u: "mock-diff"} ];
this.DiffManager.getDiff = sinon.stub().callsArgWith(4, null, this.diff);
return this.HttpController.getDiff(this.req, this.res, this.next);
});
it('should get the diff', function() {
return this.DiffManager.getDiff
.calledWith(
this.project_id,
this.doc_id,
parseInt(this.from, 10),
parseInt(this.to, 10)
)
.should.equal(true)
})
it("should get the diff", function() {
return this.DiffManager.getDiff
.calledWith(this.project_id, this.doc_id, parseInt(this.from, 10), parseInt(this.to, 10))
.should.equal(true);
});
return it('should return the diff', function() {
return this.res.json.calledWith({ diff: this.diff }).should.equal(true)
})
})
return it("should return the diff", function() {
return this.res.json.calledWith({diff: this.diff}).should.equal(true);
});
});
describe('getUpdates', function() {
beforeEach(function() {
this.before = Date.now()
this.nextBeforeTimestamp = this.before - 100
this.min_count = 10
this.req = {
params: {
project_id: this.project_id
},
query: {
before: this.before.toString(),
min_count: this.min_count.toString()
}
}
this.res = { json: sinon.stub() }
this.updates = ['mock-summarized-updates']
this.UpdatesManager.getSummarizedProjectUpdates = sinon
.stub()
.callsArgWith(2, null, this.updates, this.nextBeforeTimestamp)
return this.HttpController.getUpdates(this.req, this.res, this.next)
})
describe("getUpdates", function() {
beforeEach(function() {
this.before = Date.now();
this.nextBeforeTimestamp = this.before - 100;
this.min_count = 10;
this.req = {
params: {
project_id: this.project_id
},
query: {
before: this.before.toString(),
min_count: this.min_count.toString()
}
};
this.res =
{json: sinon.stub()};
this.updates = ["mock-summarized-updates"];
this.UpdatesManager.getSummarizedProjectUpdates = sinon.stub().callsArgWith(2, null, this.updates, this.nextBeforeTimestamp);
return this.HttpController.getUpdates(this.req, this.res, this.next);
});
it('should get the updates', function() {
return this.UpdatesManager.getSummarizedProjectUpdates
.calledWith(this.project_id, {
before: this.before,
min_count: this.min_count
})
.should.equal(true)
})
it("should get the updates", function() {
return this.UpdatesManager.getSummarizedProjectUpdates
.calledWith(this.project_id, {before: this.before, min_count: this.min_count})
.should.equal(true);
});
return it('should return the formatted updates', function() {
return this.res.json
.calledWith({
updates: this.updates,
nextBeforeTimestamp: this.nextBeforeTimestamp
})
.should.equal(true)
})
})
return it("should return the formatted updates", function() {
return this.res.json.calledWith({updates: this.updates, nextBeforeTimestamp: this.nextBeforeTimestamp}).should.equal(true);
});
});
return describe('RestoreManager', function() {
beforeEach(function() {
this.version = '42'
this.req = {
params: {
doc_id: this.doc_id,
project_id: this.project_id,
version: this.version
},
headers: {
'x-user-id': this.user_id
}
}
this.res = { send: sinon.stub() }
return describe("RestoreManager", function() {
beforeEach(function() {
this.version = "42";
this.req = {
params: {
doc_id: this.doc_id,
project_id: this.project_id,
version: this.version
},
headers: {
"x-user-id": this.user_id
}
};
this.res =
{send: sinon.stub()};
this.RestoreManager.restoreToBeforeVersion = sinon.stub().callsArg(4)
return this.HttpController.restore(this.req, this.res, this.next)
})
this.RestoreManager.restoreToBeforeVersion = sinon.stub().callsArg(4);
return this.HttpController.restore(this.req, this.res, this.next);
});
it("should restore the document", function() {
return this.RestoreManager.restoreToBeforeVersion
.calledWith(this.project_id, this.doc_id, parseInt(this.version, 10), this.user_id)
.should.equal(true);
});
return it("should return a success code", function() {
return this.res.send.calledWith(204).should.equal(true);
});
});
});
it('should restore the document', function() {
return this.RestoreManager.restoreToBeforeVersion
.calledWith(
this.project_id,
this.doc_id,
parseInt(this.version, 10),
this.user_id
)
.should.equal(true)
})
return it('should return a success code', function() {
return this.res.send.calledWith(204).should.equal(true)
})
})
})

View file

@ -15,270 +15,306 @@
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/LockManager.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/LockManager.js'
const SandboxedModule = require('sandboxed-module')
describe("LockManager", function() {
beforeEach(function() {
this.Settings = {
redis: {
lock:{}
}
};
this.LockManager = SandboxedModule.require(modulePath, { requires: {
"redis-sharelatex": {
createClient: () => { return this.rclient =
{auth: sinon.stub()}; }
},
"settings-sharelatex": this.Settings,
"logger-sharelatex": {error() {}}
}
});
describe('LockManager', function() {
beforeEach(function() {
this.Settings = {
redis: {
lock: {}
}
}
this.LockManager = SandboxedModule.require(modulePath, {
requires: {
'redis-sharelatex': {
createClient: () => {
return (this.rclient = { auth: sinon.stub() })
}
},
'settings-sharelatex': this.Settings,
'logger-sharelatex': { error() {} }
}
})
this.key = "lock-key";
return this.callback = sinon.stub();
});
this.key = 'lock-key'
return (this.callback = sinon.stub())
})
describe("checkLock", function() {
describe("when the lock is taken", function() {
beforeEach(function() {
this.rclient.exists = sinon.stub().callsArgWith(1, null, "1");
return this.LockManager.checkLock(this.key, this.callback);
});
describe('checkLock', function() {
describe('when the lock is taken', function() {
beforeEach(function() {
this.rclient.exists = sinon.stub().callsArgWith(1, null, '1')
return this.LockManager.checkLock(this.key, this.callback)
})
it("should check the lock in redis", function() {
return this.rclient.exists
.calledWith(this.key)
.should.equal(true);
});
it('should check the lock in redis', function() {
return this.rclient.exists.calledWith(this.key).should.equal(true)
})
return it("should return the callback with false", function() {
return this.callback.calledWith(null, false).should.equal(true);
});
});
return it('should return the callback with false', function() {
return this.callback.calledWith(null, false).should.equal(true)
})
})
return describe("when the lock is free", function() {
beforeEach(function() {
this.rclient.exists = sinon.stub().callsArgWith(1, null, "0");
return this.LockManager.checkLock(this.key, this.callback);
});
return describe('when the lock is free', function() {
beforeEach(function() {
this.rclient.exists = sinon.stub().callsArgWith(1, null, '0')
return this.LockManager.checkLock(this.key, this.callback)
})
return it("should return the callback with true", function() {
return this.callback.calledWith(null, true).should.equal(true);
});
});
});
return it('should return the callback with true', function() {
return this.callback.calledWith(null, true).should.equal(true)
})
})
})
describe('tryLock', function() {
describe('when the lock is taken', function() {
beforeEach(function() {
this.rclient.set = sinon.stub().callsArgWith(5, null, null)
this.LockManager.randomLock = sinon
.stub()
.returns('locked-random-value')
return this.LockManager.tryLock(this.key, this.callback)
})
describe("tryLock", function() {
describe("when the lock is taken", function() {
beforeEach(function() {
this.rclient.set = sinon.stub().callsArgWith(5, null, null);
this.LockManager.randomLock = sinon.stub().returns("locked-random-value");
return this.LockManager.tryLock(this.key, this.callback);
});
it('should check the lock in redis', function() {
return this.rclient.set
.calledWith(
this.key,
'locked-random-value',
'EX',
this.LockManager.LOCK_TTL,
'NX'
)
.should.equal(true)
})
it("should check the lock in redis", function() {
return this.rclient.set
.calledWith(this.key, "locked-random-value", "EX", this.LockManager.LOCK_TTL, "NX")
.should.equal(true);
});
return it('should return the callback with false', function() {
return this.callback.calledWith(null, false).should.equal(true)
})
})
return it("should return the callback with false", function() {
return this.callback.calledWith(null, false).should.equal(true);
});
});
return describe('when the lock is free', function() {
beforeEach(function() {
this.rclient.set = sinon.stub().callsArgWith(5, null, 'OK')
return this.LockManager.tryLock(this.key, this.callback)
})
return describe("when the lock is free", function() {
beforeEach(function() {
this.rclient.set = sinon.stub().callsArgWith(5, null, "OK");
return this.LockManager.tryLock(this.key, this.callback);
});
return it('should return the callback with true', function() {
return this.callback.calledWith(null, true).should.equal(true)
})
})
})
return it("should return the callback with true", function() {
return this.callback.calledWith(null, true).should.equal(true);
});
});
});
describe('deleteLock', function() {
return beforeEach(function() {
beforeEach(function() {
this.rclient.del = sinon.stub().callsArg(1)
return this.LockManager.deleteLock(this.key, this.callback)
})
describe("deleteLock", function() { return beforeEach(function() {
beforeEach(function() {
this.rclient.del = sinon.stub().callsArg(1);
return this.LockManager.deleteLock(this.key, this.callback);
});
it('should delete the lock in redis', function() {
return this.rclient.del.calledWith(key).should.equal(true)
})
it("should delete the lock in redis", function() {
return this.rclient.del
.calledWith(key)
.should.equal(true);
});
return it('should call the callback', function() {
return this.callback.called.should.equal(true)
})
})
})
return it("should call the callback", function() {
return this.callback.called.should.equal(true);
});
}); }
);
describe('getLock', function() {
describe('when the lock is not taken', function() {
beforeEach(function(done) {
this.LockManager.tryLock = sinon.stub().callsArgWith(1, null, true)
return this.LockManager.getLock(this.key, (...args) => {
this.callback(...Array.from(args || []))
return done()
})
})
describe("getLock", function() {
describe("when the lock is not taken", function() {
beforeEach(function(done) {
this.LockManager.tryLock = sinon.stub().callsArgWith(1, null, true);
return this.LockManager.getLock(this.key, (...args) => {
this.callback(...Array.from(args || []));
return done();
});
});
it('should try to get the lock', function() {
return this.LockManager.tryLock.calledWith(this.key).should.equal(true)
})
it("should try to get the lock", function() {
return this.LockManager.tryLock
.calledWith(this.key)
.should.equal(true);
});
it('should only need to try once', function() {
return this.LockManager.tryLock.callCount.should.equal(1)
})
it("should only need to try once", function() {
return this.LockManager.tryLock.callCount.should.equal(1);
});
return it('should return the callback', function() {
return this.callback.calledWith(null).should.equal(true)
})
})
return it("should return the callback", function() {
return this.callback.calledWith(null).should.equal(true);
});
});
describe('when the lock is initially set', function() {
beforeEach(function(done) {
const startTime = Date.now()
this.LockManager.LOCK_TEST_INTERVAL = 5
this.LockManager.tryLock = function(doc_id, callback) {
if (callback == null) {
callback = function(error, isFree) {}
}
if (Date.now() - startTime < 100) {
return callback(null, false)
} else {
return callback(null, true)
}
}
sinon.spy(this.LockManager, 'tryLock')
describe("when the lock is initially set", function() {
beforeEach(function(done) {
const startTime = Date.now();
this.LockManager.LOCK_TEST_INTERVAL = 5;
this.LockManager.tryLock = function(doc_id, callback) {
if (callback == null) { callback = function(error, isFree) {}; }
if ((Date.now() - startTime) < 100) {
return callback(null, false);
} else {
return callback(null, true);
}
};
sinon.spy(this.LockManager, "tryLock");
return this.LockManager.getLock(this.key, (...args) => {
this.callback(...Array.from(args || []))
return done()
})
})
return this.LockManager.getLock(this.key, (...args) => {
this.callback(...Array.from(args || []));
return done();
});
});
it('should call tryLock multiple times until free', function() {
return (this.LockManager.tryLock.callCount > 1).should.equal(true)
})
it("should call tryLock multiple times until free", function() {
return (this.LockManager.tryLock.callCount > 1).should.equal(true);
});
return it('should return the callback', function() {
return this.callback.calledWith(null).should.equal(true)
})
})
return it("should return the callback", function() {
return this.callback.calledWith(null).should.equal(true);
});
});
return describe('when the lock times out', function() {
beforeEach(function(done) {
const time = Date.now()
this.LockManager.MAX_LOCK_WAIT_TIME = 5
this.LockManager.tryLock = sinon.stub().callsArgWith(1, null, false)
return this.LockManager.getLock(this.key, (...args) => {
this.callback(...Array.from(args || []))
return done()
})
})
return describe("when the lock times out", function() {
beforeEach(function(done) {
const time = Date.now();
this.LockManager.MAX_LOCK_WAIT_TIME = 5;
this.LockManager.tryLock = sinon.stub().callsArgWith(1, null, false);
return this.LockManager.getLock(this.key, (...args) => {
this.callback(...Array.from(args || []));
return done();
});
});
return it('should return the callback with an error', function() {
return this.callback
.calledWith(sinon.match.instanceOf(Error))
.should.equal(true)
})
})
})
return it("should return the callback with an error", function() {
return this.callback.calledWith(sinon.match.instanceOf(Error)).should.equal(true);
});
});
});
return describe('runWithLock', function() {
describe('with successful run', function() {
beforeEach(function() {
this.runner = function(releaseLock) {
if (releaseLock == null) {
releaseLock = function(error) {}
}
return releaseLock()
}
sinon.spy(this, 'runner')
this.LockManager.getLock = sinon.stub().callsArg(1)
this.LockManager.releaseLock = sinon.stub().callsArg(2)
return this.LockManager.runWithLock(
this.key,
this.runner,
this.callback
)
})
return describe("runWithLock", function() {
describe("with successful run", function() {
beforeEach(function() {
this.runner = function(releaseLock) {
if (releaseLock == null) { releaseLock = function(error) {}; }
return releaseLock();
};
sinon.spy(this, "runner");
this.LockManager.getLock = sinon.stub().callsArg(1);
this.LockManager.releaseLock = sinon.stub().callsArg(2);
return this.LockManager.runWithLock(this.key, this.runner, this.callback);
});
it('should get the lock', function() {
return this.LockManager.getLock.calledWith(this.key).should.equal(true)
})
it("should get the lock", function() {
return this.LockManager.getLock
.calledWith(this.key)
.should.equal(true);
});
it('should run the passed function', function() {
return this.runner.called.should.equal(true)
})
it("should run the passed function", function() {
return this.runner.called.should.equal(true);
});
it('should release the lock', function() {
return this.LockManager.releaseLock
.calledWith(this.key)
.should.equal(true)
})
it("should release the lock", function() {
return this.LockManager.releaseLock
.calledWith(this.key)
.should.equal(true);
});
return it('should call the callback', function() {
return this.callback.called.should.equal(true)
})
})
return it("should call the callback", function() {
return this.callback.called.should.equal(true);
});
});
describe('when the runner function returns an error', function() {
beforeEach(function() {
this.error = new Error('oops')
this.runner = releaseLock => {
if (releaseLock == null) {
releaseLock = function(error) {}
}
return releaseLock(this.error)
}
sinon.spy(this, 'runner')
this.LockManager.getLock = sinon.stub().callsArg(1)
this.LockManager.releaseLock = sinon.stub().callsArg(2)
return this.LockManager.runWithLock(
this.key,
this.runner,
this.callback
)
})
describe("when the runner function returns an error", function() {
beforeEach(function() {
this.error = new Error("oops");
this.runner = releaseLock => {
if (releaseLock == null) { releaseLock = function(error) {}; }
return releaseLock(this.error);
};
sinon.spy(this, "runner");
this.LockManager.getLock = sinon.stub().callsArg(1);
this.LockManager.releaseLock = sinon.stub().callsArg(2);
return this.LockManager.runWithLock(this.key, this.runner, this.callback);
});
it('should release the lock', function() {
return this.LockManager.releaseLock
.calledWith(this.key)
.should.equal(true)
})
it("should release the lock", function() {
return this.LockManager.releaseLock
.calledWith(this.key)
.should.equal(true);
});
return it('should call the callback with the error', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
return it("should call the callback with the error", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
});
return describe('releaseLock', function() {
describe('when the lock is current', function() {
beforeEach(function() {
this.rclient.eval = sinon.stub().yields(null, 1)
return this.LockManager.releaseLock(
this.key,
this.lockValue,
this.callback
)
})
return describe("releaseLock", function() {
describe("when the lock is current", function() {
beforeEach(function() {
this.rclient.eval = sinon.stub().yields(null, 1);
return this.LockManager.releaseLock(this.key, this.lockValue, this.callback);
});
it('should clear the data from redis', function() {
return this.rclient.eval
.calledWith(
this.LockManager.unlockScript,
1,
this.key,
this.lockValue
)
.should.equal(true)
})
it('should clear the data from redis', function() {
return this.rclient.eval.calledWith(this.LockManager.unlockScript, 1, this.key, this.lockValue).should.equal(true);
});
return it('should call the callback', function() {
return this.callback.called.should.equal(true)
})
})
return it('should call the callback', function() {
return this.callback.called.should.equal(true);
});
});
return describe("when the lock has expired", function() {
beforeEach(function() {
this.rclient.eval = sinon.stub().yields(null, 0);
return this.LockManager.releaseLock(this.key, this.lockValue, this.callback);
});
return it('should return an error if the lock has expired', function() {
return this.callback.calledWith(sinon.match.has('message', "tried to release timed out lock")).should.equal(true);
});
});
});
});
});
return describe('when the lock has expired', function() {
beforeEach(function() {
this.rclient.eval = sinon.stub().yields(null, 0)
return this.LockManager.releaseLock(
this.key,
this.lockValue,
this.callback
)
})
return it('should return an error if the lock has expired', function() {
return this.callback
.calledWith(
sinon.match.has('message', 'tried to release timed out lock')
)
.should.equal(true)
})
})
})
})
})

View file

@ -9,195 +9,237 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/MongoManager.js";
const packModulePath = "../../../../app/js/PackManager.js";
const SandboxedModule = require('sandboxed-module');
const {ObjectId} = require("mongojs");
const tk = require("timekeeper");
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/MongoManager.js'
const packModulePath = '../../../../app/js/PackManager.js'
const SandboxedModule = require('sandboxed-module')
const { ObjectId } = require('mongojs')
const tk = require('timekeeper')
describe("MongoManager", function() {
beforeEach(function() {
tk.freeze(new Date());
this.MongoManager = SandboxedModule.require(modulePath, { requires: {
"./mongojs" : { db: (this.db = {}), ObjectId },
"./PackManager" : (this.PackManager = {}),
'metrics-sharelatex': {timeAsyncMethod(){}},
'logger-sharelatex': {log(){}}
}
});
this.callback = sinon.stub();
this.doc_id = ObjectId().toString();
return this.project_id = ObjectId().toString();
});
describe('MongoManager', function() {
beforeEach(function() {
tk.freeze(new Date())
this.MongoManager = SandboxedModule.require(modulePath, {
requires: {
'./mongojs': { db: (this.db = {}), ObjectId },
'./PackManager': (this.PackManager = {}),
'metrics-sharelatex': { timeAsyncMethod() {} },
'logger-sharelatex': { log() {} }
}
})
this.callback = sinon.stub()
this.doc_id = ObjectId().toString()
return (this.project_id = ObjectId().toString())
})
afterEach(function() { return tk.reset(); });
afterEach(function() {
return tk.reset()
})
describe("getLastCompressedUpdate", function() {
beforeEach(function() {
this.update = "mock-update";
this.db.docHistory = {};
this.db.docHistory.find = sinon.stub().returns(this.db.docHistory);
this.db.docHistory.findOne = sinon.stub().returns(this.db.docHistory);
this.db.docHistory.sort = sinon.stub().returns(this.db.docHistory);
this.db.docHistory.limit = sinon.stub().returns(this.db.docHistory);
this.db.docHistory.toArray = sinon.stub().callsArgWith(0, null, [this.update]);
describe('getLastCompressedUpdate', function() {
beforeEach(function() {
this.update = 'mock-update'
this.db.docHistory = {}
this.db.docHistory.find = sinon.stub().returns(this.db.docHistory)
this.db.docHistory.findOne = sinon.stub().returns(this.db.docHistory)
this.db.docHistory.sort = sinon.stub().returns(this.db.docHistory)
this.db.docHistory.limit = sinon.stub().returns(this.db.docHistory)
this.db.docHistory.toArray = sinon
.stub()
.callsArgWith(0, null, [this.update])
return this.MongoManager.getLastCompressedUpdate(this.doc_id, this.callback);
});
return this.MongoManager.getLastCompressedUpdate(
this.doc_id,
this.callback
)
})
it("should find the updates for the doc", function() {
return this.db.docHistory.find
.calledWith({doc_id: ObjectId(this.doc_id)})
.should.equal(true);
});
it('should find the updates for the doc', function() {
return this.db.docHistory.find
.calledWith({ doc_id: ObjectId(this.doc_id) })
.should.equal(true)
})
it("should limit to one result", function() {
return this.db.docHistory.limit
.calledWith(1)
.should.equal(true);
});
it('should limit to one result', function() {
return this.db.docHistory.limit.calledWith(1).should.equal(true)
})
it("should sort in descending version order", function() {
return this.db.docHistory.sort
.calledWith({v: -1})
.should.equal(true);
});
it('should sort in descending version order', function() {
return this.db.docHistory.sort.calledWith({ v: -1 }).should.equal(true)
})
return it("should call the call back with the update", function() {
return this.callback.calledWith(null, this.update).should.equal(true);
});
});
return it('should call the call back with the update', function() {
return this.callback.calledWith(null, this.update).should.equal(true)
})
})
describe('peekLastCompressedUpdate', function() {
describe('when there is no last update', function() {
beforeEach(function() {
this.PackManager.getLastPackFromIndex = sinon
.stub()
.callsArgWith(1, null, null)
this.MongoManager.getLastCompressedUpdate = sinon
.stub()
.callsArgWith(1, null, null)
return this.MongoManager.peekLastCompressedUpdate(
this.doc_id,
this.callback
)
})
describe("peekLastCompressedUpdate", function() {
describe("when there is no last update", function() {
beforeEach(function() {
this.PackManager.getLastPackFromIndex = sinon.stub().callsArgWith(1, null, null);
this.MongoManager.getLastCompressedUpdate = sinon.stub().callsArgWith(1, null, null);
return this.MongoManager.peekLastCompressedUpdate(this.doc_id, this.callback);
});
it('should get the last update', function() {
return this.MongoManager.getLastCompressedUpdate
.calledWith(this.doc_id)
.should.equal(true)
})
it("should get the last update", function() {
return this.MongoManager.getLastCompressedUpdate
.calledWith(this.doc_id)
.should.equal(true);
});
return it('should call the callback with no update', function() {
return this.callback.calledWith(null, null).should.equal(true)
})
})
return it("should call the callback with no update", function() {
return this.callback.calledWith(null, null).should.equal(true);
});
});
describe('when there is an update', function() {
beforeEach(function() {
this.update = { _id: Object() }
this.MongoManager.getLastCompressedUpdate = sinon
.stub()
.callsArgWith(1, null, this.update)
return this.MongoManager.peekLastCompressedUpdate(
this.doc_id,
this.callback
)
})
describe("when there is an update", function() {
beforeEach(function() {
this.update = { _id: Object() };
this.MongoManager.getLastCompressedUpdate = sinon.stub().callsArgWith(1, null, this.update);
return this.MongoManager.peekLastCompressedUpdate(this.doc_id, this.callback);
});
it('should get the last update', function() {
return this.MongoManager.getLastCompressedUpdate
.calledWith(this.doc_id)
.should.equal(true)
})
it("should get the last update", function() {
return this.MongoManager.getLastCompressedUpdate
.calledWith(this.doc_id)
.should.equal(true);
});
return it('should call the callback with the update', function() {
return this.callback.calledWith(null, this.update).should.equal(true)
})
})
return it("should call the callback with the update", function() {
return this.callback.calledWith(null, this.update).should.equal(true);
});
});
return describe('when there is a last update in S3', function() {
beforeEach(function() {
this.update = { _id: Object(), v: 12345, v_end: 12345, inS3: true }
this.PackManager.getLastPackFromIndex = sinon
.stub()
.callsArgWith(1, null, this.update)
this.MongoManager.getLastCompressedUpdate = sinon
.stub()
.callsArgWith(1, null)
return this.MongoManager.peekLastCompressedUpdate(
this.doc_id,
this.callback
)
})
return describe("when there is a last update in S3", function() {
beforeEach(function() {
this.update = { _id: Object(), v: 12345, v_end: 12345, inS3:true};
this.PackManager.getLastPackFromIndex = sinon.stub().callsArgWith(1, null, this.update);
this.MongoManager.getLastCompressedUpdate = sinon.stub().callsArgWith(1, null);
return this.MongoManager.peekLastCompressedUpdate(this.doc_id, this.callback);
});
it('should get the last update', function() {
return this.MongoManager.getLastCompressedUpdate
.calledWith(this.doc_id)
.should.equal(true)
})
it("should get the last update", function() {
return this.MongoManager.getLastCompressedUpdate
.calledWith(this.doc_id)
.should.equal(true);
});
return it('should call the callback with a null update and the correct version', function() {
return this.callback
.calledWith(null, null, this.update.v_end)
.should.equal(true)
})
})
})
return it("should call the callback with a null update and the correct version", function() {
return this.callback.calledWith(null, null, this.update.v_end).should.equal(true);
});
});
});
describe('backportProjectId', function() {
beforeEach(function() {
this.db.docHistory = { update: sinon.stub().callsArg(3) }
return this.MongoManager.backportProjectId(
this.project_id,
this.doc_id,
this.callback
)
})
it("should insert the project_id into all entries for the doc_id which don't have it set", function() {
return this.db.docHistory.update
.calledWith(
{
doc_id: ObjectId(this.doc_id),
project_id: { $exists: false }
},
{
$set: { project_id: ObjectId(this.project_id) }
},
{
multi: true
}
)
.should.equal(true)
})
describe("backportProjectId", function() {
beforeEach(function() {
this.db.docHistory =
{update: sinon.stub().callsArg(3)};
return this.MongoManager.backportProjectId(this.project_id, this.doc_id, this.callback);
});
return it('should call the callback', function() {
return this.callback.called.should.equal(true)
})
})
it("should insert the project_id into all entries for the doc_id which don't have it set", function() {
return this.db.docHistory.update
.calledWith({
doc_id: ObjectId(this.doc_id),
project_id: { $exists: false }
}, {
$set: { project_id: ObjectId(this.project_id) }
}, {
multi: true
})
.should.equal(true);
});
describe('getProjectMetaData', function() {
beforeEach(function() {
this.metadata = { mock: 'metadata' }
this.db.projectHistoryMetaData = {
find: sinon.stub().callsArgWith(1, null, [this.metadata])
}
return this.MongoManager.getProjectMetaData(
this.project_id,
this.callback
)
})
return it("should call the callback", function() {
return this.callback.called.should.equal(true);
});
});
it('should look up the meta data in the db', function() {
return this.db.projectHistoryMetaData.find
.calledWith({ project_id: ObjectId(this.project_id) })
.should.equal(true)
})
describe("getProjectMetaData", function() {
beforeEach(function() {
this.metadata = { "mock": "metadata" };
this.db.projectHistoryMetaData =
{find: sinon.stub().callsArgWith(1, null, [this.metadata])};
return this.MongoManager.getProjectMetaData(this.project_id, this.callback);
});
return it('should return the metadata', function() {
return this.callback.calledWith(null, this.metadata).should.equal(true)
})
})
it("should look up the meta data in the db", function() {
return this.db.projectHistoryMetaData.find
.calledWith({ project_id: ObjectId(this.project_id) })
.should.equal(true);
});
return describe('setProjectMetaData', function() {
beforeEach(function() {
this.metadata = { mock: 'metadata' }
this.db.projectHistoryMetaData = {
update: sinon.stub().callsArgWith(3, null, [this.metadata])
}
return this.MongoManager.setProjectMetaData(
this.project_id,
this.metadata,
this.callback
)
})
return it("should return the metadata", function() {
return this.callback.calledWith(null, this.metadata).should.equal(true);
});
});
return describe("setProjectMetaData", function() {
beforeEach(function() {
this.metadata = { "mock": "metadata" };
this.db.projectHistoryMetaData =
{update: sinon.stub().callsArgWith(3, null, [this.metadata])};
return this.MongoManager.setProjectMetaData(this.project_id, this.metadata, this.callback);
});
it("should upsert the metadata into the DB", function() {
return this.db.projectHistoryMetaData.update
.calledWith({
project_id: ObjectId(this.project_id)
}, {
$set: this.metadata
}, {
upsert: true
})
.should.equal(true);
});
return it("should call the callback", function() {
return this.callback.called.should.equal(true);
});
});
});
it('should upsert the metadata into the DB', function() {
return this.db.projectHistoryMetaData.update
.calledWith(
{
project_id: ObjectId(this.project_id)
},
{
$set: this.metadata
},
{
upsert: true
}
)
.should.equal(true)
})
return it('should call the callback', function() {
return this.callback.called.should.equal(true)
})
})
})

View file

@ -11,118 +11,156 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/RedisManager.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/RedisManager.js'
const SandboxedModule = require('sandboxed-module')
describe("RedisManager", function() {
beforeEach(function() {
this.RedisManager = SandboxedModule.require(modulePath, { requires: {
"redis-sharelatex" : {
createClient: () => { return this.rclient = {
auth: sinon.stub(),
multi: () => this.rclient
}; }
},
"settings-sharelatex": {
redis: {
history: {
key_schema: {
uncompressedHistoryOps({doc_id}) { return `UncompressedHistoryOps:${doc_id}`; },
docsWithHistoryOps({project_id}) { return `DocsWithHistoryOps:${project_id}`; }
}
}
}
}
}
}
);
this.doc_id = "doc-id-123";
this.project_id = "project-id-123";
this.batchSize = 100;
return this.callback = sinon.stub();
});
describe('RedisManager', function() {
beforeEach(function() {
this.RedisManager = SandboxedModule.require(modulePath, {
requires: {
'redis-sharelatex': {
createClient: () => {
return (this.rclient = {
auth: sinon.stub(),
multi: () => this.rclient
})
}
},
'settings-sharelatex': {
redis: {
history: {
key_schema: {
uncompressedHistoryOps({ doc_id }) {
return `UncompressedHistoryOps:${doc_id}`
},
docsWithHistoryOps({ project_id }) {
return `DocsWithHistoryOps:${project_id}`
}
}
}
}
}
}
})
this.doc_id = 'doc-id-123'
this.project_id = 'project-id-123'
this.batchSize = 100
return (this.callback = sinon.stub())
})
describe("getOldestDocUpdates", function() {
beforeEach(function() {
this.rawUpdates = [ {v: 42, op: "mock-op-42"}, { v: 45, op: "mock-op-45" }];
this.jsonUpdates = (Array.from(this.rawUpdates).map((update) => JSON.stringify(update)));
this.rclient.lrange = sinon.stub().callsArgWith(3, null, this.jsonUpdates);
return this.RedisManager.getOldestDocUpdates(this.doc_id, this.batchSize, this.callback);
});
describe('getOldestDocUpdates', function() {
beforeEach(function() {
this.rawUpdates = [
{ v: 42, op: 'mock-op-42' },
{ v: 45, op: 'mock-op-45' }
]
this.jsonUpdates = Array.from(this.rawUpdates).map(update =>
JSON.stringify(update)
)
this.rclient.lrange = sinon.stub().callsArgWith(3, null, this.jsonUpdates)
return this.RedisManager.getOldestDocUpdates(
this.doc_id,
this.batchSize,
this.callback
)
})
it("should read the updates from redis", function() {
return this.rclient.lrange
.calledWith(`UncompressedHistoryOps:${this.doc_id}`, 0, this.batchSize - 1)
.should.equal(true);
});
it('should read the updates from redis', function() {
return this.rclient.lrange
.calledWith(
`UncompressedHistoryOps:${this.doc_id}`,
0,
this.batchSize - 1
)
.should.equal(true)
})
it("should call the callback with the unparsed ops", function() {
return this.callback.calledWith(null, this.jsonUpdates).should.equal(true);
});
it('should call the callback with the unparsed ops', function() {
return this.callback.calledWith(null, this.jsonUpdates).should.equal(true)
})
describe('expandDocUpdates', function() {
beforeEach(function() {
return this.RedisManager.expandDocUpdates(
this.jsonUpdates,
this.callback
)
})
describe("expandDocUpdates", function() {
beforeEach(function() {
return this.RedisManager.expandDocUpdates(this.jsonUpdates, this.callback);
});
return it('should call the callback with the parsed ops', function() {
return this.callback
.calledWith(null, this.rawUpdates)
.should.equal(true)
})
})
return it("should call the callback with the parsed ops", function() {
return this.callback.calledWith(null, this.rawUpdates).should.equal(true);
});
});
return describe('deleteAppliedDocUpdates', function() {
beforeEach(function() {
this.rclient.lrem = sinon.stub()
this.rclient.srem = sinon.stub()
this.rclient.exec = sinon.stub().callsArgWith(0)
return this.RedisManager.deleteAppliedDocUpdates(
this.project_id,
this.doc_id,
this.jsonUpdates,
this.callback
)
})
it('should delete the first update from redis', function() {
return this.rclient.lrem
.calledWith(
`UncompressedHistoryOps:${this.doc_id}`,
1,
this.jsonUpdates[0]
)
.should.equal(true)
})
return describe("deleteAppliedDocUpdates", function() {
beforeEach(function() {
this.rclient.lrem = sinon.stub();
this.rclient.srem = sinon.stub();
this.rclient.exec = sinon.stub().callsArgWith(0);
return this.RedisManager.deleteAppliedDocUpdates(this.project_id, this.doc_id, this.jsonUpdates, this.callback);
});
it('should delete the second update from redis', function() {
return this.rclient.lrem
.calledWith(
`UncompressedHistoryOps:${this.doc_id}`,
1,
this.jsonUpdates[1]
)
.should.equal(true)
})
it("should delete the first update from redis", function() {
return this.rclient.lrem
.calledWith(`UncompressedHistoryOps:${this.doc_id}`, 1, this.jsonUpdates[0])
.should.equal(true);
});
it('should delete the doc from the set of docs with history ops', function() {
return this.rclient.srem
.calledWith(`DocsWithHistoryOps:${this.project_id}`, this.doc_id)
.should.equal(true)
})
it("should delete the second update from redis", function() {
return this.rclient.lrem
.calledWith(`UncompressedHistoryOps:${this.doc_id}`, 1, this.jsonUpdates[1])
.should.equal(true);
});
return it('should call the callback ', function() {
return this.callback.called.should.equal(true)
})
})
})
it("should delete the doc from the set of docs with history ops", function() {
return this.rclient.srem
.calledWith(`DocsWithHistoryOps:${this.project_id}`, this.doc_id)
.should.equal(true);
});
return describe('getDocIdsWithHistoryOps', function() {
beforeEach(function() {
this.doc_ids = ['mock-id-1', 'mock-id-2']
this.rclient.smembers = sinon.stub().callsArgWith(1, null, this.doc_ids)
return this.RedisManager.getDocIdsWithHistoryOps(
this.project_id,
this.callback
)
})
return it("should call the callback ", function() {
return this.callback.called.should.equal(true);
});
});
});
it('should read the doc_ids from redis', function() {
return this.rclient.smembers
.calledWith(`DocsWithHistoryOps:${this.project_id}`)
.should.equal(true)
})
return describe("getDocIdsWithHistoryOps", function() {
beforeEach(function() {
this.doc_ids = ["mock-id-1", "mock-id-2"];
this.rclient.smembers = sinon.stub().callsArgWith(1, null, this.doc_ids);
return this.RedisManager.getDocIdsWithHistoryOps(this.project_id, this.callback);
});
it("should read the doc_ids from redis", function() {
return this.rclient.smembers
.calledWith(`DocsWithHistoryOps:${this.project_id}`)
.should.equal(true);
});
return it("should call the callback with the doc_ids", function() {
return this.callback.calledWith(null, this.doc_ids).should.equal(true);
});
});
});
return it('should call the callback with the doc_ids', function() {
return this.callback.calledWith(null, this.doc_ids).should.equal(true)
})
})
})

View file

@ -9,51 +9,62 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/RestoreManager.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/RestoreManager.js'
const SandboxedModule = require('sandboxed-module')
describe("RestoreManager", function() {
beforeEach(function() {
this.RestoreManager = SandboxedModule.require(modulePath, { requires: {
"logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }),
"./DocumentUpdaterManager": (this.DocumentUpdaterManager = {}),
"./DiffManager": (this.DiffManager = {})
}
});
this.callback = sinon.stub();
this.project_id = "mock-project-id";
this.doc_id = "mock-doc-id";
this.user_id = "mock-user-id";
return this.version = 42;
});
describe('RestoreManager', function() {
beforeEach(function() {
this.RestoreManager = SandboxedModule.require(modulePath, {
requires: {
'logger-sharelatex': (this.logger = {
log: sinon.stub(),
error: sinon.stub()
}),
'./DocumentUpdaterManager': (this.DocumentUpdaterManager = {}),
'./DiffManager': (this.DiffManager = {})
}
})
this.callback = sinon.stub()
this.project_id = 'mock-project-id'
this.doc_id = 'mock-doc-id'
this.user_id = 'mock-user-id'
return (this.version = 42)
})
return describe("restoreToBeforeVersion", function() {
beforeEach(function() {
this.content = "mock content";
this.DocumentUpdaterManager.setDocument = sinon.stub().callsArg(4);
this.DiffManager.getDocumentBeforeVersion = sinon.stub().callsArgWith(3, null, this.content);
return this.RestoreManager.restoreToBeforeVersion(this.project_id, this.doc_id, this.version, this.user_id, this.callback);
});
return describe('restoreToBeforeVersion', function() {
beforeEach(function() {
this.content = 'mock content'
this.DocumentUpdaterManager.setDocument = sinon.stub().callsArg(4)
this.DiffManager.getDocumentBeforeVersion = sinon
.stub()
.callsArgWith(3, null, this.content)
return this.RestoreManager.restoreToBeforeVersion(
this.project_id,
this.doc_id,
this.version,
this.user_id,
this.callback
)
})
it("should get the content before the requested version", function() {
return this.DiffManager.getDocumentBeforeVersion
.calledWith(this.project_id, this.doc_id, this.version)
.should.equal(true);
});
it('should get the content before the requested version', function() {
return this.DiffManager.getDocumentBeforeVersion
.calledWith(this.project_id, this.doc_id, this.version)
.should.equal(true)
})
it("should set the document in the document updater", function() {
return this.DocumentUpdaterManager.setDocument
.calledWith(this.project_id, this.doc_id, this.content, this.user_id)
.should.equal(true);
});
it('should set the document in the document updater', function() {
return this.DocumentUpdaterManager.setDocument
.calledWith(this.project_id, this.doc_id, this.content, this.user_id)
.should.equal(true)
})
return it("should call the callback", function() {
return this.callback.called.should.equal(true);
});
});
});
return it('should call the callback', function() {
return this.callback.called.should.equal(true)
})
})
})

View file

@ -9,157 +9,180 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/UpdateTrimmer.js";
const SandboxedModule = require('sandboxed-module');
const tk = require("timekeeper");
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/UpdateTrimmer.js'
const SandboxedModule = require('sandboxed-module')
const tk = require('timekeeper')
describe("UpdateTrimmer", function() {
beforeEach(function() {
this.now = new Date();
tk.freeze(this.now);
describe('UpdateTrimmer', function() {
beforeEach(function() {
this.now = new Date()
tk.freeze(this.now)
this.UpdateTrimmer = SandboxedModule.require(modulePath, { requires: {
"logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }),
"./WebApiManager": (this.WebApiManager = {}),
"./MongoManager": (this.MongoManager = {})
}
});
this.UpdateTrimmer = SandboxedModule.require(modulePath, {
requires: {
'logger-sharelatex': (this.logger = {
log: sinon.stub(),
error: sinon.stub()
}),
'./WebApiManager': (this.WebApiManager = {}),
'./MongoManager': (this.MongoManager = {})
}
})
this.callback = sinon.stub();
return this.project_id = "mock-project-id";
});
this.callback = sinon.stub()
return (this.project_id = 'mock-project-id')
})
afterEach(function() { return tk.reset(); });
afterEach(function() {
return tk.reset()
})
return describe("shouldTrimUpdates", function() {
beforeEach(function() {
this.metadata = {};
this.details =
{features: {}};
this.MongoManager.getProjectMetaData = sinon.stub().callsArgWith(1, null, this.metadata);
this.MongoManager.setProjectMetaData = sinon.stub().callsArgWith(2);
this.MongoManager.upgradeHistory = sinon.stub().callsArgWith(1);
return this.WebApiManager.getProjectDetails = sinon.stub().callsArgWith(1, null, this.details);
});
return describe('shouldTrimUpdates', function() {
beforeEach(function() {
this.metadata = {}
this.details = { features: {} }
this.MongoManager.getProjectMetaData = sinon
.stub()
.callsArgWith(1, null, this.metadata)
this.MongoManager.setProjectMetaData = sinon.stub().callsArgWith(2)
this.MongoManager.upgradeHistory = sinon.stub().callsArgWith(1)
return (this.WebApiManager.getProjectDetails = sinon
.stub()
.callsArgWith(1, null, this.details))
})
describe("with preserveHistory set in the project meta data", function() {
beforeEach(function() {
this.metadata.preserveHistory = true;
return this.UpdateTrimmer.shouldTrimUpdates(this.project_id, this.callback);
});
describe('with preserveHistory set in the project meta data', function() {
beforeEach(function() {
this.metadata.preserveHistory = true
return this.UpdateTrimmer.shouldTrimUpdates(
this.project_id,
this.callback
)
})
it("should look up the meta data", function() {
return this.MongoManager.getProjectMetaData
.calledWith(this.project_id)
.should.equal(true);
});
it('should look up the meta data', function() {
return this.MongoManager.getProjectMetaData
.calledWith(this.project_id)
.should.equal(true)
})
it("should not look up the project details", function() {
return this.WebApiManager.getProjectDetails
.called
.should.equal(false);
});
it('should not look up the project details', function() {
return this.WebApiManager.getProjectDetails.called.should.equal(false)
})
return it("should return false", function() {
return this.callback.calledWith(null, false).should.equal(true);
});
});
return it('should return false', function() {
return this.callback.calledWith(null, false).should.equal(true)
})
})
describe("without preserveHistory set in the project meta data", function() {
beforeEach(function() {
return this.metadata.preserveHistory = false;
});
describe('without preserveHistory set in the project meta data', function() {
beforeEach(function() {
return (this.metadata.preserveHistory = false)
})
describe("when the project has the versioning feature", function() {
beforeEach(function() {
this.details.features.versioning = true;
return this.UpdateTrimmer.shouldTrimUpdates(this.project_id, this.callback);
});
describe('when the project has the versioning feature', function() {
beforeEach(function() {
this.details.features.versioning = true
return this.UpdateTrimmer.shouldTrimUpdates(
this.project_id,
this.callback
)
})
it("should look up the meta data", function() {
return this.MongoManager.getProjectMetaData
.calledWith(this.project_id)
.should.equal(true);
});
it('should look up the meta data', function() {
return this.MongoManager.getProjectMetaData
.calledWith(this.project_id)
.should.equal(true)
})
it("should look up the project details", function() {
return this.WebApiManager.getProjectDetails
.calledWith(this.project_id)
.should.equal(true);
});
it('should look up the project details', function() {
return this.WebApiManager.getProjectDetails
.calledWith(this.project_id)
.should.equal(true)
})
it("should insert preserveHistory into the metadata", function() {
return this.MongoManager.setProjectMetaData
.calledWith(this.project_id, {preserveHistory: true})
.should.equal(true);
});
it('should insert preserveHistory into the metadata', function() {
return this.MongoManager.setProjectMetaData
.calledWith(this.project_id, { preserveHistory: true })
.should.equal(true)
})
it("should upgrade any existing history", function() {
return this.MongoManager.upgradeHistory
.calledWith(this.project_id)
.should.equal(true);
});
it('should upgrade any existing history', function() {
return this.MongoManager.upgradeHistory
.calledWith(this.project_id)
.should.equal(true)
})
return it("should return false", function() {
return this.callback.calledWith(null, false).should.equal(true);
});
});
return it('should return false', function() {
return this.callback.calledWith(null, false).should.equal(true)
})
})
return describe("when the project does not have the versioning feature", function() {
beforeEach(function() {
this.details.features.versioning = false;
return this.UpdateTrimmer.shouldTrimUpdates(this.project_id, this.callback);
});
return describe('when the project does not have the versioning feature', function() {
beforeEach(function() {
this.details.features.versioning = false
return this.UpdateTrimmer.shouldTrimUpdates(
this.project_id,
this.callback
)
})
return it("should return true", function() {
return this.callback.calledWith(null, true).should.equal(true);
});
});
});
return it('should return true', function() {
return this.callback.calledWith(null, true).should.equal(true)
})
})
})
return describe("without any meta data", function() {
beforeEach(function() {
return this.MongoManager.getProjectMetaData = sinon.stub().callsArgWith(1, null, null);
});
return describe('without any meta data', function() {
beforeEach(function() {
return (this.MongoManager.getProjectMetaData = sinon
.stub()
.callsArgWith(1, null, null))
})
describe("when the project has the versioning feature", function() {
beforeEach(function() {
this.details.features.versioning = true;
return this.UpdateTrimmer.shouldTrimUpdates(this.project_id, this.callback);
});
describe('when the project has the versioning feature', function() {
beforeEach(function() {
this.details.features.versioning = true
return this.UpdateTrimmer.shouldTrimUpdates(
this.project_id,
this.callback
)
})
it("should insert preserveHistory into the metadata", function() {
return this.MongoManager.setProjectMetaData
.calledWith(this.project_id, {preserveHistory: true})
.should.equal(true);
});
it('should insert preserveHistory into the metadata', function() {
return this.MongoManager.setProjectMetaData
.calledWith(this.project_id, { preserveHistory: true })
.should.equal(true)
})
it("should upgrade any existing history", function() {
return this.MongoManager.upgradeHistory
.calledWith(this.project_id)
.should.equal(true);
});
it('should upgrade any existing history', function() {
return this.MongoManager.upgradeHistory
.calledWith(this.project_id)
.should.equal(true)
})
return it("should return false", function() {
return this.callback.calledWith(null, false).should.equal(true);
});
});
return it('should return false', function() {
return this.callback.calledWith(null, false).should.equal(true)
})
})
return describe("when the project does not have the versioning feature", function() {
beforeEach(function() {
this.details.features.versioning = false;
return this.UpdateTrimmer.shouldTrimUpdates(this.project_id, this.callback);
});
return it("should return true", function() {
return this.callback.calledWith(null, true).should.equal(true);
});
});
});
});
});
return describe('when the project does not have the versioning feature', function() {
beforeEach(function() {
this.details.features.versioning = false
return this.UpdateTrimmer.shouldTrimUpdates(
this.project_id,
this.callback
)
})
return it('should return true', function() {
return this.callback.calledWith(null, true).should.equal(true)
})
})
})
})
})

View file

@ -9,162 +9,206 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const { expect } = chai;
const modulePath = "../../../../app/js/WebApiManager.js";
const SandboxedModule = require('sandboxed-module');
const sinon = require('sinon')
const chai = require('chai')
const should = chai.should()
const { expect } = chai
const modulePath = '../../../../app/js/WebApiManager.js'
const SandboxedModule = require('sandboxed-module')
describe("WebApiManager", function() {
beforeEach(function() {
this.WebApiManager = SandboxedModule.require(modulePath, { requires: {
"requestretry": (this.request = {}),
"logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }),
'settings-sharelatex': (this.settings = {
apis: {
web: {
url: "http://example.com",
user: "sharelatex",
pass: "password"
}
}
})
}
}
);
this.callback = sinon.stub();
this.user_id = "mock-user-id";
this.project_id = "mock-project-id";
this.user_info = {
email: "leo@sharelatex.com",
id: this.user_id,
first_name: "Leo",
last_nane: "Lion",
extra_param: "blah"
};
return this.project =
{features: "mock-features"};
});
describe('WebApiManager', function() {
beforeEach(function() {
this.WebApiManager = SandboxedModule.require(modulePath, {
requires: {
requestretry: (this.request = {}),
'logger-sharelatex': (this.logger = {
log: sinon.stub(),
error: sinon.stub()
}),
'settings-sharelatex': (this.settings = {
apis: {
web: {
url: 'http://example.com',
user: 'sharelatex',
pass: 'password'
}
}
})
}
})
this.callback = sinon.stub()
this.user_id = 'mock-user-id'
this.project_id = 'mock-project-id'
this.user_info = {
email: 'leo@sharelatex.com',
id: this.user_id,
first_name: 'Leo',
last_nane: 'Lion',
extra_param: 'blah'
}
return (this.project = { features: 'mock-features' })
})
describe("getUserInfo", function() {
describe("successfully", function() {
beforeEach(function() {
this.body = JSON.stringify(this.user_info);
this.request.get = sinon.stub().callsArgWith(1, null, {statusCode: 200}, this.body);
return this.WebApiManager.getUserInfo(this.user_id, this.callback);
});
describe('getUserInfo', function() {
describe('successfully', function() {
beforeEach(function() {
this.body = JSON.stringify(this.user_info)
this.request.get = sinon
.stub()
.callsArgWith(1, null, { statusCode: 200 }, this.body)
return this.WebApiManager.getUserInfo(this.user_id, this.callback)
})
it('should get the user from the web api', function() {
return this.request.get
.calledWithMatch({
url: `${this.settings.apis.web.url}/user/${this.user_id}/personal_info`,
auth: {
user: this.settings.apis.web.user,
pass: this.settings.apis.web.pass,
sendImmediately: true
}
})
.should.equal(true);
});
it('should get the user from the web api', function() {
return this.request.get
.calledWithMatch({
url: `${this.settings.apis.web.url}/user/${this.user_id}/personal_info`,
auth: {
user: this.settings.apis.web.user,
pass: this.settings.apis.web.pass,
sendImmediately: true
}
})
.should.equal(true)
})
return it("should call the callback with only the email, id and names", function() {
return this.callback.calledWith(null, {
id: this.user_id,
email: this.user_info.email,
first_name: this.user_info.first_name,
last_name: this.user_info.last_name
}).should.equal(true);
});
});
return it('should call the callback with only the email, id and names', function() {
return this.callback
.calledWith(null, {
id: this.user_id,
email: this.user_info.email,
first_name: this.user_info.first_name,
last_name: this.user_info.last_name
})
.should.equal(true)
})
})
describe("when the web API returns an error", function() {
beforeEach(function() {
this.request.get = sinon.stub().callsArgWith(1, (this.error = new Error("something went wrong")), null, null);
return this.WebApiManager.getUserInfo(this.user_id, this.callback);
});
describe('when the web API returns an error', function() {
beforeEach(function() {
this.request.get = sinon
.stub()
.callsArgWith(
1,
(this.error = new Error('something went wrong')),
null,
null
)
return this.WebApiManager.getUserInfo(this.user_id, this.callback)
})
return it("should return an error to the callback", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
});
return it('should return an error to the callback', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
describe("when the web returns a failure error code", function() {
beforeEach(function() {
this.request.get = sinon.stub().callsArgWith(1, null, { statusCode: 500, attempts: 42}, "");
return this.WebApiManager.getUserInfo(this.user_id, this.callback);
});
describe('when the web returns a failure error code', function() {
beforeEach(function() {
this.request.get = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500, attempts: 42 }, '')
return this.WebApiManager.getUserInfo(this.user_id, this.callback)
})
return it("should return the callback with an error", function() {
return this.callback
.calledWith(sinon.match.has('message', "web returned a non-success status code: 500 (attempts: 42)"))
.should.equal(true);
});
});
return it('should return the callback with an error', function() {
return this.callback
.calledWith(
sinon.match.has(
'message',
'web returned a non-success status code: 500 (attempts: 42)'
)
)
.should.equal(true)
})
})
return describe("when the user cannot be found", function() {
beforeEach(function() {
this.request.get = sinon.stub().callsArgWith(1, null, {statusCode: 404}, "nothing");
return this.WebApiManager.getUserInfo(this.user_id, this.callback);
});
return describe('when the user cannot be found', function() {
beforeEach(function() {
this.request.get = sinon
.stub()
.callsArgWith(1, null, { statusCode: 404 }, 'nothing')
return this.WebApiManager.getUserInfo(this.user_id, this.callback)
})
return it("should return a null value", function() {
return this.callback
.calledWith(null, null)
.should.equal(true);
});
});
});
return it('should return a null value', function() {
return this.callback.calledWith(null, null).should.equal(true)
})
})
})
return describe('getProjectDetails', function() {
describe('successfully', function() {
beforeEach(function() {
this.body = JSON.stringify(this.project)
this.request.get = sinon
.stub()
.callsArgWith(1, null, { statusCode: 200 }, this.body)
return this.WebApiManager.getProjectDetails(
this.project_id,
this.callback
)
})
return describe("getProjectDetails", function() {
describe("successfully", function() {
beforeEach(function() {
this.body = JSON.stringify(this.project);
this.request.get = sinon.stub().callsArgWith(1, null, {statusCode: 200}, this.body);
return this.WebApiManager.getProjectDetails(this.project_id, this.callback);
});
it('should get the project from the web api', function() {
return this.request.get
.calledWithMatch({
url: `${this.settings.apis.web.url}/project/${this.project_id}/details`,
auth: {
user: this.settings.apis.web.user,
pass: this.settings.apis.web.pass,
sendImmediately: true
}
})
.should.equal(true)
})
it('should get the project from the web api', function() {
return this.request.get
.calledWithMatch({
url: `${this.settings.apis.web.url}/project/${this.project_id}/details`,
auth: {
user: this.settings.apis.web.user,
pass: this.settings.apis.web.pass,
sendImmediately: true
}
})
.should.equal(true);
});
return it('should call the callback with the project', function() {
return this.callback.calledWith(null, this.project).should.equal(true)
})
})
return it("should call the callback with the project", function() {
return this.callback.calledWith(null, this.project).should.equal(true);
});
});
describe('when the web API returns an error', function() {
beforeEach(function() {
this.request.get = sinon
.stub()
.callsArgWith(
1,
(this.error = new Error('something went wrong')),
null,
null
)
return this.WebApiManager.getProjectDetails(
this.project_id,
this.callback
)
})
describe("when the web API returns an error", function() {
beforeEach(function() {
this.request.get = sinon.stub().callsArgWith(1, (this.error = new Error("something went wrong")), null, null);
return this.WebApiManager.getProjectDetails(this.project_id, this.callback);
});
return it('should return an error to the callback', function() {
return this.callback.calledWith(this.error).should.equal(true)
})
})
return it("should return an error to the callback", function() {
return this.callback.calledWith(this.error).should.equal(true);
});
});
return describe('when the web returns a failure error code', function() {
beforeEach(function() {
this.request.get = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500, attempts: 42 }, '')
return this.WebApiManager.getProjectDetails(
this.project_id,
this.callback
)
})
return describe("when the web returns a failure error code", function() {
beforeEach(function() {
this.request.get = sinon.stub().callsArgWith(1, null, { statusCode: 500, attempts: 42 }, "");
return this.WebApiManager.getProjectDetails(this.project_id, this.callback);
});
return it("should return the callback with an error", function() {
return this.callback
.calledWith(sinon.match.has('message', "web returned a non-success status code: 500 (attempts: 42)"))
.should.equal(true);
});
});
});
});
return it('should return the callback with an error', function() {
return this.callback
.calledWith(
sinon.match.has(
'message',
'web returned a non-success status code: 500 (attempts: 42)'
)
)
.should.equal(true)
})
})
})
})