|
|
@@ -10,384 +10,581 @@
|
|
|
* 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");
|
|
|
-chai.should();
|
|
|
-const { expect } = chai;
|
|
|
-const mongojs = require("../../../app/js/mongojs");
|
|
|
-const { ObjectId } = mongojs;
|
|
|
-const Settings = require("settings-sharelatex");
|
|
|
-const request = require("request");
|
|
|
-const rclient = require("redis").createClient(Settings.redis.history); // Only works locally for now
|
|
|
-
|
|
|
-const TrackChangesApp = require("./helpers/TrackChangesApp");
|
|
|
-const TrackChangesClient = require("./helpers/TrackChangesClient");
|
|
|
-const MockWebApi = require("./helpers/MockWebApi");
|
|
|
-
|
|
|
-describe("Appending doc ops to the history", function() {
|
|
|
- before(function(done) { return TrackChangesApp.ensureRunning(done); });
|
|
|
-
|
|
|
- describe("when the history does not exist yet", function() {
|
|
|
- before(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: false}};
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ i: "f", p: 3 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 3
|
|
|
- }, {
|
|
|
- op: [{ i: "o", p: 4 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 4
|
|
|
- }, {
|
|
|
- op: [{ i: "o", p: 5 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 5
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- it("should insert the compressed op into mongo", function() {
|
|
|
- return expect(this.updates[0].pack[0].op).to.deep.equal([{
|
|
|
- p: 3, i: "foo"
|
|
|
- }]);
|
|
|
- });
|
|
|
-
|
|
|
- it("should insert the correct version number into mongo", function() {
|
|
|
- return expect(this.updates[0].v).to.equal(5);
|
|
|
- });
|
|
|
-
|
|
|
- it("should store the doc id", function() {
|
|
|
- return expect(this.updates[0].doc_id.toString()).to.equal(this.doc_id);
|
|
|
- });
|
|
|
-
|
|
|
- it("should store the project id", function() {
|
|
|
- return expect(this.updates[0].project_id.toString()).to.equal(this.project_id);
|
|
|
- });
|
|
|
-
|
|
|
- return it("should clear the doc from the DocsWithHistoryOps set", function(done) {
|
|
|
- rclient.sismember(`DocsWithHistoryOps:${this.project_id}`, this.doc_id, (error, member) => {
|
|
|
- member.should.equal(0);
|
|
|
- return done();
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- describe("when the history has already been started", function() {
|
|
|
- beforeEach(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: false}};
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ i: "f", p: 3 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 3
|
|
|
- }, {
|
|
|
- op: [{ i: "o", p: 4 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 4
|
|
|
- }, {
|
|
|
- op: [{ i: "o", p: 5 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 5
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- describe("when the updates are recent and from the same user", function() {
|
|
|
- beforeEach(function(done) {
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ i: "b", p: 6 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 6
|
|
|
- }, {
|
|
|
- op: [{ i: "a", p: 7 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 7
|
|
|
- }, {
|
|
|
- op: [{ i: "r", p: 8 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 8
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- it("should combine all the updates into one pack", function() {
|
|
|
- return expect(this.updates[0].pack[1].op).to.deep.equal([{
|
|
|
- p: 6, i: "bar"
|
|
|
- }]);
|
|
|
- });
|
|
|
-
|
|
|
- return it("should insert the correct version number into mongo", function() {
|
|
|
- return expect(this.updates[0].v_end).to.equal(8);
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- return describe("when the updates are far apart", function() {
|
|
|
- beforeEach(function(done) {
|
|
|
- const oneDay = 24 * 60 * 60 * 1000;
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ i: "b", p: 6 }],
|
|
|
- meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
- v: 6
|
|
|
- }, {
|
|
|
- op: [{ i: "a", p: 7 }],
|
|
|
- meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
- v: 7
|
|
|
- }, {
|
|
|
- op: [{ i: "r", p: 8 }],
|
|
|
- meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
- v: 8
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- return it("should combine the updates into one pack", function() {
|
|
|
- expect(this.updates[0].pack[0].op).to.deep.equal([{
|
|
|
- p: 3, i: "foo"
|
|
|
- }]);
|
|
|
- return expect(this.updates[0].pack[1].op).to.deep.equal([{
|
|
|
- p: 6, i: "bar"
|
|
|
- }]);
|
|
|
- });
|
|
|
- });
|
|
|
-});
|
|
|
-
|
|
|
- describe("when the updates need processing in batches", function() {
|
|
|
- before(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: false}};
|
|
|
- const updates = [];
|
|
|
- this.expectedOp = [{ p:0, i: "" }];
|
|
|
- for (let i = 0; i <= 250; i++) {
|
|
|
- updates.push({
|
|
|
- op: [{i: "a", p: 0}],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: i
|
|
|
- });
|
|
|
- this.expectedOp[0].i = `a${this.expectedOp[0].i}`;
|
|
|
- }
|
|
|
-
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, updates, error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates1) => {
|
|
|
- this.updates = updates1;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- it("should concat the compressed op into mongo", function() {
|
|
|
- return expect(this.updates[0].pack.length).to.deep.equal(3);
|
|
|
- }); // batch size is 100
|
|
|
-
|
|
|
- return it("should insert the correct version number into mongo", function() {
|
|
|
- return expect(this.updates[0].v_end).to.equal(250);
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- describe("when there are multiple ops in each update", function() {
|
|
|
- before(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: false}};
|
|
|
- const oneDay = 24 * 60 * 60 * 1000;
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ i: "f", p: 3 }, { i: "o", p: 4 }, { i: "o", p: 5 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 3
|
|
|
- }, {
|
|
|
- op: [{ i: "b", p: 6 }, { i: "a", p: 7 }, { i: "r", p: 8 }],
|
|
|
- meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
- v: 4
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- it("should insert the compressed ops into mongo", function() {
|
|
|
- expect(this.updates[0].pack[0].op).to.deep.equal([{
|
|
|
- p: 3, i: "foo"
|
|
|
- }]);
|
|
|
- return expect(this.updates[0].pack[1].op).to.deep.equal([{
|
|
|
- p: 6, i: "bar"
|
|
|
- }]);
|
|
|
- });
|
|
|
-
|
|
|
- return it("should insert the correct version numbers into mongo", function() {
|
|
|
- expect(this.updates[0].pack[0].v).to.equal(3);
|
|
|
- return expect(this.updates[0].pack[1].v).to.equal(4);
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- describe("when there is a no-op update", function() {
|
|
|
- before(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: false}};
|
|
|
- const oneDay = 24 * 60 * 60 * 1000;
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 3
|
|
|
- }, {
|
|
|
- op: [{ i: "foo", p: 3 }],
|
|
|
- meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
- v: 4
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- it("should insert the compressed no-op into mongo", function() {
|
|
|
- return expect(this.updates[0].pack[0].op).to.deep.equal([]);
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- it("should insert the compressed next update into mongo", function() {
|
|
|
- return expect(this.updates[0].pack[1].op).to.deep.equal([{
|
|
|
- p: 3, i: "foo"
|
|
|
- }]);
|
|
|
- });
|
|
|
-
|
|
|
- return it("should insert the correct version numbers into mongo", function() {
|
|
|
- expect(this.updates[0].pack[0].v).to.equal(3);
|
|
|
- return expect(this.updates[0].pack[1].v).to.equal(4);
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- describe("when there is a comment update", function() {
|
|
|
- before(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: false}};
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ c: "foo", p: 3 }, {d: "bar", p: 6}],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 3
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- it("should ignore the comment op", function() {
|
|
|
- return expect(this.updates[0].pack[0].op).to.deep.equal([{d: "bar", p: 6}]);
|
|
|
- });
|
|
|
-
|
|
|
- return it("should insert the correct version numbers into mongo", function() {
|
|
|
- return expect(this.updates[0].pack[0].v).to.equal(3);
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- describe("when the project has versioning enabled", function() {
|
|
|
- before(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: true}};
|
|
|
-
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ i: "f", p: 3 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 3
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- return it("should not add a expiresAt entry in the update in mongo", function() {
|
|
|
- return expect(this.updates[0].expiresAt).to.be.undefined;
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- return describe("when the project does not have versioning enabled", function() {
|
|
|
- before(function(done) {
|
|
|
- this.project_id = ObjectId().toString();
|
|
|
- this.doc_id = ObjectId().toString();
|
|
|
- this.user_id = ObjectId().toString();
|
|
|
- MockWebApi.projects[this.project_id] = {features: {versioning: false}};
|
|
|
-
|
|
|
- TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
|
|
|
- op: [{ i: "f", p: 3 }],
|
|
|
- meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
- v: 3
|
|
|
- }], error => {
|
|
|
- if (error != null) { throw error; }
|
|
|
- return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
|
|
|
- this.updates = updates;
|
|
|
- if (error != null) { throw error; }
|
|
|
- return done();
|
|
|
- });
|
|
|
- });
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- return it("should add a expiresAt entry in the update in mongo", function() {
|
|
|
- return expect(this.updates[0].expiresAt).to.exist;
|
|
|
- });
|
|
|
- });
|
|
|
-});
|
|
|
+const sinon = require('sinon')
|
|
|
+const chai = require('chai')
|
|
|
+chai.should()
|
|
|
+const { expect } = chai
|
|
|
+const mongojs = require('../../../app/js/mongojs')
|
|
|
+const { ObjectId } = mongojs
|
|
|
+const Settings = require('settings-sharelatex')
|
|
|
+const request = require('request')
|
|
|
+const rclient = require('redis').createClient(Settings.redis.history) // Only works locally for now
|
|
|
+
|
|
|
+const TrackChangesApp = require('./helpers/TrackChangesApp')
|
|
|
+const TrackChangesClient = require('./helpers/TrackChangesClient')
|
|
|
+const MockWebApi = require('./helpers/MockWebApi')
|
|
|
+
|
|
|
+describe('Appending doc ops to the history', function() {
|
|
|
+ before(function(done) {
|
|
|
+ return TrackChangesApp.ensureRunning(done)
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the history does not exist yet', function() {
|
|
|
+ before(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: false } }
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [{ i: 'f', p: 3 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 3
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'o', p: 4 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 4
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'o', p: 5 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 5
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should insert the compressed op into mongo', function() {
|
|
|
+ return expect(this.updates[0].pack[0].op).to.deep.equal([
|
|
|
+ {
|
|
|
+ p: 3,
|
|
|
+ i: 'foo'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should insert the correct version number into mongo', function() {
|
|
|
+ return expect(this.updates[0].v).to.equal(5)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should store the doc id', function() {
|
|
|
+ return expect(this.updates[0].doc_id.toString()).to.equal(this.doc_id)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should store the project id', function() {
|
|
|
+ return expect(this.updates[0].project_id.toString()).to.equal(
|
|
|
+ this.project_id
|
|
|
+ )
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should clear the doc from the DocsWithHistoryOps set', function(done) {
|
|
|
+ rclient.sismember(
|
|
|
+ `DocsWithHistoryOps:${this.project_id}`,
|
|
|
+ this.doc_id,
|
|
|
+ (error, member) => {
|
|
|
+ member.should.equal(0)
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the history has already been started', function() {
|
|
|
+ beforeEach(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: false } }
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [{ i: 'f', p: 3 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 3
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'o', p: 4 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 4
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'o', p: 5 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 5
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the updates are recent and from the same user', function() {
|
|
|
+ beforeEach(function(done) {
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [{ i: 'b', p: 6 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 6
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'a', p: 7 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 7
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'r', p: 8 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 8
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should combine all the updates into one pack', function() {
|
|
|
+ return expect(this.updates[0].pack[1].op).to.deep.equal([
|
|
|
+ {
|
|
|
+ p: 6,
|
|
|
+ i: 'bar'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should insert the correct version number into mongo', function() {
|
|
|
+ return expect(this.updates[0].v_end).to.equal(8)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ return describe('when the updates are far apart', function() {
|
|
|
+ beforeEach(function(done) {
|
|
|
+ const oneDay = 24 * 60 * 60 * 1000
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [{ i: 'b', p: 6 }],
|
|
|
+ meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
+ v: 6
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'a', p: 7 }],
|
|
|
+ meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
+ v: 7
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'r', p: 8 }],
|
|
|
+ meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
+ v: 8
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should combine the updates into one pack', function() {
|
|
|
+ expect(this.updates[0].pack[0].op).to.deep.equal([
|
|
|
+ {
|
|
|
+ p: 3,
|
|
|
+ i: 'foo'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ return expect(this.updates[0].pack[1].op).to.deep.equal([
|
|
|
+ {
|
|
|
+ p: 6,
|
|
|
+ i: 'bar'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the updates need processing in batches', function() {
|
|
|
+ before(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: false } }
|
|
|
+ const updates = []
|
|
|
+ this.expectedOp = [{ p: 0, i: '' }]
|
|
|
+ for (let i = 0; i <= 250; i++) {
|
|
|
+ updates.push({
|
|
|
+ op: [{ i: 'a', p: 0 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: i
|
|
|
+ })
|
|
|
+ this.expectedOp[0].i = `a${this.expectedOp[0].i}`
|
|
|
+ }
|
|
|
+
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ updates,
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates1) => {
|
|
|
+ this.updates = updates1
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should concat the compressed op into mongo', function() {
|
|
|
+ return expect(this.updates[0].pack.length).to.deep.equal(3)
|
|
|
+ }) // batch size is 100
|
|
|
+
|
|
|
+ return it('should insert the correct version number into mongo', function() {
|
|
|
+ return expect(this.updates[0].v_end).to.equal(250)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when there are multiple ops in each update', function() {
|
|
|
+ before(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: false } }
|
|
|
+ const oneDay = 24 * 60 * 60 * 1000
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [
|
|
|
+ { i: 'f', p: 3 },
|
|
|
+ { i: 'o', p: 4 },
|
|
|
+ { i: 'o', p: 5 }
|
|
|
+ ],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 3
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [
|
|
|
+ { i: 'b', p: 6 },
|
|
|
+ { i: 'a', p: 7 },
|
|
|
+ { i: 'r', p: 8 }
|
|
|
+ ],
|
|
|
+ meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
+ v: 4
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should insert the compressed ops into mongo', function() {
|
|
|
+ expect(this.updates[0].pack[0].op).to.deep.equal([
|
|
|
+ {
|
|
|
+ p: 3,
|
|
|
+ i: 'foo'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ return expect(this.updates[0].pack[1].op).to.deep.equal([
|
|
|
+ {
|
|
|
+ p: 6,
|
|
|
+ i: 'bar'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should insert the correct version numbers into mongo', function() {
|
|
|
+ expect(this.updates[0].pack[0].v).to.equal(3)
|
|
|
+ return expect(this.updates[0].pack[1].v).to.equal(4)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when there is a no-op update', function() {
|
|
|
+ before(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: false } }
|
|
|
+ const oneDay = 24 * 60 * 60 * 1000
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 3
|
|
|
+ },
|
|
|
+ {
|
|
|
+ op: [{ i: 'foo', p: 3 }],
|
|
|
+ meta: { ts: Date.now() + oneDay, user_id: this.user_id },
|
|
|
+ v: 4
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should insert the compressed no-op into mongo', function() {
|
|
|
+ return expect(this.updates[0].pack[0].op).to.deep.equal([])
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should insert the compressed next update into mongo', function() {
|
|
|
+ return expect(this.updates[0].pack[1].op).to.deep.equal([
|
|
|
+ {
|
|
|
+ p: 3,
|
|
|
+ i: 'foo'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should insert the correct version numbers into mongo', function() {
|
|
|
+ expect(this.updates[0].pack[0].v).to.equal(3)
|
|
|
+ return expect(this.updates[0].pack[1].v).to.equal(4)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when there is a comment update', function() {
|
|
|
+ before(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: false } }
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [
|
|
|
+ { c: 'foo', p: 3 },
|
|
|
+ { d: 'bar', p: 6 }
|
|
|
+ ],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 3
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should ignore the comment op', function() {
|
|
|
+ return expect(this.updates[0].pack[0].op).to.deep.equal([
|
|
|
+ { d: 'bar', p: 6 }
|
|
|
+ ])
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should insert the correct version numbers into mongo', function() {
|
|
|
+ return expect(this.updates[0].pack[0].v).to.equal(3)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the project has versioning enabled', function() {
|
|
|
+ before(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: true } }
|
|
|
+
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [{ i: 'f', p: 3 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 3
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should not add a expiresAt entry in the update in mongo', function() {
|
|
|
+ return expect(this.updates[0].expiresAt).to.be.undefined
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ return describe('when the project does not have versioning enabled', function() {
|
|
|
+ before(function(done) {
|
|
|
+ this.project_id = ObjectId().toString()
|
|
|
+ this.doc_id = ObjectId().toString()
|
|
|
+ this.user_id = ObjectId().toString()
|
|
|
+ MockWebApi.projects[this.project_id] = { features: { versioning: false } }
|
|
|
+
|
|
|
+ TrackChangesClient.pushRawUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ [
|
|
|
+ {
|
|
|
+ op: [{ i: 'f', p: 3 }],
|
|
|
+ meta: { ts: Date.now(), user_id: this.user_id },
|
|
|
+ v: 3
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ error => {
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return TrackChangesClient.flushAndGetCompressedUpdates(
|
|
|
+ this.project_id,
|
|
|
+ this.doc_id,
|
|
|
+ (error, updates) => {
|
|
|
+ this.updates = updates
|
|
|
+ if (error != null) {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ return done()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return null
|
|
|
+ })
|
|
|
+
|
|
|
+ return it('should add a expiresAt entry in the update in mongo', function() {
|
|
|
+ return expect(this.updates[0].expiresAt).to.exist
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|