ValidStateMonitor#update return Promise
Stepping stone to async. fix checks. * src/validate/ValidStateMonitor.js (update, detectFixes, _checkFailureFix): Return Promise. * test/validate/ValidStateMonitorTest.js: Update to use promises. DEV-2296master
parent
af7813e605
commit
fb3cd11265
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Field validity monitor
|
||||
*
|
||||
* Copyright (C) 2016 LoVullo Associates, Inc.
|
||||
* Copyright (C) 2016, 2017 LoVullo Associates, Inc.
|
||||
*
|
||||
* This file is part of liza.
|
||||
*
|
||||
|
@ -40,22 +40,29 @@ module.exports = Class( 'ValidStateMonitor' )
|
|||
/**
|
||||
* Mark fields as updated and detect failures and fixes
|
||||
*
|
||||
* The field data DATA should be a key-value store with an array as the
|
||||
* value for each key. If the data are not present, then it is assumed
|
||||
* to have been left unchanged, and will not contribute to a
|
||||
* fix. Otherwise, any field in FAILURES but not in DATA will count as
|
||||
* a fix.
|
||||
* The field data `data` should be a key-value store with an array as
|
||||
* the value for each key. If the data are not present, then it is
|
||||
* assumed to have been left unchanged, and will not contribute to a
|
||||
* fix. Otherwise, any field in `failures` but not in `data` will count
|
||||
* as a fix.
|
||||
*
|
||||
* FAILURES should follow the same structure as DATA. Indexes should
|
||||
* omitted from the value if they are not failures.
|
||||
* `failures` should follow the same structure as `data`. Indexes
|
||||
* should omitted from the value if they are not failures.
|
||||
*
|
||||
* The return value is a promise that is accepted once all fix checks
|
||||
* have been performed (after which the `fix` event is emitted if
|
||||
* appropriate). The `failure` event is emitted synchronously if any
|
||||
* additional failures are detected.
|
||||
*
|
||||
* @param {Object} data key-value field data
|
||||
* @param {Object} failures key-value field errors
|
||||
*
|
||||
* @return {ValidStateMonitor} self
|
||||
* @return {Promise.<ValidStateMonitor>} self after fix checks
|
||||
*/
|
||||
'public update': function( data, failures )
|
||||
{
|
||||
var _self = this;
|
||||
|
||||
var fixed = this.detectFixes( data, this._failures, failures ),
|
||||
count_new = this.mergeFailures( this._failures, failures );
|
||||
|
||||
|
@ -64,12 +71,16 @@ module.exports = Class( 'ValidStateMonitor' )
|
|||
this.emit( 'failure', this._failures );
|
||||
}
|
||||
|
||||
if ( fixed !== null )
|
||||
// failures is synchronous, fixes async
|
||||
return fixed.then( function( fixes )
|
||||
{
|
||||
this.emit( 'fix', fixed );
|
||||
}
|
||||
if ( fixes !== null )
|
||||
{
|
||||
_self.emit( 'fix', fixes );
|
||||
}
|
||||
|
||||
return this;
|
||||
return _self.__inst;
|
||||
} );
|
||||
},
|
||||
|
||||
|
||||
|
@ -182,26 +193,35 @@ module.exports = Class( 'ValidStateMonitor' )
|
|||
* @param {Object} data validated data
|
||||
* @param {Object} failures new failures
|
||||
*
|
||||
* @return {!Object} fixed list of fixed indexes for each fixed field
|
||||
* @return {Promise.<!Object>} fixed list of fixed indexes for each fixed field
|
||||
*/
|
||||
'virtual protected detectFixes': function( data, past, failures )
|
||||
{
|
||||
var fixed = {},
|
||||
has_fixed = false;
|
||||
var _self = this,
|
||||
fixed = {};
|
||||
|
||||
for ( var name in past )
|
||||
{
|
||||
var past_fail = past[ name ],
|
||||
fail = failures[ name ];
|
||||
return Promise.all(
|
||||
Object.keys( past ).map( function( name )
|
||||
{
|
||||
var past_fail = past[ name ],
|
||||
fail = failures[ name ];
|
||||
|
||||
has_fixed = has_fixed || this._checkFailureFix(
|
||||
name, fail, past_fail, data, fixed
|
||||
);
|
||||
}
|
||||
return _self._checkFailureFix(
|
||||
name, fail, past_fail, data, fixed
|
||||
);
|
||||
} )
|
||||
)
|
||||
.then( function( fixes )
|
||||
{
|
||||
var has_fixed = fixes.some( function( value )
|
||||
{
|
||||
return value === true;
|
||||
} );
|
||||
|
||||
return ( has_fixed )
|
||||
? fixed
|
||||
: null;
|
||||
return ( has_fixed )
|
||||
? fixed
|
||||
: null;
|
||||
} );
|
||||
},
|
||||
|
||||
|
||||
|
@ -214,7 +234,7 @@ module.exports = Class( 'ValidStateMonitor' )
|
|||
* @param {Object} data validated data
|
||||
* @param {Object} fixed destination for fixed field data
|
||||
*
|
||||
* @return {boolean} whether a field was fixed
|
||||
* @return {Promise.<boolean>} whether a field was fixed
|
||||
*/
|
||||
'private _checkFailureFix': function( name, fail, past_fail, data, fixed )
|
||||
{
|
||||
|
@ -261,6 +281,7 @@ module.exports = Class( 'ValidStateMonitor' )
|
|||
}
|
||||
}
|
||||
|
||||
return has_fixed;
|
||||
// preparation for future use of Store, which is async
|
||||
return Promise.resolve( has_fixed );
|
||||
}
|
||||
} );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Test field validity monitor
|
||||
*
|
||||
* Copyright (C) 2016 LoVullo Associates, Inc.
|
||||
* Copyright (C) 2016, 2017 LoVullo Associates, Inc.
|
||||
*
|
||||
* This file is part of liza.
|
||||
*
|
||||
|
@ -21,10 +21,13 @@
|
|||
|
||||
var root = require( '../../' ),
|
||||
Sut = root.validate.ValidStateMonitor,
|
||||
expect = require( 'chai' ).expect,
|
||||
chai = require( 'chai' ),
|
||||
expect = chai.expect,
|
||||
Failure = root.validate.Failure,
|
||||
Field = root.field.BucketField;
|
||||
|
||||
chai.use( require( 'chai-as-promised' ) );
|
||||
|
||||
|
||||
var nocall = function( type )
|
||||
{
|
||||
|
@ -51,7 +54,7 @@ describe( 'ValidStateMonitor', function()
|
|||
{
|
||||
it( 'does nothing with no data or failures', function()
|
||||
{
|
||||
Sut()
|
||||
return Sut()
|
||||
.on( 'failure', nocall( 'failure' ) )
|
||||
.on( 'fix', nocall( 'fix' ) )
|
||||
.update( {}, {} );
|
||||
|
@ -60,7 +63,7 @@ describe( 'ValidStateMonitor', function()
|
|||
|
||||
it( 'does nothing with data but no failures', function()
|
||||
{
|
||||
Sut()
|
||||
return Sut()
|
||||
.on( 'failure', nocall( 'failure' ) )
|
||||
.on( 'fix', nocall( 'fix' ) )
|
||||
.update( { foo: mkfail( 'foo', [ 'bar' ] ) }, {} );
|
||||
|
@ -128,7 +131,10 @@ describe( 'ValidStateMonitor', function()
|
|||
.once( 'failure', test_first )
|
||||
.on( 'fix', nocall( 'fix' ) )
|
||||
.update( {}, { foo: [ undefined, fail[ 1 ] ] } )
|
||||
.update( {}, { foo: [ fail[ 0 ] ] } );
|
||||
.then( () =>
|
||||
{
|
||||
return sut.update( {}, { foo: [ fail[ 0 ] ] } );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
|
@ -172,24 +178,28 @@ describe( 'ValidStateMonitor', function()
|
|||
// leading to fewer caues
|
||||
sut
|
||||
.update( {}, { foo: [ fail1 ] } )
|
||||
.update( {}, { foo: [ fail2 ] } );
|
||||
|
||||
// if cause1 wasn't removed, then this will fix it
|
||||
sut
|
||||
.once( 'fix', function( fixed )
|
||||
.then( () =>
|
||||
{
|
||||
expect( fixed )
|
||||
.to.deep.equal( { foo: [ 'causefix1' ] } );
|
||||
|
||||
// and then we should have no failures
|
||||
expect( sut.hasFailures() ).to.be.false;
|
||||
|
||||
done();
|
||||
return sut.update( {}, { foo: [ fail2 ] } );
|
||||
} )
|
||||
.update(
|
||||
{ foo: [ 'moo' ], cause1: [ 'causefix1' ] },
|
||||
{}
|
||||
);
|
||||
.then( () =>
|
||||
{
|
||||
return sut
|
||||
.once( 'fix', function( fixed )
|
||||
{
|
||||
expect( fixed )
|
||||
.to.deep.equal( { foo: [ 'causefix1' ] } );
|
||||
|
||||
// and then we should have no failures
|
||||
expect( sut.hasFailures() ).to.be.false;
|
||||
|
||||
done();
|
||||
} )
|
||||
.update(
|
||||
{ foo: [ 'moo' ], cause1: [ 'causefix1' ] },
|
||||
{}
|
||||
);
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
@ -201,7 +211,9 @@ describe( 'ValidStateMonitor', function()
|
|||
var data = { foo: [ 'bardata', 'baz' ] },
|
||||
fail = mkfail( 'foo', [ 'bar', 'baz' ] );
|
||||
|
||||
Sut()
|
||||
var sut = Sut();
|
||||
|
||||
sut
|
||||
.on( 'fix', function( fixed )
|
||||
{
|
||||
expect( fixed )
|
||||
|
@ -209,7 +221,10 @@ describe( 'ValidStateMonitor', function()
|
|||
done();
|
||||
} )
|
||||
.update( data, { foo: [ fail[ 0 ], fail[ 1 ] ] } )
|
||||
.update( data, { foo: [ undefined, fail[ 1 ] ] } );
|
||||
.then( () =>
|
||||
{
|
||||
return sut.update( data, { foo: [ undefined, fail[ 1 ] ] } );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
|
@ -230,7 +245,10 @@ describe( 'ValidStateMonitor', function()
|
|||
foo: fail_foo, // does not exist in data
|
||||
bar: fail_bar,
|
||||
} )
|
||||
.update( data, {} );
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.update( data, {} );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
|
@ -244,9 +262,14 @@ describe( 'ValidStateMonitor', function()
|
|||
called++;
|
||||
} )
|
||||
.update( {}, { foo: mkfail( 'foo', [ 'bar' ] ) } )
|
||||
.update( {}, {} ); // do not trigger failure event
|
||||
|
||||
expect( called ).to.equal( 1 );
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.update( {}, {} ); // do not trigger failure event
|
||||
} )
|
||||
.then( sut =>
|
||||
{
|
||||
expect( called ).to.equal( 1 );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
|
@ -269,7 +292,10 @@ describe( 'ValidStateMonitor', function()
|
|||
done();
|
||||
} )
|
||||
.update( data, { foo: [ fail ] } )
|
||||
.update( data, {} );
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.update( data, {} );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
|
@ -290,7 +316,10 @@ describe( 'ValidStateMonitor', function()
|
|||
done();
|
||||
} )
|
||||
.update( data, { foo: [ fail ] } )
|
||||
.update( data, {} );
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.update( data, {} );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
|
@ -316,7 +345,10 @@ describe( 'ValidStateMonitor', function()
|
|||
done();
|
||||
} )
|
||||
.update( data, { foo: [ fail ] } )
|
||||
.update( data, {} );
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.update( data, {} );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
|
@ -336,7 +368,10 @@ describe( 'ValidStateMonitor', function()
|
|||
Sut()
|
||||
.on( 'fix', nocall )
|
||||
.update( data, { foo: [ fail ] } )
|
||||
.update( data, {} );
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.update( data, {} );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
@ -351,22 +386,25 @@ describe( 'ValidStateMonitor', function()
|
|||
.update( data, {
|
||||
bar: mkfail( 'bar', [ 'moo', 'cow' ] ) // fail
|
||||
} )
|
||||
.on( 'failure', function( failed )
|
||||
.then( sut =>
|
||||
{
|
||||
expect( failed )
|
||||
.to.deep.equal( {
|
||||
foo: fail_foo,
|
||||
} );
|
||||
} )
|
||||
.on( 'fix', function( fixed )
|
||||
{
|
||||
expect( fixed )
|
||||
.to.deep.equal( { bar: [ 'baz', 'quux' ] } );
|
||||
done();
|
||||
} )
|
||||
.update( data, {
|
||||
foo: fail_foo, // fail
|
||||
// fixes bar
|
||||
return sut.on( 'failure', function( failed )
|
||||
{
|
||||
expect( failed )
|
||||
.to.deep.equal( {
|
||||
foo: fail_foo,
|
||||
} );
|
||||
} )
|
||||
.on( 'fix', function( fixed )
|
||||
{
|
||||
expect( fixed )
|
||||
.to.deep.equal( { bar: [ 'baz', 'quux' ] } );
|
||||
done();
|
||||
} )
|
||||
.update( data, {
|
||||
foo: fail_foo, // fail
|
||||
// fixes bar
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
@ -387,11 +425,14 @@ describe( 'ValidStateMonitor', function()
|
|||
{
|
||||
var fail = mkfail( 'foo', [ 'fail' ] );
|
||||
|
||||
expect(
|
||||
return expect(
|
||||
Sut()
|
||||
.update( {}, { foo: fail } )
|
||||
.getFailures()
|
||||
).to.deep.equal( { foo: fail } );
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.getFailures()
|
||||
} )
|
||||
).to.eventually.deep.equal( { foo: fail } );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
@ -407,11 +448,14 @@ describe( 'ValidStateMonitor', function()
|
|||
|
||||
it( 'is true when failures exist', function()
|
||||
{
|
||||
expect(
|
||||
return expect(
|
||||
Sut()
|
||||
.update( {}, { foo: mkfail( 'foo', [ 'bar' ] ) } )
|
||||
.hasFailures()
|
||||
).to.be.true;
|
||||
.then( sut =>
|
||||
{
|
||||
return sut.hasFailures();
|
||||
} )
|
||||
).to.eventually.be.true;
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
|
Loading…
Reference in New Issue