futoin-xferengine
Version:
Neutral clustered multi-currency transaction engine with limits
527 lines (472 loc) • 22.3 kB
JavaScript
;
const expect = require( 'chai' ).expect;
const moment = require( 'moment' );
const Executor = require( 'futoin-executor/Executor' );
const SpecTools = require( 'futoin-invoker/SpecTools' );
module.exports = function( describe, it, vars ) {
let as;
let ccm;
let executor;
beforeEach( 'common', function() {
ccm = vars.ccm;
as = vars.as;
executor = vars.executor;
} );
describe( 'PeerComm', function() {
const LimitsFace = require( '../LimitsFace' );
const LimitsService = require( '../LimitsService' );
const InfoFace = require( '../Currency/InfoFace' );
const InfoService = require( '../Currency/InfoService' );
const AccountsFace = require( '../AccountsFace' );
const AccountsService = require( '../AccountsService' );
const DepositFace = require( '../DepositFace' );
const DepositService = require( '../DepositService' );
const WithdrawFace = require( '../WithdrawFace' );
const WithdrawService = require( '../WithdrawService' );
const PaymentFace = require( '../PaymentFace' );
const PaymentService = require( '../PaymentService' );
const PeerFace = require( '../PeerFace' );
const PeerService = require( '../PeerService' );
const XferTools = require( '../XferTools' );
let system_account;
let peer_external;
let source_account;
let sink_account;
let source_transit;
let sink_transit;
const checkBalance = ( as, account, balance ) => {
ccm.iface( 'xfer.accounts' ).getAccount( as, account );
as.add( ( as, info ) => expect( info.balance ).to.equal( balance ) );
};
beforeEach( 'peerxfer', function() {
as.add(
( as ) => {
InfoService.register( as, executor );
InfoFace.register( as, ccm, 'currency.info', executor );
LimitsService.register( as, executor );
LimitsFace.register( as, ccm, 'xfer.limits', executor );
AccountsService.register( as, executor );
AccountsFace.register( as, ccm, 'xfer.accounts', executor );
DepositService.register( as, executor );
DepositFace.register( as, ccm, 'xfer.deposits', executor );
WithdrawService.register( as, executor );
WithdrawFace.register( as, ccm, 'xfer.withdrawals', executor );
PaymentService.register( as, executor );
PaymentFace.register( as, ccm, 'xfer.payments', executor );
PeerService.register( as, executor );
PeerFace.register( as, ccm, 'xfer.peer1', executor, 'peer2:pwd' );
const basvc = vars.secprov._auth_svc;
basvc.addUser( 'peer1', 'pwd', null, true );
basvc._user_ids[ 1 ].info.global_id = 'peer1';
basvc.addUser( 'peer2', 'pwd', null, true );
basvc._user_ids[ 2 ].info.global_id = 'peer2';
ccm.registerOnDemand(
DepositFace.IFACE_NAME,
'mock',
( as, ccm, alias, api ) => {
DepositFace.register(
as,
ccm,
alias,
executor
);
}
);
ccm.registerOnDemand(
PeerFace.IFACE_NAME,
'mock',
( as, ccm, alias, api ) => {
PeerFace.register(
as,
ccm,
alias,
executor,
api.credentials
);
}
);
ccm.registerOnDemand(
WithdrawFace.IFACE_NAME,
'mock',
( as, ccm, alias, api ) => {
WithdrawFace.register(
as,
ccm,
alias,
executor
);
}
);
},
( as, err ) => {
console.log( err );
console.log( as.state.error_info );
console.log( as.state.last_exception );
}
);
} );
it ( 'should pair peer', function( done ) {
as.add(
( as ) => {
as.add( ( as ) => as.state.test_name = 'Adding limits' );
const xferlim = ccm.iface( 'xfer.limits' );
xferlim.addLimitGroup( as, 'PeerTest' );
xferlim.setLimits( as, 'PeerTest', 'Payments', 'I:EUR', {
outbound_daily_amt : "1000.00",
outbound_daily_cnt : 1000,
inbound_daily_amt : "1000.00",
inbound_daily_cnt : 1000,
outbound_weekly_amt : "1000.00",
outbound_weekly_cnt : 1000,
inbound_weekly_amt : "1000.00",
inbound_weekly_cnt : 1000,
outbound_monthly_amt : "1000.00",
outbound_monthly_cnt : 1000,
inbound_monthly_amt : "1000.00",
inbound_monthly_cnt : 1000,
outbound_min_amt : "1.00",
}, false, false );
xferlim.setLimits( as, 'PeerTest', 'Deposits', 'I:EUR', {
deposit_daily_amt : "100.00",
deposit_daily_cnt : 4,
withdrawal_daily_amt : "100.00",
withdrawal_daily_cnt : 4,
deposit_weekly_amt : "100.00",
deposit_weekly_cnt : 4,
withdrawal_weekly_amt : "100.00",
withdrawal_weekly_cnt : 4,
deposit_monthly_amt : "100.00",
deposit_monthly_cnt : 4,
withdrawal_monthly_amt : "100.00",
withdrawal_monthly_cnt : 4,
deposit_min_amt : "0.10",
withdrawal_min_amt : "0.10",
}, false, false );
xferlim.setLimits( as, 'PeerTest', 'Misc', 'I:EUR', {
message_daily_cnt : 1000,
failure_daily_cnt : 1000,
limithit_daily_cnt : 1000,
message_weekly_cnt : 1000,
failure_weekly_cnt : 1000,
limithit_weekly_cnt : 1000,
message_monthly_cnt : 1000,
failure_monthly_cnt : 1000,
limithit_monthly_cnt : 1000,
}, false, false );
xferlim.addLimitGroup( as, 'PeerUserTest' );
xferlim.setLimits( as, 'PeerUserTest', 'Payments', 'I:EUR', {
outbound_daily_amt : "100.00",
outbound_daily_cnt : 10,
inbound_daily_amt : "100.00",
inbound_daily_cnt : 10,
outbound_weekly_amt : "100.00",
outbound_weekly_cnt : 10,
inbound_weekly_amt : "100.00",
inbound_weekly_cnt : 10,
outbound_monthly_amt : "100.00",
outbound_monthly_cnt : 10,
inbound_monthly_amt : "100.00",
inbound_monthly_cnt : 10,
outbound_min_amt : "1.00",
}, false, false );
xferlim.setLimits( as, 'PeerUserTest', 'Deposits', 'I:EUR', {
deposit_daily_amt : "100.00",
deposit_daily_cnt : 4,
withdrawal_daily_amt : "100.00",
withdrawal_daily_cnt : 4,
deposit_weekly_amt : "100.00",
deposit_weekly_cnt : 4,
withdrawal_weekly_amt : "100.00",
withdrawal_weekly_cnt : 4,
deposit_monthly_amt : "100.00",
deposit_monthly_cnt : 4,
withdrawal_monthly_amt : "100.00",
withdrawal_monthly_cnt : 4,
deposit_min_amt : "0.10",
withdrawal_min_amt : "0.10",
}, {
deposit_daily_amt : "100.00",
deposit_daily_cnt : 2,
withdrawal_daily_amt : "9.00",
withdrawal_daily_cnt : 2,
deposit_weekly_amt : "100.00",
deposit_weekly_cnt : 2,
withdrawal_weekly_amt : "100.00",
withdrawal_weekly_cnt : 2,
deposit_monthly_amt : "100.00",
deposit_monthly_cnt : 2,
withdrawal_monthly_amt : "100.00",
withdrawal_monthly_cnt : 2,
deposit_min_amt : "0.10",
withdrawal_min_amt : "0.10",
}, false );
//--
const xferacct = ccm.iface( 'xfer.accounts' );
const xt = new XferTools( ccm, 'Payments' );
//SpecTools.on('error', function() { console.log(arguments); } );
//---
as.add( ( as ) => as.state.test_name = 'Regular accounts on "Peer1"' );
xferacct.addAccountHolder( as, 'Peer1 Holder', 'PeerTest', true, true, {}, {} );
as.add( ( as, holder ) => {
xferacct.addAccount(
as,
holder,
'Regular',
'I:EUR',
'Source',
true
);
as.add( ( as, id ) => source_account = id );
xferacct.addAccount(
as,
holder,
'Regular',
'I:EUR',
'Sink',
true
);
as.add( ( as, id ) => sink_account = id );
xferacct.addAccount(
as,
holder,
'System',
'I:EUR',
'System',
true
);
as.add( ( as, id ) => system_account = id );
} );
//---
as.add( ( as ) => as.state.test_name = 'External accounts on peers' );
xferacct.addAccountHolder(
as, 'peer1', 'PeerTest', true, true, {},
{
api: {
'futoin.xfer.deposit': {
flavour: 'mock',
},
'futoin.xfer.withdraw': {
flavour: 'mock',
},
'futoin.xfer.peer': {
flavour: 'mock',
credentials: 'peer2:pwd',
},
},
}
);
as.add( ( as, holder ) => {
let first_id;
xt.pairPeer( as, holder, 'I:EUR' );
as.add( ( as, id ) => first_id = id );
xt.pairPeer( as, holder, 'I:USD' );
xt.pairPeer( as, holder, 'I:EUR' );
as.add( ( as, id ) => {
expect( id ).to.equal( first_id );
peer_external = id;
} );
xferacct.getAccountHolderExt( as, 'peer2' );
as.add( ( as, info ) => {
xferacct.updateAccountHolder( as, info.id, 'PeerTest' );
} );
} );
//---
as.add( ( as ) => as.state.test_name = 'Transit accounts on "Peer2"' );
xferacct.addAccountHolder( as, 'Peer2 Transit', 'PeerUserTest', true, true, {}, {} );
as.add( ( as, holder ) => {
xferacct.addAccount(
as,
holder,
'Transit',
'I:EUR',
'Source',
true,
source_account,
peer_external
);
as.add( ( as, id ) => source_transit = id );
xferacct.addAccount(
as,
holder,
'Transit',
'I:EUR',
'Sink',
true,
sink_account,
peer_external
);
as.add( ( as, id ) => sink_transit = id );
} );
},
( as, err ) => {
console.log( as.state.test_name );
console.log( err );
console.log( as.state.error_info );
done( as.state.last_exception || 'Fail' );
}
);
as.add( ( as ) => done() );
as.execute();
} );
it ( 'should process peer xfers', function( done ) {
this.timeout( 10e3 );
as.add(
( as ) => {
const xferacct = ccm.iface( 'xfer.accounts' );
const deposits = ccm.iface( 'xfer.deposits' );
const withdrawals = ccm.iface( 'xfer.withdrawals' );
const payments = ccm.iface( 'xfer.payments' );
//---
as.add( ( as ) => as.state.test_name = 'Deposit to source' );
payments.onInbound( as,
source_account,
system_account,
'I:EUR',
'12.00',
'T1',
{},
moment.utc().format()
);
checkBalance( as, source_account, '12.00' );
checkBalance( as, system_account, '-12.00' );
//---
as.add( ( as ) => as.state.test_name = 'Deposit source -> sink' );
xferacct.setOverdraft( as, peer_external, 'I:EUR', '12.00' );
deposits.onDeposit( as,
sink_transit,
source_transit,
'I:EUR',
'10.00',
'T2',
{},
moment.utc().format()
);
checkBalance( as, system_account, '-12.00' );
checkBalance( as, source_account, '2.00' );
checkBalance( as, sink_account, '10.00' );
checkBalance( as, sink_transit, '0.00' );
checkBalance( as, source_transit, '0.00' );
//---
as.add( ( as ) => as.state.test_name = 'Inbound source -> system' );
payments.onInbound( as,
system_account,
source_transit,
'I:EUR',
'2.00',
'T3',
{},
moment.utc().format()
);
checkBalance( as, system_account, '-10.00' );
checkBalance( as, source_account, '0.00' );
checkBalance( as, sink_account, '10.00' );
checkBalance( as, sink_transit, '0.00' );
checkBalance( as, source_transit, '0.00' );
//---
as.add( ( as ) => as.state.test_name = 'Deposit system -> sink' );
deposits.onDeposit( as,
sink_transit,
system_account,
'I:EUR',
'2.00',
'T4',
{},
moment.utc().format()
);
checkBalance( as, system_account, '-12.00' );
checkBalance( as, source_account, '0.00' );
checkBalance( as, sink_account, '12.00' );
checkBalance( as, sink_transit, '0.00' );
checkBalance( as, source_transit, '0.00' );
//---
as.add( ( as ) => as.state.test_name = 'Withdraw sink -> system' );
withdrawals.startWithdrawal( as,
sink_transit,
system_account,
'I:EUR',
'2.00',
'T1',
{},
moment.utc().format()
);
as.add( ( as, { wait_user } ) => expect( wait_user ).to.be.false );
checkBalance( as, system_account, '-10.00' );
checkBalance( as, source_account, '0.00' );
checkBalance( as, sink_account, '10.00' );
checkBalance( as, sink_transit, '0.00' );
checkBalance( as, source_transit, '0.00' );
//---
as.add( ( as ) => as.state.test_name = 'Withdraw sink -> source #1' );
withdrawals.startWithdrawal( as,
sink_transit,
source_transit,
'I:EUR',
'10.00',
'T2',
{},
moment.utc().format()
);
as.add( ( as, { xfer_id, wait_user } ) => {
expect( wait_user ).to.be.true;
checkBalance( as, system_account, '-10.00' );
checkBalance( as, source_account, '0.00' );
checkBalance( as, sink_account, '0.00' );
checkBalance( as, sink_transit, '0.00' );
checkBalance( as, source_transit, '0.00' );
as.add( ( as ) => as.state.test_name = 'Withdraw sink -> source #1 (reject)' );
withdrawals.rejectWithdrawal( as,
xfer_id,
sink_transit,
source_transit,
'I:EUR',
'10.00',
moment.utc().format()
);
} );
checkBalance( as, system_account, '-10.00' );
checkBalance( as, source_account, '0.00' );
checkBalance( as, sink_account, '10.00' );
checkBalance( as, sink_transit, '0.00' );
checkBalance( as, source_transit, '0.00' );
//---
as.add( ( as ) => as.state.test_name = 'Withdraw sink -> source #2' );
withdrawals.startWithdrawal( as,
sink_transit,
source_transit,
'I:EUR',
'10.00',
'T3',
{},
moment.utc().format()
);
as.add( ( as, { xfer_id, wait_user } ) => {
expect( wait_user ).to.be.true;
as.state.test_name = 'Withdraw sink -> source #2 (confirm)';
withdrawals.confirmWithdrawal( as,
xfer_id,
sink_transit,
source_transit,
'I:EUR',
'10.00',
moment.utc().format()
);
} );
checkBalance( as, system_account, '-10.00' );
checkBalance( as, source_account, '10.00' );
checkBalance( as, sink_account, '0.00' );
checkBalance( as, sink_transit, '0.00' );
checkBalance( as, source_transit, '0.00' );
//---
},
( as, err ) => {
console.log( as.state.test_name );
console.log( err );
console.log( as.state.error_info );
done( as.state.last_exception || 'Fail' );
}
);
as.add( ( as ) => done() );
as.execute();
} );
} );
};