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 * 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 ], var past_fail = past[ name ],
fail = failures[ 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 );
} }
} ); } );

View File

@ -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,10 +178,13 @@ 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 return sut.update( {}, { foo: [ fail2 ] } );
sut } )
.then( () =>
{
return sut
.once( 'fix', function( fixed ) .once( 'fix', function( fixed )
{ {
expect( fixed ) expect( fixed )
@ -192,6 +201,7 @@ describe( 'ValidStateMonitor', function()
); );
} ); } );
} ); } );
} );
describe( 'given data with absence of failure', function() describe( 'given data with absence of failure', function()
@ -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,10 +262,15 @@ describe( 'ValidStateMonitor', function()
called++; called++;
} ) } )
.update( {}, { foo: mkfail( 'foo', [ 'bar' ] ) } ) .update( {}, { foo: mkfail( 'foo', [ 'bar' ] ) } )
.update( {}, {} ); // do not trigger failure event .then( sut =>
{
return sut.update( {}, {} ); // do not trigger failure event
} )
.then( sut =>
{
expect( called ).to.equal( 1 ); expect( called ).to.equal( 1 );
} ); } );
} );
describe( 'given a cause', function() describe( 'given a cause', function()
@ -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,7 +386,9 @@ 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 =>
{
return sut.on( 'failure', function( failed )
{ {
expect( failed ) expect( failed )
.to.deep.equal( { .to.deep.equal( {
@ -370,6 +407,7 @@ describe( 'ValidStateMonitor', function()
} ); } );
} ); } );
} ); } );
} );
describe( '#getFailures', function() describe( '#getFailures', function()
@ -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;
} ); } );
} ); } );
} ); } );