1
0
Fork 0

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-2296
master
Mike Gerwitz 2017-01-23 15:47:55 -05:00
parent af7813e605
commit fb3cd11265
2 changed files with 146 additions and 81 deletions

View File

@ -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 );
}
} );

View File

@ -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;
} );
} );
} );