DataValidator: accept classification results
* src/validate/DataValidator.js (validate): New `classes' parameter. API BC break from previous commits. (populateStore, updateFailures): Generalize methods. * test/validate/DataValidatorTest.js: Add associated test. Refactor existing tests to adhere to new API/expectations. DEV-2206master
parent
28d74d7068
commit
0dcbd32202
|
@ -56,10 +56,10 @@ module.exports = Class( 'DataValidator',
|
||||||
'private _factory': null,
|
'private _factory': null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bucket diff store
|
* Various layers of the diff store
|
||||||
* @type {Store}
|
* @type {Object}
|
||||||
*/
|
*/
|
||||||
'private _store_factory': null,
|
'private _stores': {},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +96,7 @@ module.exports = Class( 'DataValidator',
|
||||||
*/
|
*/
|
||||||
'private _createStores': function( store_factory )
|
'private _createStores': function( store_factory )
|
||||||
{
|
{
|
||||||
this._bucket_store = store_factory();
|
this._stores = store_factory();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,12 +112,14 @@ module.exports = Class( 'DataValidator',
|
||||||
* @return {Promise} accepts with unspecified value once field monitor
|
* @return {Promise} accepts with unspecified value once field monitor
|
||||||
* has completed its update
|
* has completed its update
|
||||||
*/
|
*/
|
||||||
'public validate'( diff, validatef )
|
'public validate'( diff, classes, validatef )
|
||||||
{
|
{
|
||||||
const _self = this;
|
const _self = this;
|
||||||
|
|
||||||
let failures = {};
|
let failures = {};
|
||||||
|
|
||||||
|
if ( diff !== undefined )
|
||||||
|
{
|
||||||
_self._bucket_validator.validate( diff, ( name, value, i ) =>
|
_self._bucket_validator.validate( diff, ( name, value, i ) =>
|
||||||
{
|
{
|
||||||
diff[ name ][ i ] = undefined;
|
diff[ name ][ i ] = undefined;
|
||||||
|
@ -127,9 +129,11 @@ module.exports = Class( 'DataValidator',
|
||||||
}, true );
|
}, true );
|
||||||
|
|
||||||
validatef && validatef( diff, failures );
|
validatef && validatef( diff, failures );
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: this assumes that the above is synchronous
|
// XXX: this assumes that the above is synchronous
|
||||||
return this.updateFailures( diff, failures );
|
return this._populateStore( classes, this._stores.cstore, 'indexes' )
|
||||||
|
.then( () => this.updateFailures( diff, failures ) );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,36 +150,39 @@ module.exports = Class( 'DataValidator',
|
||||||
*/
|
*/
|
||||||
'public updateFailures'( diff, failures )
|
'public updateFailures'( diff, failures )
|
||||||
{
|
{
|
||||||
const _self = this;
|
return this._populateStore( diff, this._stores.bstore ).then( () =>
|
||||||
|
this._field_monitor.update(
|
||||||
return this._populateStore( diff ).then( () =>
|
this._stores.store, failures
|
||||||
{
|
)
|
||||||
return _self._field_monitor.update(
|
|
||||||
_self._bucket_store, failures
|
|
||||||
);
|
);
|
||||||
} );
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate store with diff
|
* Populate store with data
|
||||||
*
|
*
|
||||||
* This effectively converts a basic array into a `Store`. This is
|
* This effectively converts a basic array into a `Store`. This is
|
||||||
* surprisingly performant on v8. If the stores mix in traits, there
|
* surprisingly performant on v8. If the stores mix in traits, there
|
||||||
* may be a slight performance hit for trait-overridden methods.
|
* may be a slight performance hit for trait-overridden methods.
|
||||||
*
|
*
|
||||||
* @param {Object} diff bucket diff
|
* @param {Object} data data to map onto store
|
||||||
*
|
*
|
||||||
* @return {Promise} when all items have been added to the store
|
* @return {Promise} when all items have been added to the store
|
||||||
*/
|
*/
|
||||||
'private _populateStore'( diff )
|
'private _populateStore'( data, store, subkey )
|
||||||
{
|
{
|
||||||
var bstore = this._bucket_store;
|
if ( data === undefined )
|
||||||
|
{
|
||||||
|
return Promise.resolve( [] );
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.all(
|
const mapf = ( subkey !== undefined )
|
||||||
Object.keys( diff ).map(
|
? key => store.add( key, data[ key ][ subkey ] )
|
||||||
key => bstore.add( key, diff[ key ] )
|
: key => store.add( key, data[ key ] );
|
||||||
)
|
|
||||||
);
|
return store.clear()
|
||||||
|
.then( () => Promise.all(
|
||||||
|
Object.keys( data ).map( mapf )
|
||||||
|
) );
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -56,7 +56,11 @@ describe( 'DataValidator', () =>
|
||||||
|
|
||||||
const vmonitor = ValidStateMonitor();
|
const vmonitor = ValidStateMonitor();
|
||||||
const dep_factory = createMockDependencyFactory();
|
const dep_factory = createMockDependencyFactory();
|
||||||
|
|
||||||
const getStore = createStubStore();
|
const getStore = createStubStore();
|
||||||
|
const { bstore } = getStore();
|
||||||
|
|
||||||
|
const mock_bstore = sinon.mock( bstore );
|
||||||
|
|
||||||
const mock_vmonitor = sinon.mock( vmonitor );
|
const mock_vmonitor = sinon.mock( vmonitor );
|
||||||
const mock_dep_factory = sinon.mock( dep_factory );
|
const mock_dep_factory = sinon.mock( dep_factory );
|
||||||
|
@ -68,9 +72,10 @@ describe( 'DataValidator', () =>
|
||||||
foo: { 1: expected_failure }
|
foo: { 1: expected_failure }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// call to actual validator
|
||||||
mock_vmonitor.expects( 'update' )
|
mock_vmonitor.expects( 'update' )
|
||||||
.once()
|
.once()
|
||||||
.withExactArgs( getStore(), expected_failures )
|
.withExactArgs( getStore().store, expected_failures )
|
||||||
.returns( Promise.resolve( undefined ) );
|
.returns( Promise.resolve( undefined ) );
|
||||||
|
|
||||||
mock_dep_factory.expects( 'createFieldFailure' )
|
mock_dep_factory.expects( 'createFieldFailure' )
|
||||||
|
@ -78,6 +83,11 @@ describe( 'DataValidator', () =>
|
||||||
.withExactArgs( 'foo', 1, expected_value )
|
.withExactArgs( 'foo', 1, expected_value )
|
||||||
.returns( expected_failure );
|
.returns( expected_failure );
|
||||||
|
|
||||||
|
// clears previous diffs
|
||||||
|
mock_bstore.expects( 'clear' )
|
||||||
|
.once()
|
||||||
|
.returns( Promise.resolve( bstore ) );
|
||||||
|
|
||||||
return Sut( bvalidator, vmonitor, dep_factory, getStore )
|
return Sut( bvalidator, vmonitor, dep_factory, getStore )
|
||||||
.validate( diff )
|
.validate( diff )
|
||||||
.then( () =>
|
.then( () =>
|
||||||
|
@ -86,12 +96,54 @@ describe( 'DataValidator', () =>
|
||||||
mock_dep_factory.verify();
|
mock_dep_factory.verify();
|
||||||
|
|
||||||
// cleared on call to err in above mock validator
|
// cleared on call to err in above mock validator
|
||||||
return expect( getStore().get( 'foo' ) )
|
return expect( getStore().bstore.get( 'foo' ) )
|
||||||
.to.eventually.deep.equal( [ 'a', undefined, 'c' ] );
|
.to.eventually.deep.equal( [ 'a', undefined, 'c' ] );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( 'merges classification changes with diff', () =>
|
||||||
|
{
|
||||||
|
// SUT will only care about the indexes
|
||||||
|
const classes = {
|
||||||
|
first: { indexes: [], is: false },
|
||||||
|
second: { indexes: [ 0, 1 ], is: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const bvalidator = createMockBucketValidator();
|
||||||
|
const vmonitor = ValidStateMonitor();
|
||||||
|
const dep_factory = createMockDependencyFactory();
|
||||||
|
|
||||||
|
const getStore = createStubStore();
|
||||||
|
const { cstore } = getStore();
|
||||||
|
|
||||||
|
const mock_cstore = sinon.mock( cstore );
|
||||||
|
|
||||||
|
// clears previous diffs
|
||||||
|
mock_cstore.expects( 'clear' )
|
||||||
|
.once()
|
||||||
|
.returns( Promise.resolve( cstore ) );
|
||||||
|
|
||||||
|
return Sut( bvalidator, vmonitor, dep_factory, getStore )
|
||||||
|
.validate( {}, classes )
|
||||||
|
.then( () =>
|
||||||
|
{
|
||||||
|
// clear should have been called
|
||||||
|
mock_cstore.verify();
|
||||||
|
|
||||||
|
// keep in mind that we are using MemoryStore for this
|
||||||
|
// test (whereas a real implementation would probably be
|
||||||
|
// using a DiffStore)
|
||||||
|
return Promise.all(
|
||||||
|
Object.keys( classes ).map( key =>
|
||||||
|
expect( cstore.get( key ) )
|
||||||
|
.to.eventually.deep.equal( classes[ key ].indexes )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
it( 'considers failures from external validator', () =>
|
it( 'considers failures from external validator', () =>
|
||||||
{
|
{
|
||||||
const expected_failure = {};
|
const expected_failure = {};
|
||||||
|
@ -130,7 +182,7 @@ describe( 'DataValidator', () =>
|
||||||
sinon.mock( vmonitor )
|
sinon.mock( vmonitor )
|
||||||
.expects( 'update' )
|
.expects( 'update' )
|
||||||
.once()
|
.once()
|
||||||
.withExactArgs( getStore(), expected_failures )
|
.withExactArgs( getStore().store, expected_failures )
|
||||||
.returns( Promise.resolve( undefined ) );
|
.returns( Promise.resolve( undefined ) );
|
||||||
|
|
||||||
sinon.mock( dep_factory )
|
sinon.mock( dep_factory )
|
||||||
|
@ -138,13 +190,13 @@ describe( 'DataValidator', () =>
|
||||||
.returns( expected_failure );
|
.returns( expected_failure );
|
||||||
|
|
||||||
return Sut( bvalidator, vmonitor, dep_factory, getStore )
|
return Sut( bvalidator, vmonitor, dep_factory, getStore )
|
||||||
.validate( diff, validatef );
|
.validate( diff, {}, validatef );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
it( 'rejects if field monitor update rejects', () =>
|
it( 'rejects if field monitor update rejects', () =>
|
||||||
{
|
{
|
||||||
const bvalidator = createMockBucketValidator( ( x, y, z ) => {} );
|
const bvalidator = createMockBucketValidator();
|
||||||
const vmonitor = ValidStateMonitor();
|
const vmonitor = ValidStateMonitor();
|
||||||
const dep_factory = createMockDependencyFactory();
|
const dep_factory = createMockDependencyFactory();
|
||||||
|
|
||||||
|
@ -166,6 +218,8 @@ describe( 'DataValidator', () =>
|
||||||
|
|
||||||
function createMockBucketValidator( validatef )
|
function createMockBucketValidator( validatef )
|
||||||
{
|
{
|
||||||
|
validatef = validatef || ( ( x, y, z ) => {} );
|
||||||
|
|
||||||
return BucketDataValidator.extend(
|
return BucketDataValidator.extend(
|
||||||
{
|
{
|
||||||
'override public validate': validatef,
|
'override public validate': validatef,
|
||||||
|
@ -186,7 +240,11 @@ function createMockDependencyFactory( map )
|
||||||
|
|
||||||
function createStubStore()
|
function createStubStore()
|
||||||
{
|
{
|
||||||
const store = MemoryStore();
|
const stores = {
|
||||||
|
store: MemoryStore(),
|
||||||
|
bstore: MemoryStore(),
|
||||||
|
cstore: MemoryStore(),
|
||||||
|
};
|
||||||
|
|
||||||
return () => store;
|
return () => stores;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue