recoder-code
Version:
Complete AI-powered development platform with ML model training, plugin registry, real-time collaboration, monitoring, infrastructure automation, and enterprise deployment capabilities
471 lines (421 loc) • 17.3 kB
JavaScript
var async = require('async');
var sinon = require('sinon');
var chai = require('chai');
chai.use(require('sinon-chai'));
var expect = chai.expect;
var ShareDbMongo = require('..');
var mongodb = require('./../mongodb');
var Collection = mongodb.Collection;
var mongoUrl = process.env.TEST_MONGO_URL || 'mongodb://localhost:27017/test';
var BEFORE_EDIT = ShareDbMongo.MiddlewareActions.beforeOverwrite;
var BEFORE_CREATE = ShareDbMongo.MiddlewareActions.beforeCreate;
var BEFORE_SNAPSHOT_LOOKUP = ShareDbMongo.MiddlewareActions.beforeSnapshotLookup;
function create(callback) {
var db = new ShareDbMongo(mongoUrl);
db.getDbs(function(err, mongo) {
if (err) return callback(err);
mongo.dropDatabase()
.then(function() {
callback(null, db, mongo);
})
.catch(callback);
});
}
describe('mongo db middleware', function() {
var sandbox = sinon.createSandbox();
var db;
beforeEach(function(done) {
sandbox.spy(Collection.prototype, 'find');
create(function(err, createdDb) {
if (err) return done(err);
db = createdDb;
done();
});
});
afterEach(function(done) {
sandbox.restore();
db.close(done);
});
describe('error handling', function() {
it('throws error when no action is given', function() {
function invalidAction() {
db.use(null, function(_request, next) {
next();
});
}
expect(invalidAction).to.throw();
});
it('throws error when no handler is given', function() {
function invalidAction() {
db.use('someAction');
}
expect(invalidAction).to.throw();
});
it('throws error on unrecognized action name', function() {
function invalidAction() {
db.use('someAction', function(_request, next) {
next();
});
}
expect(invalidAction).to.throw();
});
});
describe(BEFORE_EDIT, function() {
it('has the expected properties on the request object', function(done) {
db.use(BEFORE_EDIT, function(request, next) {
expect(request).to.have.all.keys([
'action',
'collectionName',
'documentToWrite',
'op',
'options',
'query'
]);
expect(request.action).to.equal(BEFORE_EDIT);
expect(request.collectionName).to.equal('testcollection');
expect(request.documentToWrite.foo).to.equal('fuzz');
expect(request.op.op).to.exist;
expect(request.options.testOptions).to.equal('yes');
expect(request.query._id).to.equal('test1');
next();
done();
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
var editOp = {v: 2, op: [{p: ['foo'], oi: 'bar', oi: 'baz'}], m: {ts: Date.now()}};
var newSnapshot = {type: 'json0', id: 'test1', v: 2, data: {foo: 'fuzz'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
db.commit('testcollection', snapshot.id, editOp, newSnapshot, {testOptions: 'yes'}, function(err) {
if (err) return done(err);
});
});
});
it('should augment query filter and write to the document when commit is called', function(done) {
// Augment the query. The original query looks up the document by id, wheras this middleware
// changes it to use the `foo` property. The end result still returns the same document. The next
// middleware ensures we attached it to the request.
// We can't truly change which document is returned from the query because MongoDB will not allow
// the immutable fields such as `_id` to be changed.
db.use(BEFORE_EDIT, function(request, next) {
request.query.foo = 'bar';
next();
});
// Attach this middleware to check that the original one is passing the context
// correctly. Commit will be called after this.
db.use(BEFORE_EDIT, function(request, next) {
expect(request.query).to.deep.equal({
_id: 'test1',
_v: 1,
foo: 'bar'
});
next();
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
var editOp = {v: 2, op: [{p: ['foo'], oi: 'bar', oi: 'baz'}], m: {ts: Date.now()}};
var newSnapshot = {type: 'json0', id: 'test1', v: 2, data: {foo: 'baz'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
expectDocumentToContainFoo('bar', function() {
db.commit('testcollection', snapshot.id, editOp, newSnapshot, null, function(err) {
if (err) return done(err);
// Ensure the value is updated as expected
expectDocumentToContainFoo('baz', done);
});
});
});
});
});
it('should augment the written document when commit is called', function(done) {
// Change the written value of foo to be `fuzz`
db.use(BEFORE_EDIT, function(request, next) {
request.documentToWrite.foo = 'fuzz';
next();
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
// Issue a commit to change `bar` to `baz`
var editOp = {v: 2, op: [{p: ['foo'], oi: 'bar', oi: 'baz'}], m: {ts: Date.now()}};
var newSnapshot = {type: 'json0', id: 'test1', v: 2, data: {foo: 'baz'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
expectDocumentToContainFoo('bar', function() {
db.commit('testcollection', snapshot.id, editOp, newSnapshot, null, function(err) {
if (err) return done(err);
// Ensure the value is updated as expected
expectDocumentToContainFoo('fuzz', done);
});
});
});
});
describe(BEFORE_CREATE, function() {
it('has the expected properties on the request object', function(done) {
db.use(BEFORE_CREATE, function(request, next) {
expect(request).to.have.all.keys([
'action',
'collectionName',
'documentToWrite',
'op',
'options'
]);
expect(request.action).to.equal(BEFORE_CREATE);
expect(request.collectionName).to.equal('testcollection');
expect(request.documentToWrite.foo).to.equal('bar');
expect(request.op).to.exist;
expect(request.options.testOptions).to.equal('baz');
next();
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, {testOptions: 'baz'}, done);
});
it('should augment the written document when commit is called', function(done) {
// Change the written value of foo to be `fuzz`
db.use(BEFORE_CREATE, function(request, next) {
request.documentToWrite.foo = 'fuzz';
next();
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
expectDocumentToContainFoo('fuzz', done);
});
});
it('returns without writing when there was a middleware error', function(done) {
db.use(BEFORE_CREATE, function(_, next) {
next(new Error('Oh no!'));
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
expectDocumentNotToExist(function() {
if (err) return done();
done('Expected an error, did not get one');
});
});
});
});
describe(BEFORE_SNAPSHOT_LOOKUP, function() {
it('has the expected properties on the request object before getting a single snapshot', function(done) {
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
expect(request).to.have.all.keys([
'action',
'collectionName',
'options',
'query'
]);
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
expect(request.collectionName).to.equal('testcollection');
expect(request.options.testOptions).to.equal('yes');
expect(request.query._id).to.equal('test1');
next();
done();
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
db.getSnapshot('testcollection', 'test1', null, {testOptions: 'yes'}, function(err, doc) {
if (err) return done(err);
expect(doc).to.exist;
});
});
});
it('passes triggeredBy = submitRequest when fields has $submit = true', function(done) {
var middlewareSpy = sinon.spy(function(request, next) {
expect(request).to.have.all.keys([
'action',
'collectionName',
'options',
'query',
'triggeredBy'
]);
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
expect(request.collectionName).to.equal('testcollection');
expect(request.options.testOptions).to.equal('yes');
expect(request.triggeredBy).to.equal('submitRequest');
expect(request.query._id).to.equal('test1');
// test that when we set findOptions in the middleware, they get passed to the Mongo driver.
request.findOptions = {
maxTimeMS: 999
};
next();
});
db.use(BEFORE_SNAPSHOT_LOOKUP, middlewareSpy);
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
db.getSnapshot('testcollection', 'test1', {
$submit: true
}, {testOptions: 'yes'}, function(err, doc) {
if (err) return done(err);
expect(doc).to.exist;
expect(middlewareSpy).to.have.been.calledOnceWith(sinon.match.object, sinon.match.func);
expect(Collection.prototype.find).to.have.been.calledOnceWith({
_id: snapshot.id
}, {
maxTimeMS: 999
});
done();
});
});
});
it('has the expected properties on the request object before getting ops', function(done) {
var middlewareSpy = sinon.spy(function(request, next) {
expect(request).to.have.all.keys([
'action',
'collectionName',
'options',
'query'
]);
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
expect(request.collectionName).to.equal('testcollection');
expect(request.options.testOptions).to.equal('yes');
expect(request.query._id).to.deep.equal('test2');
next();
});
db.use(BEFORE_SNAPSHOT_LOOKUP, middlewareSpy);
var snapshot = {type: 'json0', id: 'test2', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
db.getOps('testcollection', 'test2', 0, 1, {testOptions: 'yes'}, function(err) {
if (err) return done(err);
/*
Don't finalize the test in the middleware - since getOps will make queries *after* the middleware is fired.
If we call done() in the middleware, we'll close the db connection, and then getOps will call _getOps()
which will throw a "db connection closed" error.
*/
expect(middlewareSpy).to.have.been.calledOnceWith(sinon.match.object, sinon.match.func);
done();
});
});
});
it('has the expected properties on the request object before getting ops bulk', function(done) {
var middlewareSpy = sinon.spy(function(request, next) {
expect(request).to.have.all.keys([
'action',
'collectionName',
'options',
'query'
]);
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
expect(request.collectionName).to.equal('testcollection');
expect(request.options.testOptions).to.equal('yes');
expect(request.query._id).to.deep.equal({$in: ['test2']});
next();
});
db.use(BEFORE_SNAPSHOT_LOOKUP, middlewareSpy);
var snapshot = {type: 'json0', id: 'test2', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
db.getOpsBulk('testcollection', {
test2: 0
}, {
test2: 1
}, {testOptions: 'yes'}, function(err) {
if (err) return done(err);
/*
Don't finalize the test in the middleware - since getOps will make queries *after* the middleware is fired.
If we call done() in the middleware, we'll close the db connection, and then getOps will call _getOps()
which will throw a "db connection closed" error.
*/
expect(middlewareSpy).to.have.been.calledOnceWith(sinon.match.object, sinon.match.func);
done();
});
});
});
it('has the expected properties on the request object before getting bulk snapshots', function(done) {
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
expect(request).to.have.all.keys([
'action',
'collectionName',
'options',
'query'
]);
expect(request.action).to.equal(BEFORE_SNAPSHOT_LOOKUP);
expect(request.collectionName).to.equal('testcollection');
expect(request.options.testOptions).to.equal('yes');
expect(request.query._id).to.deep.equal({$in: ['test1']});
next();
done();
});
var snapshot = {type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}};
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, function(err) {
if (err) return done(err);
db.getSnapshotBulk('testcollection', ['test1'], null, {testOptions: 'yes'}, function(err, doc) {
if (err) return done(err);
expect(doc).to.exist;
});
});
});
it('should augment the query when getSnapshot is called', function(done) {
var snapshots = [
{type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}},
{type: 'json0', id: 'test2', v: 1, data: {foo: 'baz'}}
];
async.each(snapshots, function(snapshot, cb) {
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, cb);
}, function(err) {
if (err) return done(err);
db.getSnapshot('testcollection', 'test1', null, null, function(err, doc) {
if (err) return done(err);
expect(doc.data).eql({
foo: 'bar'
});
// Change the query to look for baz and not bar
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
request.query = {_id: 'test2'};
next();
});
db.getSnapshot('testcollection', 'test1', null, null, function(err, doc) {
if (err) return done(err);
expect(doc.data).eql({
foo: 'baz'
});
done();
});
});
});
});
it('should augment the query when getSnapshotBulk is called', function(done) {
var snapshots = [
{type: 'json0', id: 'test1', v: 1, data: {foo: 'bar'}},
{type: 'json0', id: 'test2', v: 1, data: {foo: 'baz'}}
];
async.each(snapshots, function(snapshot, cb) {
db.commit('testcollection', snapshot.id, {v: 0, create: {}}, snapshot, null, cb);
}, function(err) {
if (err) return done(err);
db.getSnapshotBulk('testcollection', ['test1', 'test2'], null, null, function(err, docs) {
if (err) return done(err);
expect(docs.test1.data.foo).to.equal('bar');
expect(docs.test2.data.foo).to.equal('baz');
// Change the query to look for baz and not bar
db.use(BEFORE_SNAPSHOT_LOOKUP, function(request, next) {
request.query = {_id: {$in: ['test2']}};
next();
});
db.getSnapshotBulk('testcollection', ['test1', 'test2'], null, null, function(err, docs) {
if (err) return done(err);
expect(docs.test1.data).not.to.exist;
expect(docs.test2.data.foo).to.equal('baz');
done();
});
});
});
});
});
function expectDocumentToContainFoo(valueOfFoo, cb) {
var query = {_id: 'test1'};
db.query('testcollection', query, null, null, function(err, results) {
if (err) return done(err);
expect(results[0].data).eql({
foo: valueOfFoo
});
cb();
});
};
function expectDocumentNotToExist(cb) {
var query = {_id: 'test1'};
db.query('testcollection', query, null, null, function(err, results) {
if (err) return cb(err);
expect(results).to.be.empty;
cb();
});
};
});