recoder-code
Version:
Complete AI-powered development platform with ML model training, plugin registry, real-time collaboration, monitoring, infrastructure automation, and enterprise deployment capabilities
204 lines (178 loc) • 5.79 kB
JavaScript
var expect = require('chai').expect;
var ShareDbMongo = require('..');
var getQuery = require('sharedb-mingo-memory/get-query');
var sinon = require('sinon');
var mongoUrl = process.env.TEST_MONGO_URL || 'mongodb://localhost:27017/test';
function create(callback) {
var db = new ShareDbMongo(mongoUrl, {
mongoOptions: {},
getOpsWithoutStrictLinking: true
});
db.getDbs(function(err, mongo) {
if (err) return callback(err);
mongo.dropDatabase()
.then(function() {
callback(null, db, mongo);
})
.catch(callback);
});
};
require('sharedb/test/db')({create: create, getQuery: getQuery});
describe('getOpsWithoutStrictLinking: true', function() {
beforeEach(function(done) {
var self = this;
create(function(err, db, mongo) {
if (err) return done(err);
self.db = db;
self.mongo = mongo;
done();
});
});
afterEach(function(done) {
this.db.close(done);
});
describe('a chain of ops', function() {
var db;
var mongo;
var id;
var collection;
beforeEach(function(done) {
db = this.db;
mongo = this.mongo;
id = 'document1';
collection = 'testcollection';
sinon.spy(db, '_getOps');
sinon.spy(db, '_getSnapshotOpLink');
var ops = [
{v: 0, create: {}},
{v: 1, p: ['foo'], oi: 'bar'},
{v: 2, p: ['foo'], oi: 'baz'},
{v: 3, p: ['foo'], oi: 'qux'}
];
commitOpChain(db, mongo, collection, id, ops, done);
});
it('fetches ops 0-1 without fetching all ops', function(done) {
db.getOps(collection, id, 0, 2, null, function(error, ops) {
if (error) return done(error);
expect(ops.length).to.equal(2);
expect(ops[0].v).to.equal(0);
expect(ops[1].v).to.equal(1);
expect(db._getSnapshotOpLink.notCalled).to.equal(true);
expect(db._getOps.calledOnceWith(collection, id, 0, 2)).to.equal(true);
done();
});
});
it('fetches ops 0-1 when v1 has a spurious duplicate', function(done) {
var spuriousOp = {v: 1, d: id, p: ['foo'], oi: 'corrupt', o: null};
callInSeries([
function(next) {
mongo.collection('o_' + collection).insertOne(spuriousOp)
.then(function(result) {
next(null, result);
})
.catch(next);
},
function(result, next) {
db.getOps(collection, id, 0, 2, null, next);
},
function(ops, next) {
expect(ops.length).to.equal(2);
expect(ops[1].oi).to.equal('bar');
expect(db._getSnapshotOpLink.notCalled).to.equal(true);
expect(db._getOps.calledOnceWith(collection, id, 0, 2)).to.equal(true);
next();
},
done
]);
});
it('fetches ops 0-1 when the next op v2 has a spurious duplicate', function(done) {
var spuriousOp = {v: 2, d: id, p: ['foo'], oi: 'corrupt', o: null};
callInSeries([
function(next) {
mongo.collection('o_' + collection).insertOne(spuriousOp)
.then(function(result) {
next(null, result);
})
.catch(next);
},
function(result, next) {
db.getOps(collection, id, 0, 2, null, next);
},
function(ops, next) {
expect(ops.length).to.equal(2);
expect(ops[1].oi).to.equal('bar');
expect(db._getSnapshotOpLink.notCalled).to.equal(true);
expect(db._getOps.calledOnceWith(collection, id, 0, 3)).to.equal(true);
next();
},
done
]);
});
it('fetches ops 0-1 when all the ops have spurious duplicates', function(done) {
var spuriousOps = [
{v: 0, d: id, p: ['foo'], oi: 'corrupt', o: null},
{v: 1, d: id, p: ['foo'], oi: 'corrupt', o: null},
{v: 2, d: id, p: ['foo'], oi: 'corrupt', o: null},
{v: 3, d: id, p: ['foo'], oi: 'corrupt', o: null}
];
callInSeries([
function(next) {
mongo.collection('o_' + collection).insertMany(spuriousOps)
.then(function(result) {
next(null, result);
})
.catch(next);
},
function(result, next) {
db.getOps(collection, id, 0, 2, null, next);
},
function(ops, next) {
expect(ops.length).to.equal(2);
expect(ops[0].create).to.eql({});
expect(ops[1].oi).to.equal('bar');
expect(db._getSnapshotOpLink.calledOnce).to.equal(true);
next();
},
done
]);
});
});
});
function commitOpChain(db, mongo, collection, id, ops, previousOpId, version, callback) {
if (typeof previousOpId === 'function') {
callback = previousOpId;
previousOpId = undefined;
version = 0;
}
ops = ops.slice();
var op = ops.shift();
if (!op) {
return callback();
}
var snapshot = {id: id, v: version + 1, type: 'json0', data: {}, m: null, _opLink: previousOpId};
db.commit(collection, id, op, snapshot, null, function(error) {
if (error) return callback(error);
mongo.collection('o_' + collection).find({d: id, v: version}).next()
.then(function(op) {
commitOpChain(db, mongo, collection, id, ops, op._id, ++version, callback);
})
.catch(callback);
});
}
function callInSeries(callbacks, args) {
if (!callbacks.length) return;
args = args || [];
var error = args.shift();
if (error) {
var finalCallback = callbacks[callbacks.length - 1];
return finalCallback(error);
}
var callback = callbacks.shift();
if (callbacks.length) {
args.push(function() {
var args = Array.from(arguments);
callInSeries(callbacks, args);
});
}
callback.apply(callback, args);
}