1
0
Fork 0

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-2206
master
Mike Gerwitz 2017-01-30 00:06:08 -05:00
parent 28d74d7068
commit 0dcbd32202
2 changed files with 102 additions and 37 deletions

View File

@ -56,10 +56,10 @@ module.exports = Class( 'DataValidator',
'private _factory': null,
/**
* Bucket diff store
* @type {Store}
* Various layers of the diff store
* @type {Object}
*/
'private _store_factory': null,
'private _stores': {},
/**
@ -96,7 +96,7 @@ module.exports = Class( 'DataValidator',
*/
'private _createStores': function( store_factory )
{
this._bucket_store = store_factory();
this._stores = store_factory();
},
@ -112,24 +112,28 @@ module.exports = Class( 'DataValidator',
* @return {Promise} accepts with unspecified value once field monitor
* has completed its update
*/
'public validate'( diff, validatef )
'public validate'( diff, classes, validatef )
{
const _self = this;
let failures = {};
_self._bucket_validator.validate( diff, ( name, value, i ) =>
if ( diff !== undefined )
{
diff[ name ][ i ] = undefined;
_self._bucket_validator.validate( diff, ( name, value, i ) =>
{
diff[ name ][ i ] = undefined;
( failures[ name ] = failures[ name ] || {} )[ i ] =
_self._factory.createFieldFailure( name, i, value );
}, true );
( failures[ name ] = failures[ name ] || {} )[ i ] =
_self._factory.createFieldFailure( name, i, value );
}, true );
validatef && validatef( diff, failures );
validatef && validatef( diff, failures );
}
// 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 )
{
const _self = this;
return this._populateStore( diff ).then( () =>
{
return _self._field_monitor.update(
_self._bucket_store, failures
);
} );
return this._populateStore( diff, this._stores.bstore ).then( () =>
this._field_monitor.update(
this._stores.store, failures
)
);
},
/**
* Populate store with diff
* Populate store with data
*
* This effectively converts a basic array into a `Store`. This is
* surprisingly performant on v8. If the stores mix in traits, there
* 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
*/
'private _populateStore'( diff )
'private _populateStore'( data, store, subkey )
{
var bstore = this._bucket_store;
if ( data === undefined )
{
return Promise.resolve( [] );
}
return Promise.all(
Object.keys( diff ).map(
key => bstore.add( key, diff[ key ] )
)
);
const mapf = ( subkey !== undefined )
? key => store.add( key, data[ key ][ subkey ] )
: key => store.add( key, data[ key ] );
return store.clear()
.then( () => Promise.all(
Object.keys( data ).map( mapf )
) );
},
} );

View File

@ -56,7 +56,11 @@ describe( 'DataValidator', () =>
const vmonitor = ValidStateMonitor();
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_dep_factory = sinon.mock( dep_factory );
@ -68,9 +72,10 @@ describe( 'DataValidator', () =>
foo: { 1: expected_failure }
};
// call to actual validator
mock_vmonitor.expects( 'update' )
.once()
.withExactArgs( getStore(), expected_failures )
.withExactArgs( getStore().store, expected_failures )
.returns( Promise.resolve( undefined ) );
mock_dep_factory.expects( 'createFieldFailure' )
@ -78,6 +83,11 @@ describe( 'DataValidator', () =>
.withExactArgs( 'foo', 1, expected_value )
.returns( expected_failure );
// clears previous diffs
mock_bstore.expects( 'clear' )
.once()
.returns( Promise.resolve( bstore ) );
return Sut( bvalidator, vmonitor, dep_factory, getStore )
.validate( diff )
.then( () =>
@ -86,12 +96,54 @@ describe( 'DataValidator', () =>
mock_dep_factory.verify();
// 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' ] );
} );
} );
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', () =>
{
const expected_failure = {};
@ -130,7 +182,7 @@ describe( 'DataValidator', () =>
sinon.mock( vmonitor )
.expects( 'update' )
.once()
.withExactArgs( getStore(), expected_failures )
.withExactArgs( getStore().store, expected_failures )
.returns( Promise.resolve( undefined ) );
sinon.mock( dep_factory )
@ -138,13 +190,13 @@ describe( 'DataValidator', () =>
.returns( expected_failure );
return Sut( bvalidator, vmonitor, dep_factory, getStore )
.validate( diff, validatef );
.validate( diff, {}, validatef );
} );
it( 'rejects if field monitor update rejects', () =>
{
const bvalidator = createMockBucketValidator( ( x, y, z ) => {} );
const bvalidator = createMockBucketValidator();
const vmonitor = ValidStateMonitor();
const dep_factory = createMockDependencyFactory();
@ -166,6 +218,8 @@ describe( 'DataValidator', () =>
function createMockBucketValidator( validatef )
{
validatef = validatef || ( ( x, y, z ) => {} );
return BucketDataValidator.extend(
{
'override public validate': validatef,
@ -186,7 +240,11 @@ function createMockDependencyFactory( map )
function createStubStore()
{
const store = MemoryStore();
const stores = {
store: MemoryStore(),
bstore: MemoryStore(),
cstore: MemoryStore(),
};
return () => store;
return () => stores;
}