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