1
0
Fork 0

RatingService: Improved error handling

This does only a slightly better job than before.
master
Mike Gerwitz 2019-10-28 10:56:13 -04:00
parent a23f2040dd
commit 65e7880c81
2 changed files with 201 additions and 87 deletions

View File

@ -34,6 +34,13 @@ import { UserResponse } from "../request/UserResponse";
type RequestCallback = () => void; type RequestCallback = () => void;
/** Result of rating */
export type RateRequestResult = {
data: RateResult,
initialRatedDate: UnixTimestamp,
lastRatedDate: UnixTimestamp,
};
/** /**
* Handle rating requests * Handle rating requests
@ -93,32 +100,38 @@ export class RatingService
_response: UserResponse, _response: UserResponse,
quote: ServerSideQuote, quote: ServerSideQuote,
cmd: string, cmd: string,
): Promise<void> ): Promise<RateRequestResult>
{ {
// cmd represents a request for a single rater const program = quote.getProgram();
if ( !cmd && this._isQuoteValid( quote ) )
return new Promise<RateRequestResult>( resolve =>
{ {
// send an empty reply (keeps what is currently in the bucket) // cmd represents a request for a single rater
this._server.sendResponse( request, quote, { if ( !cmd && this._isQuoteValid( quote ) )
data: {}, {
}, [] ); // send an empty reply (keeps what is currently in the
// bucket)
this._server.sendResponse( request, quote, {
data: {},
}, [] );
return Promise.resolve(); // XXX: When this class is no longer responsible for
} // sending the response to the server, this below data needs
// to represent the _current_ values, since as it is written
// now, it'll overwrite what is currently in the bucket
return resolve( {
data: { _unavailable_all: '0' },
initialRatedDate: <UnixTimestamp>0,
lastRatedDate: <UnixTimestamp>0,
} );
}
var program = quote.getProgram(); resolve( this._performRating( request, program, quote, cmd ) );
} )
return new Promise( ( resolve, reject ) => .catch( err =>
{ {
try this._sendRatingError( request, quote, program, err );
{ throw err;
this._performRating( request, program, quote, cmd, resolve );
}
catch ( err )
{
this._sendRatingError( request, quote, program, err );
reject( err );
}
} ); } );
} }
@ -155,67 +168,81 @@ export class RatingService
} }
/**
* Perform rating and process result
*
* @param request - user request to satisfy
* @param program - quote program
* @param quote - quote to process
* @param indv - individual supplier to rate (or empty)
*
* @return promise for results of rating
*/
private _performRating( private _performRating(
request: UserRequest, request: UserRequest,
program: Program, program: Program,
quote: ServerSideQuote, quote: ServerSideQuote,
indv: string, indv: string,
c: RequestCallback, ): Promise<RateRequestResult>
)
{ {
var rater = this._rater_manager.byId( program.getId() ); return new Promise<RateRequestResult>( ( resolve, reject ) =>
{
var rater = this._rater_manager.byId( program.getId() );
this._logger.log( this._logger.PRIORITY_INFO, this._logger.log( this._logger.PRIORITY_INFO,
"Performing '%s' rating for quote #%s", "Performing '%s' rating for quote #%s",
quote.getProgramId(), quote.getProgramId(),
quote.getId() quote.getId()
); );
rater.rate( quote, request.getSession(), indv, rater.rate( quote, request.getSession(), indv,
( rate_data: RateResult, actions: ClientActions ) => ( rate_data: RateResult, actions: ClientActions ) =>
{
actions = actions || [];
this.postProcessRaterData(
request, rate_data, actions, program, quote
);
const class_dest = {};
const cleaned = this._cleanRateData(
rate_data,
class_dest
);
// TODO: move me during refactoring
this._dao.saveQuoteClasses(
quote, class_dest, () => {}, () => {}
);
// save all data server-side (important: do after
// post-processing); async
this._saveRatingData( quote, rate_data, indv, function()
{ {
// we're done actions = actions || [];
c();
} );
// no need to wait for the save; send the response this.postProcessRaterData(
this._server.sendResponse( request, quote, { request, rate_data, actions, program, quote
data: cleaned, );
initialRatedDate: quote.getRatedDate(),
lastRatedDate: quote.getLastPremiumDate()
}, actions );
},
( message: string ) =>
{
this._sendRatingError( request, quote, program,
Error( message )
);
c(); const class_dest = {};
}
); const cleaned = this._cleanRateData(
rate_data,
class_dest
);
// TODO: move me during refactoring
this._dao.saveQuoteClasses(
quote, class_dest, () => {}, () => {}
);
const result = {
data: cleaned,
initialRatedDate: quote.getRatedDate(),
lastRatedDate: quote.getLastPremiumDate()
};
// save all data server-side (important: do after
// post-processing); async
this._saveRatingData( quote, rate_data, indv, function()
{
// we're done
resolve( result );
} );
// no need to wait for the save; send the response
this._server.sendResponse( request, quote, result, actions );
},
( message: string ) =>
{
this._sendRatingError( request, quote, program,
Error( message )
);
reject( Error( message ) );
}
);
} );
} }

View File

@ -44,6 +44,31 @@ chai_use( require( 'chai-as-promised' ) );
describe( 'RatingService', () => describe( 'RatingService', () =>
{ {
it( "returns rating results", () =>
{
const {
logger,
server,
raters,
dao,
request,
response,
quote,
stub_rate_data,
} = getStubs();
const sut = new Sut( logger, dao, server, raters );
const expected = {
data: stub_rate_data,
initialRatedDate: quote.getRatedDate(),
lastRatedDate: quote.getLastPremiumDate(),
};
return expect( sut.request( request, response, quote, "" ) )
.to.eventually.deep.equal( expected );
} );
it( "saves rate data to own field", () => it( "saves rate data to own field", () =>
{ {
const { const {
@ -86,17 +111,18 @@ describe( 'RatingService', () =>
} ); } );
it( "rejects with error", () => it( "rejects and responds with error", () =>
{ {
const { const {
logger,
server,
raters,
dao, dao,
request, logger,
response, program,
quote, quote,
rater, rater,
raters,
request,
response,
server,
} = getStubs(); } = getStubs();
const expected_error = new Error( "expected error" ); const expected_error = new Error( "expected error" );
@ -105,8 +131,66 @@ describe( 'RatingService', () =>
const sut = new Sut( logger, dao, server, raters ); const sut = new Sut( logger, dao, server, raters );
let logged = false;
logger.log = function(
priority: number,
_format: string,
qid: QuoteId,
program_id: string,
message: string,
)
{
if ( typeof message === 'string' )
{
expect( priority ).to.equal( logger.PRIORITY_ERROR );
expect( qid ).to.equal( quote.getId() );
expect( program_id ).to.equal( program.getId() );
expect( message ).to.contain( expected_error.message );
logged = true;
}
return logger;
};
return expect( sut.request( request, response, quote, "" ) ) return expect( sut.request( request, response, quote, "" ) )
.to.eventually.rejectedWith( expected_error ); .to.eventually.rejectedWith( expected_error )
.then( () => expect( logged ).to.be.true );
} );
it( "returns error message from rater", () =>
{
const {
dao,
logger,
quote,
rater,
raters,
request,
response,
server,
} = getStubs();
const expected_message = 'expected foo';
const sut = new Sut( logger, dao, server, raters );
rater.rate = (
_quote: ServerSideQuote,
_session: UserSession,
_indv: string,
_success: ( data: RateResult, actions: ClientActions ) => void,
failure: ( message: string ) => void,
) =>
{
failure( expected_message );
return rater;
};
return expect( sut.request( request, response, quote, "" ) )
.to.eventually.rejectedWith( Error, expected_message );
} ); } );
@ -142,7 +226,7 @@ describe( 'RatingService', () =>
} }
}( logger, dao, server, raters ); }( logger, dao, server, raters );
return sut.request( request, response, quote, 'something' ); sut.request( request, response, quote, 'something' );
} ); } );
it( "calls getLastPremiumDate during #_performRating", done => it( "calls getLastPremiumDate during #_performRating", done =>
@ -183,9 +267,8 @@ describe( 'RatingService', () =>
return server; return server;
}; };
return sut.request( request, response, quote, "" ); sut.request( request, response, quote, "" );
} ); } );
} ); } );
} ); } );
@ -211,9 +294,13 @@ function getStubs()
_session: UserSession, _session: UserSession,
_indv: string, _indv: string,
success: ( data: RateResult, actions: ClientActions ) => void, success: ( data: RateResult, actions: ClientActions ) => void,
_failure: ( message: string ) => void,
) )
{ {
success( stub_rate_data, [] ); // force to be async so that the tests resemble how the code
// actually runs
process.nextTick( () => success( stub_rate_data, [] ) );
return this; return this;
} }
}; };
@ -230,7 +317,7 @@ function getStubs()
readonly PRIORITY_INFO: number = 3; readonly PRIORITY_INFO: number = 3;
readonly PRIORITY_SOCKET: number = 4; readonly PRIORITY_SOCKET: number = 4;
log(): this log( _priority: number, ..._args: Array<string|number> ): this
{ {
return this; return this;
} }