test: extract hook-monitor helper
This commit is contained in:
parent
90f04181a4
commit
7d7662bfef
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright IBM Corp. 2016. All Rights Reserved.
|
||||||
|
// Node module: loopback-datasource-juggler
|
||||||
|
// This file is licensed under the MIT License.
|
||||||
|
// License text available at https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
module.exports = HookMonitor;
|
||||||
|
|
||||||
|
function HookMonitor(opts) {
|
||||||
|
if (!(this instanceof HookMonitor)) {
|
||||||
|
return new HookMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options = opts || {};
|
||||||
|
this.names = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
HookMonitor.prototype.install = function(ObservedModel, hookNames) {
|
||||||
|
var monitor = this;
|
||||||
|
this.names = [];
|
||||||
|
ObservedModel._notify = ObservedModel.notifyObserversOf;
|
||||||
|
ObservedModel.notifyObserversOf = function(operation, context, callback) {
|
||||||
|
if (!Array.isArray(hookNames) || hookNames.indexOf(operation) !== -1) {
|
||||||
|
var item = monitor.options.includeModelName ?
|
||||||
|
ObservedModel.modelName + ':' + operation :
|
||||||
|
operation;
|
||||||
|
monitor.names.push(item);
|
||||||
|
}
|
||||||
|
this._notify.apply(this, arguments);
|
||||||
|
};
|
||||||
|
};
|
|
@ -13,23 +13,24 @@ var aCtxForModel = contextTestHelpers.aCtxForModel;
|
||||||
var uid = require('./helpers/uid-generator');
|
var uid = require('./helpers/uid-generator');
|
||||||
var getLastGeneratedUid = uid.last;
|
var getLastGeneratedUid = uid.last;
|
||||||
|
|
||||||
|
var HookMonitor = require('./helpers/hook-monitor');
|
||||||
|
|
||||||
module.exports = function(dataSource, should, connectorCapabilities) {
|
module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
if (!connectorCapabilities) connectorCapabilities = {};
|
if (!connectorCapabilities) connectorCapabilities = {};
|
||||||
if (connectorCapabilities.replaceOrCreateReportsNewInstance === undefined) {
|
if (connectorCapabilities.replaceOrCreateReportsNewInstance === undefined) {
|
||||||
console.warn('The connector does not support a recently added feature: replaceOrCreateReportsNewInstance');
|
console.warn('The connector does not support a recently added feature: replaceOrCreateReportsNewInstance');
|
||||||
}
|
}
|
||||||
describe('Persistence hooks', function() {
|
describe('Persistence hooks', function() {
|
||||||
var ctxRecorder, expectedError, observersCalled;
|
var ctxRecorder, hookMonitor, expectedError;
|
||||||
var TestModel, existingInstance;
|
var TestModel, existingInstance;
|
||||||
var migrated = false;
|
var migrated = false;
|
||||||
var triggered;
|
|
||||||
|
|
||||||
var undefinedValue = undefined;
|
var undefinedValue = undefined;
|
||||||
|
|
||||||
beforeEach(function setupDatabase(done) {
|
beforeEach(function setupDatabase(done) {
|
||||||
ctxRecorder = new ContextRecorder('hook not called');
|
ctxRecorder = new ContextRecorder('hook not called');
|
||||||
|
hookMonitor = new HookMonitor({ includeModelName: false });
|
||||||
expectedError = new Error('test error');
|
expectedError = new Error('test error');
|
||||||
observersCalled = [];
|
|
||||||
|
|
||||||
TestModel = dataSource.createModel('TestModel', {
|
TestModel = dataSource.createModel('TestModel', {
|
||||||
// Set id.generated to false to honor client side values
|
// Set id.generated to false to honor client side values
|
||||||
|
@ -76,7 +77,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
function(err, list) {
|
function(err, list) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'loaded'
|
'loaded'
|
||||||
]);
|
]);
|
||||||
|
@ -186,7 +187,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
'loaded',
|
'loaded',
|
||||||
|
@ -552,7 +553,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
{ name: 'new-record' },
|
{ name: 'new-record' },
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
|
@ -573,14 +574,14 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
|
||||||
if (dataSource.connector.findOrCreate) {
|
if (dataSource.connector.findOrCreate) {
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
'loaded'
|
'loaded'
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'loaded'
|
'loaded'
|
||||||
]);
|
]);
|
||||||
|
@ -931,7 +932,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
existingInstance.save(
|
existingInstance.save(
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
'loaded',
|
'loaded',
|
||||||
|
@ -1143,7 +1144,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
{ name: 'changed' },
|
{ name: 'changed' },
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
'loaded',
|
'loaded',
|
||||||
|
@ -1399,7 +1400,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
{ name: 'replaced' },
|
{ name: 'replaced' },
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
'loaded',
|
'loaded',
|
||||||
|
@ -1642,7 +1643,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
{ id: 'not-found', name: 'not found' },
|
{ id: 'not-found', name: 'not found' },
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
|
@ -1661,7 +1662,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
if (dataSource.connector.updateOrCreate) {
|
if (dataSource.connector.updateOrCreate) {
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
|
@ -1669,7 +1670,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
'after save'
|
'after save'
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'loaded',
|
'loaded',
|
||||||
'before save',
|
'before save',
|
||||||
|
@ -1766,8 +1767,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('triggers hooks only once', function(done) {
|
it('triggers hooks only once', function(done) {
|
||||||
TestModel.observe('access', pushNameAndNext('access'));
|
monitorHookExecution(['access', 'before save']);
|
||||||
TestModel.observe('before save', pushNameAndNext('before save'));
|
|
||||||
|
|
||||||
TestModel.observe('access', function(ctx, next) {
|
TestModel.observe('access', function(ctx, next) {
|
||||||
ctx.query = { where: { id: { neq: existingInstance.id } } };
|
ctx.query = { where: { id: { neq: existingInstance.id } } };
|
||||||
|
@ -1778,7 +1778,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
{ id: 'ignored', name: 'new name' },
|
{ id: 'ignored', name: 'new name' },
|
||||||
function(err, instance) {
|
function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observersCalled.should.eql(['access', 'before save']);
|
hookMonitor.names.should.eql(['access', 'before save']);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2097,7 +2097,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
{ id: 'not-found', name: 'not found' },
|
{ id: 'not-found', name: 'not found' },
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
|
@ -2116,7 +2116,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
if (dataSource.connector.replaceOrCreate) {
|
if (dataSource.connector.replaceOrCreate) {
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'before save',
|
'before save',
|
||||||
'persist',
|
'persist',
|
||||||
|
@ -2133,7 +2133,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
// loopback-datasource-juggler/issues#836.
|
// loopback-datasource-juggler/issues#836.
|
||||||
// 2) It, also, gets triggered in "replaceAttributes()"
|
// 2) It, also, gets triggered in "replaceAttributes()"
|
||||||
// in this chain replaceORCreate()->replaceAttributes()
|
// in this chain replaceORCreate()->replaceAttributes()
|
||||||
triggered.should.eql([
|
hookMonitor.names.should.eql([
|
||||||
'access',
|
'access',
|
||||||
'loaded',
|
'loaded',
|
||||||
'before save',
|
'before save',
|
||||||
|
@ -2230,8 +2230,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('triggers hooks only once', function(done) {
|
it('triggers hooks only once', function(done) {
|
||||||
TestModel.observe('access', pushNameAndNext('access'));
|
monitorHookExecution(['access', 'before save']);
|
||||||
TestModel.observe('before save', pushNameAndNext('before save'));
|
|
||||||
|
|
||||||
TestModel.observe('access', function(ctx, next) {
|
TestModel.observe('access', function(ctx, next) {
|
||||||
ctx.query = { where: { id: { neq: existingInstance.id } } };
|
ctx.query = { where: { id: { neq: existingInstance.id } } };
|
||||||
|
@ -2242,7 +2241,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
{ id: 'ignored', name: 'new name' },
|
{ id: 'ignored', name: 'new name' },
|
||||||
function(err, instance) {
|
function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observersCalled.should.eql(['access', 'before save']);
|
hookMonitor.names.should.eql(['access', 'before save']);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2802,8 +2801,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('triggers hooks only once', function(done) {
|
it('triggers hooks only once', function(done) {
|
||||||
TestModel.observe('access', pushNameAndNext('access'));
|
monitorHookExecution();
|
||||||
TestModel.observe('after delete', pushNameAndNext('after delete'));
|
|
||||||
TestModel.observe('access', function(ctx, next) {
|
TestModel.observe('access', function(ctx, next) {
|
||||||
ctx.query = { where: { id: { neq: existingInstance.id } } };
|
ctx.query = { where: { id: { neq: existingInstance.id } } };
|
||||||
next();
|
next();
|
||||||
|
@ -2811,7 +2809,7 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
|
|
||||||
existingInstance.delete(function(err) {
|
existingInstance.delete(function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observersCalled.should.eql(['access', 'after delete']);
|
hookMonitor.names.should.eql(['access', 'before delete', 'after delete']);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2973,13 +2971,6 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function pushNameAndNext(name) {
|
|
||||||
return function(context, next) {
|
|
||||||
observersCalled.push(name);
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextWithError(err) {
|
function nextWithError(err) {
|
||||||
return function(context, next) {
|
return function(context, next) {
|
||||||
next(err);
|
next(err);
|
||||||
|
@ -3010,13 +3001,8 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
TestModel.findOne({ where: { id: id } }, { notify: false }, cb);
|
TestModel.findOne({ where: { id: id } }, { notify: false }, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function monitorHookExecution() {
|
function monitorHookExecution(hookNames) {
|
||||||
triggered = [];
|
hookMonitor.install(TestModel, hookNames);
|
||||||
TestModel._notify = TestModel.notifyObserversOf;
|
|
||||||
TestModel.notifyObserversOf = function(operation, context, callback) {
|
|
||||||
triggered.push(operation);
|
|
||||||
this._notify.apply(this, arguments);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue