UNPKG

espend-rest

Version:

A RESTful API for submitting payments and monitoring accounts on the eSpend network.

1,118 lines (989 loc) 37.5 kB
var supertest = require('supertest'); var _app = require('../server/express_app'); var app = supertest(_app); var assert = require('assert'); var ws = require('ws'); var route = new (require('events').EventEmitter); var fixtures = require('./fixtures')._payments; var RL = require('espend-lib'); var remote = require('../api/lib/remote'); var testutils = { }; // check if obj has keys testutils.hasKeys = function(obj,keys) { var list = Object.keys(obj); var hasAllKeys = true; var missing = {}; keys.forEach(function(key) { if (list.indexOf(key) == -1) { hasAllKeys = false missing[key] = true; } }) return { hasAllKeys : hasAllKeys, missing : missing } } // used to mark the orderings and count of incoming rippled testutils.orderlist = function(list) { // list = [{command:<command>}, ... ] var _list = list; var idx = 0; this.isMock = true; this.create = function(list) { _list = list; idx = 0 } this.mark = function(command) { if ((_list[idx]) && (_list[idx].command === command)) { idx++ } else { throw new Error("out of order rippled command",command) } } this.test = function() { if (this.isMock) return (idx === _list.length) else return true } this.reset = function() { _list = [] idx = 0; } }; var orderlist = new testutils.orderlist; /** * Payment tests * This file, _payment-test.js describes tests in a different format from other other tests * * If you consider making changes to a test in this file, consider moving the tests over * to payment-test.js and adopting the structure we have for the other tests * * New tests should not be added in the structure laid out here, but in the structure we * use in the other test files. */ suite('payments', function() { var rippled; suiteSetup(function(done) { var self = this; self.remote = remote; rippled = new ws.Server({port: 5150}); route.on('ping', fixtures.ping); route.on('subscribe', fixtures.subscribe); route.on('response', fixtures.response); route.on('server_info',fixtures.server_info); route.on('account_info', fixtures.account_info); route.on('ripple_path_find',fixtures.ripple_path_find); route.on('account_lines', fixtures.account_lines); route.on('submit',fixtures.submit); route.on('tx', fixtures.tx); rippled.on('connection', fixtures.connection.bind({route:route})); self.remote.once('connect', function() { self.remote.getServer().once('ledger_closed', function() { // proceed to the tests, api is ready done(); }); self.remote.getServer().emit('message', fixtures.sample_ledger); }); self.remote._servers = [ ]; self.remote.addServer('ws://localhost:5150'); self.remote.connect(); }); suiteTeardown(function(done) { var self = this; self.remote.once('disconnect', function() { rippled.close(); done() }); self.remote.disconnect(); }); var store = {}; test('Pathfinding:XEC', function(done) { // genesis initially gives Alice 429 XEC orderlist.create([{command:'ripple_path_find'}]); var incoming = function(data,ws) { delete data.id; assert.deepEqual(data, { command: 'ripple_path_find', source_account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', destination_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', destination_amount: '429000000' }); orderlist.mark('ripple_path_find'); }; route.once('ripple_path_find',incoming); app.get('/v1/accounts/'+fixtures.accounts.genesis.address+'/payments/paths/'+fixtures.accounts.alice.address+'/429+XEC') .end(function(err, resp) { assert.strictEqual(resp.body.success, true); var keyresp = testutils.hasKeys(resp.body, ['payments','success']); assert.equal(keyresp.hasAllKeys,true); store.paymentGenesisToAlice = { "secret": fixtures.accounts.genesis.secret, "client_resource_id": "foobar24", "payment": resp.body.payments[0] }; assert.equal(orderlist.test(),true); orderlist.reset(); done(); }) }); test('Posting XEC from genesis to alice',function(done) { var _subscribe = function(data,ws) { delete data.id; assert.deepEqual(data,{ command: 'subscribe', accounts: [ 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh' ] }); orderlist.mark('subscribe'); }; var _accountinfo = function(data,ws) { delete data.id; assert.deepEqual(data, { command: 'account_info', account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh' }); orderlist.mark('account_info'); }; var _submit = function(data,ws) { delete data.id; var so = new RL.SerializedObject(data.tx_blob).to_json(); delete so.TxnSignature; // sigs won't match ever assert.deepEqual(so, { TransactionType: 'Payment', Flags: 2147483648, Sequence: 1, LastLedgerSequence: 8804619, Amount: '429000000', Fee: '12', SigningPubKey: '0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020', Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Destination: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U' }); orderlist.mark('submit'); }; orderlist.create([ {command:'subscribe'}, {command:'account_info'}, {command:'submit'} ]); route.once('subscribe',_subscribe); route.once('account_info',_accountinfo); route.once('submit',_submit); // actually post a XEC payment of 429 from genesis to alice app.post('/v1/accounts/' + fixtures.accounts.genesis.address + '/payments') .send(store.paymentGenesisToAlice) .expect(function(resp) { assert.strictEqual(resp.body.success, true); var keys = Object.keys(fixtures.nominal_xrp_post_response); assert.equal(testutils.hasKeys(resp.body, keys).hasAllKeys,true); assert.equal(orderlist.test(),true); orderlist.reset(); }) .end(done); }); test('check amount alice has',function(done) { // we check that alice has 429 XEC orderlist.create([ {command:'account_info'}, {command:'account_lines'} ]); var _account_info = function(data,ws) { delete data.id; assert.deepEqual(data, { command: 'account_info', account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', ledger_index: 'validated' }); orderlist.mark('account_info'); }; var _account_lines = function(data,ws) { delete data.id; assert.deepEqual(data, { command: 'account_lines', account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', ledger_index: 'validated', limit: 200 }); orderlist.mark('account_lines'); }; route.once('account_info',_account_info); route.once('account_lines',_account_lines); app.get('/v1/accounts/'+fixtures.accounts.alice.address+'/balances') .end(function(err, resp) { assert.equal(resp.body.balances[0].value,429); assert.equal(orderlist.test(),true); orderlist.reset(); done() }); }); test('Pathfinding: from alice to bob XEC',function(done) { // Now alice gives bob 1 drop XEC orderlist.create([ {command:'ripple_path_find'}, {command:'account_info'} ]); var _ripple_path_find = function(data,ws) { orderlist.mark('ripple_path_find'); delete data.id; assert.deepEqual(data, { command: 'ripple_path_find', source_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', destination_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_amount: '1' }); }; var _account_info = function(data,ws) { orderlist.mark('account_info') delete data.id assert.deepEqual(data, { command: 'account_info', account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U' }); }; route.once('ripple_path_find', _ripple_path_find); route.once('account_info', _account_info); app.get('/v1/accounts/'+fixtures.accounts.alice.address+'/payments/paths/'+fixtures.accounts.bob.address+'/0.000001+XEC') .end(function(err, resp) { assert.strictEqual(resp.body.success, true); var keyresp = testutils.hasKeys(resp.body, ['payments','success']); assert.equal(keyresp.hasAllKeys,true); store.paymentAliceToBob = { "secret": fixtures.accounts.alice.secret, "client_resource_id": "foobar25", "payment": resp.body.payments[0] }; assert.equal(orderlist.test(),true); orderlist.reset(); done(); }); }); test('discover the reserve_base_xrp', function(done) { var _server_info = function(data,ws) { orderlist.mark('server_info'); delete data.id; assert.deepEqual(data, { command: 'server_info' }); }; route.once('server_info', _server_info); orderlist.create([{command:'server_info'}]); app.get('/v1/server') .end(function(err, resp) { store.reserve_base_xrp = resp.body.rippled_server_status.validated_ledger.reserve_base_xrp; assert.equal(orderlist.test(),true); orderlist.reset(); done(); }); }); test('Pathfinding: from alice to bob XEC',function(done) { // Now alice gives bob exactly the reserve_base_xrp XEC orderlist.create([ {command:'ripple_path_find'}, {command:'account_info'} ]); var _ripple_path_find = function(data,ws) { orderlist.mark('ripple_path_find'); delete data.id; assert.deepEqual(data, { command: 'ripple_path_find', source_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', destination_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_amount: (store.reserve_base_xrp*1000000).toString() }); }; var _account_info = function(data,ws) { orderlist.mark('account_info'); delete data.id; assert.deepEqual(data, { command: 'account_info', account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U' }) }; route.once('ripple_path_find',_ripple_path_find); route.once('account_info',_account_info); app.get('/v1/accounts/'+fixtures.accounts.alice.address+'/payments/paths/'+fixtures.accounts.bob.address+'/'+store.reserve_base_xrp+'+XEC') .end(function(err, resp) { assert.strictEqual(resp.body.success, true); var keyresp = testutils.hasKeys(resp.body, ['payments','success']); assert.equal(keyresp.hasAllKeys,true); store.paymentAliceToBob = { "secret": fixtures.accounts.alice.secret, "client_resource_id": "foobar26", "payment": resp.body.payments[0] }; assert.equal(orderlist.test(),true); orderlist.reset(); done(); }); }); test('send bob reserve_base_xrp XEC from Alice to bob', function(done) { // sending bob reserve_base_xrp XEC from alice orderlist.create([{command:'submit'}]) var _submit = function(data,ws) { var so = new RL.SerializedObject(data.tx_blob).to_json(); orderlist.mark('submit'); delete so.TxnSignature; assert.deepEqual(so,{ TransactionType: 'Payment', Flags: 2147483648, Sequence: 1, LastLedgerSequence: 8804619, Amount: (store.reserve_base_xrp*1000000).toString(), Fee: '12', SigningPubKey: '022E3308DCB75B17BEF734CE342AC40FF7FDF55E3FEA3593EE8301A70C532BB5BB', Account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', Destination: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5' }); }; route.once('submit',_submit); app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentAliceToBob) .expect(function(resp) { assert.deepEqual(resp.body, { success: true, client_resource_id: 'foobar26', status_url: 'http://127.0.0.1:5990/v1/accounts/'+fixtures.accounts.alice.address+'/payments/foobar26' }); store.status_url = '/v1/accounts/'+fixtures.accounts.alice.address+'/payments/foobar26'; assert.equal(orderlist.test(),true); orderlist.reset(); }) .end(done); }); // confirm payment via client resource ID test('check status url of the reserve_base_xrp transfer from alice to bob', function(done) { orderlist.create([{command:'tx'}]) var _tx = function(data,ws) { delete data.id; delete data.transaction; assert.deepEqual(data, { command: 'tx', binary: true }); orderlist.mark('tx'); }; route.once('tx',_tx); app.get(store.status_url) .expect(function(resp) { assert.equal(resp.status,200); assert.equal(resp.body.success,true); var payment = resp.body.payment; var statusPayment = { source_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', source_tag: '', source_amount: { value: '200', currency: 'XEC', counterparty: '' }, source_slippage: '0', destination_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_tag: '', destination_amount: { value: '200', currency: 'XEC', counterparty: '' }, invoice_id: '', paths: '[]', no_direct_ripple: false, partial_payment: false, direction: 'outgoing', timestamp: '', fee: '0.000012', source_balance_changes: [], destination_balance_changes: [] }; store.hash = resp.body.hash; var keys = Object.keys(statusPayment); for (var i = 0; i < keys.length; i++) { var key = keys[i]; assert.deepEqual(payment[key], statusPayment[key]); } assert.equal(resp.body.hash, '8EA3CF4D854669007058EB45E9860611CC24FEB655895E418A5C8BC5EA901D01'); assert.equal(resp.body.ledger, 'undefined'); assert.equal(resp.body.state, 'failed'); assert.equal(orderlist.test(),true); orderlist.reset(); }) .end(done); }); test('confirm payment via transaction hash', function(done) { orderlist.create([{command:'tx'}]); var _tx = function(data,ws) { orderlist.mark('tx'); }; route.once('tx',_tx) app.get('/v1/accounts/'+fixtures.accounts.alice.address+'/payments/'+store.hash) .expect(function(resp) { assert.equal(resp.status,200); assert.equal(resp.body.success,true); var payment = resp.body.payment; var statusPayment = { source_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', source_tag: '', source_amount: { value: '200', currency: 'XEC', counterparty: '' }, source_slippage: '0', destination_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_tag: '', destination_amount: { value: '200', currency: 'XEC', counterparty: '' }, invoice_id: '', paths: '[]', no_direct_ripple: false, partial_payment: false, direction: 'outgoing', timestamp: '', fee: '0.000012', source_balance_changes: [], destination_balance_changes: [] }; var keys = Object.keys(statusPayment); for (var i = 0; i < keys.length; i++) { var key = keys[i]; assert.deepEqual(payment[key], statusPayment[key]); }; assert.equal(resp.body.hash, '8EA3CF4D854669007058EB45E9860611CC24FEB655895E418A5C8BC5EA901D01'); assert.equal(resp.body.ledger, 'undefined'); assert.equal(resp.body.state, 'failed'); assert.equal(orderlist.test(),true); orderlist.reset(); }) .end(done); }); test('check amount bob has',function(done) { orderlist.create([ {command:'account_info'}, {command:'account_lines'} ]); var _account_info = function(data,ws) { delete data.id; assert.deepEqual(data, { command: 'account_info', account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', ledger_index: 'validated' }); orderlist.mark('account_info'); }; var _account_lines = function(data,ws) { delete data.id; assert.deepEqual(data, { command: 'account_lines', account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', ledger_index: 'validated', limit: 200 }); orderlist.mark('account_lines'); }; route.once('account_info', _account_info); route.once('account_lines',_account_lines); app.get('/v1/accounts/'+fixtures.accounts.bob.address+'/balances') .end(function(err, resp) { var balance = resp.body.balances[0]; // change all instances of 200 with reserve base xrp assert.equal(balance.value,'200'); store.bob_balance = balance.value; assert.equal(orderlist.test(),true); orderlist.reset(); done(); }); }); // bob should try to send all money back to alice test('try to send all of bobs money to alice below reserve', function(done) { orderlist.create([ {command:'ripple_path_find'}, {command:'account_info'} ]); var _ripple_path_find = function(data,ws) { orderlist.mark('ripple_path_find'); delete data.id; assert.deepEqual(data,{ command: 'ripple_path_find', source_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', destination_amount: '200000000' }); }; var _account_info = function(data,ws) { orderlist.mark('account_info'); delete data.id; assert.deepEqual(data, { command: 'account_info', account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5' }); }; route.once('ripple_path_find',_ripple_path_find); route.once('account_info',_account_info); var sendamount = store.bob_balance; app.get('/v1/accounts/'+fixtures.accounts.bob.address+'/payments/paths/'+fixtures.accounts.alice.address+'/'+sendamount+'+XEC') .end(function(err, resp) { assert.equal(404, resp.status); assert.deepEqual(resp.body, { success: false, error_type: 'invalid_request', error: 'restNOT_FOUND', message: 'No paths found. Please ensure that the source_account has sufficient funds to execute the payment. If it does there may be insufficient liquidity in the network to execute this payment right now' }); assert.equal(orderlist.test(),true); orderlist.reset(); done(); }); }); // TODO: bob should try to send all money back to alice test.skip('try to send 95% of bobs money to alice below reserve', function(done) { var sendamount = store.bob_balance * 0.95; app.get('/v1/accounts/'+fixtures.accounts.bob.address+'/payments/paths/'+fixtures.accounts.alice.address+'/'+sendamount+'+XEC') .end(function(err, resp) { assert.equal(404, resp.status); assert.deepEqual(resp.body, { success: false, error_type: 'invalid_request', error: 'No paths found', message: 'Please ensure that the source_account has sufficient funds to execute the payment. If it does there may be insufficient liquidity in the network to execute this payment right now' }); done(); }); }); // have alice send bob 10 USD/alice test('alice sends bob 10USD/alice without trust', function(done) { orderlist.create([ {command:'ripple_path_find'} ]); var _ripple_path_find = function(data,ws) { orderlist.mark('ripple_path_find'); delete data.id; assert.deepEqual(data,{ command: 'ripple_path_find', source_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', destination_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_amount: { value: '10', currency: 'USD', issuer: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U' } }); }; route.once('ripple_path_find',_ripple_path_find); app.get('/v1/accounts/'+fixtures.accounts.alice.address+'/payments/paths/'+fixtures.accounts.bob.address+'/10+USD+'+fixtures.accounts.alice.address) .expect(function(resp) { assert.deepEqual(resp.body, { success: false, error_type: 'invalid_request', error: 'restNOT_FOUND', message: 'No paths found. The destination_account does not accept USD, they only accept: XEC' }); assert.equal(orderlist.test(),true); orderlist.reset(); }) .end(done); }); test.skip('grant a trustline of 10 usd towards alice', function(done) { orderlist.create([ {command:'subscribe'}, {command:'account_info'}, {command:'submit'} ]); var _subscribe = function(data,ws) { orderlist.mark('subscribe'); delete data.id; assert.deepEqual(data, { command: 'subscribe', accounts: [ 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5' ] }); }; var _account_info = function(data,ws) { delete data.id; orderlist.mark('account_info'); assert.deepEqual(data, { command: 'account_info', account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5' }); }; var _submit = function(data,ws) { orderlist.mark('submit'); var so = new RL.SerializedObject(data.tx_blob).to_json(); delete so.TxnSignature; // sigs won't match ever assert.deepEqual(so, { Flags: 2147483648, TransactionType: 'TrustSet', Account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', LimitAmount: { value: '10', currency: 'USD', issuer: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U' }, Sequence: 1, SigningPubKey: '03BC02F6C0F2C50EF5DB02C2C17062B7449B34FBD669A75362E41348C9FAE3DDE1', Fee: '12', LastLedgerSequence: 8804624 }); }; route.once('subscribe',_subscribe); route.once('account_info',_account_info); route.once('submit',_submit); app.post('/v1/accounts/'+fixtures.accounts.bob.address+'/trustlines') .send({ "secret": fixtures.accounts.bob.secret, "trustline": { "limit": "10", "currency": "USD", "counterparty": fixtures.accounts.alice.address, "allows_rippling": false } }) .expect(function(resp) { assert.strictEqual(typeof resp.body.trustline.hash, 'string'); assert.strictEqual(typeof resp.body.trustline.hash, 'string'); delete resp.body.trustline.hash; delete resp.body.trustline.ledger; assert.deepEqual(resp.body,{ "success": true, "trustline": { "account": "rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5", "limit": "10", "currency": "USD", "counterparty": "rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U", "account_allows_rippling": true, "account_trustline_frozen": false, "state": "pending" } }); assert.equal(orderlist.test(),true); orderlist.reset(); }) .end(done); }); // have alice send bob 10 USD/alice test('get path for alice to bob 10USD/alice with trust', function(done) { orderlist.create([ {command:'ripple_path_find'} ]); var _ripple_path_find = function (data,ws) { delete data.id; assert.deepEqual(data, { command: 'ripple_path_find', source_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', destination_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_amount: { value: '10', currency: 'USD', issuer: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U' } }); orderlist.mark('ripple_path_find'); }; route.once('ripple_path_find',_ripple_path_find); app.get('/v1/accounts/'+fixtures.accounts.alice.address+'/payments/paths/'+fixtures.accounts.bob.address+'/10+USD+'+fixtures.accounts.alice.address) .expect(function(resp) { assert.deepEqual(resp.body,{ success: true, payments: [ { source_account: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U', source_tag: '', source_amount: { value: '10', currency: 'USD', counterparty: '' }, source_slippage: '0', destination_account: 'rwmityd4Ss34DBUsRy7Pacv6UA5n7yjfe5', destination_tag: '', destination_amount: { value: '10', currency: 'USD', counterparty: 'rJRLoJSErtNRFnbCyHEUYnRUKNwkVYDM7U' }, invoice_id: '', paths: '[]', partial_payment: false, no_direct_ripple: false } ] }); assert.equal(orderlist.test(),true); orderlist.reset(); }) .end(done); }); /** * The tests below don't test the input for rippled * These should be rewritten in the payments.js class */ test('path find populate carol with missing sum',function(done) { app.get('/v1/accounts/'+fixtures.accounts.genesis.address+'/payments/paths/'+fixtures.accounts.carol.address+'/+XEC') .end(function(err, resp) { assert.equal(resp.status,400); assert.deepEqual(resp.body,{ success: false, error_type: 'invalid_request', error: 'restINVALID_PARAMETER', message: 'Invalid parameter: destination_amount. Must be an amount string in the form value+currency+counterparty' }) done() }) }); test('path find populate carol with missing currency',function(done) { app.get('/v1/accounts/'+fixtures.accounts.genesis.address+'/payments/paths/'+fixtures.accounts.carol.address+'/400') .end(function(err, resp) { assert.equal(resp.status,400); assert.deepEqual(resp.body,{ success: false, error_type: 'invalid_request', error: 'restINVALID_PARAMETER', message: 'Invalid parameter: destination_amount. Must be an amount string in the form value+currency+counterparty' }) done() }) }); test('path find populate carol with all missing endpoint value',function(done) { app.get('/v1/accounts/'+fixtures.accounts.genesis.address+'/payments/paths/'+fixtures.accounts.carol.address+'/') .expect(function(resp) { assert.equal(resp.status,404); }) .end(done); }); test('path find populate carol with 400',function(done) { app.get('/v1/accounts/'+fixtures.accounts.genesis.address+'/payments/paths/'+fixtures.accounts.carol.address+'/400+XEC') .end(function(err, resp) { store.paymentGenesisToCarol = { "secret": fixtures.accounts.genesis.secret, "client_resource_id": "asdfg", "payment": resp.body.payments[0] }; done(); }) }); test('Posting XEC from genesis to carol',function(done) { app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentGenesisToCarol) .end(function(err,resp) { done(); }) }); // miss the client resource id test('path find populate dan with 600',function(done) { app.get('/v1/accounts/'+fixtures.accounts.genesis.address+'/payments/paths/'+fixtures.accounts.dan.address+'/600+XEC') .end(function(err, resp) { store.paymentGenesisToDan = { "secret": fixtures.accounts.genesis.secret, "payment": resp.body.payments[0] }; done(); }) }); test('Posting XEC from genesis to dan with missing client resource id',function(done) { app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentGenesisToDan) .end(function(err,resp) { assert.deepEqual(resp.body,{ success: false, error_type: 'invalid_request', error: 'restINVALID_PARAMETER', message: 'Missing parameter: client_resource_id. All payments must be submitted with a client_resource_id to prevent duplicate payments' }) done() }) }); test('Posting XEC from genesis to dan with empty client resource id',function(done) { store.paymentGenesisToDan["client_resource_id"] = ""; app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentGenesisToDan) .end(function(err,resp) { assert.deepEqual(resp.body, { success: false, error_type: 'invalid_request', error: 'restINVALID_PARAMETER', message: 'Missing parameter: client_resource_id. All payments must be submitted with a client_resource_id to prevent duplicate payments' }) done() }) }); test('Posting XEC from genesis to dan with valid client resource id',function(done) { store.paymentGenesisToDan["client_resource_id"] = "qwerty"; app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentGenesisToDan) .end(function(err,resp) { assert.deepEqual(resp.body, { success: true, client_resource_id: 'qwerty', status_url: 'http://127.0.0.1:5990/v1/accounts/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh/payments/qwerty' }) done() }) }); test('Double posting XEC from genesis to dan with valid client resource id',function(done) { store.paymentGenesisToDan["client_resource_id"] = "qwerty"; app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentGenesisToDan) .expect(function(resp,err) { assert.equal(resp.status, 500); assert.deepEqual(resp.body, { "success": false, "error_type":"server", "error": "restDUPLICATE_TRANSACTION", "message":"Duplicate Transaction. A record already exists in the database for a transaction of this type with the same client_resource_id. If this was not an accidental resubmission please submit the transaction again with a unique client_resource_id" }) }) .end(done); }); test.skip('dan grants a trustline of 10 usd towards carol but uses carols address in the accounts setting', function(done) { // mocha is NOT overriding the timeout contrary to documentation this.timeout(1000); app.post('/v1/accounts/'+fixtures.accounts.carol.address+'/trustlines') .send({ "secret": fixtures.accounts.dan.secret, "trustline": { "limit": "10", "currency": "USD", "counterparty": fixtures.accounts.carol.address, "allows_rippling": false } }) .expect(function(resp) { assert.deepEqual(resp.body, { success: false, error_type: 'transaction', error: 'Invalid secret' }); }) .end(done); }); test.skip('dan grants a trustline of 10 usd towards carol and uses correct address in the accounts setting but no secret', function(done) { app.post('/v1/accounts/'+fixtures.accounts.dan.address+'/trustlines') .send({ "secret": '', "trustline": { "limit": "10", "currency": "USD", "counterparty": fixtures.accounts.carol.address, "allows_rippling": false } }) .expect(function(resp) { assert.equal(resp.status, 400) assert.deepEqual(resp.body,{ success: false, error_type: 'invalid_request', error: 'restINVALID_PARAMETER', message: 'Parameter missing: secret' }) }) .end(done); }); test.skip('dan grants a trustline of 10 usd towards carol and uses correct address in the accounts setting but incorrect secret', function(done) { app.post('/v1/accounts/'+fixtures.accounts.dan.address+'/trustlines') .send({ "secret": fixtures.accounts.carol.secret, "trustline": { "limit": "10", "currency": "USD", "counterparty": fixtures.accounts.carol.address, "allows_rippling": false } }) .expect(function(resp) { assert.deepEqual(resp.body, { success: false, error_type: 'transaction', error: 'Invalid secret' }); }) .end(done); }); test.skip('dan grants a trustline of 10 usd towards carol and uses correct address in the accounts setting', function(done) { app.post('/v1/accounts/'+fixtures.accounts.dan.address+'/trustlines') .send({ "secret": fixtures.accounts.dan.secret, "trustline": { "limit": "10", "currency": "USD", "counterparty": fixtures.accounts.carol.address, "allows_rippling": false } }) .expect(function(resp) { assert.equal(resp.status,201); assert.strictEqual(typeof resp.body.hash, 'string'); assert.strictEqual(typeof resp.body.ledger, 'string'); delete resp.body.hash; delete resp.body.ledger; assert.deepEqual(resp.body,{ "success": true, "trustline": { "account": "rsE6ZLDkXhSvfJHvSqFPhdazsoMgCEC52V", "limit": "10", "currency": "USD", "counterparty": "r3YHFNkQRJDPc9aCkRojPLwKVwok3ihgBJ", "account_allows_rippling": true, "account_trustline_frozen": false }, "state": "pending" }); }) .end(done); }); test.skip('dan grants an additional trustline of 10 usd towards carol and uses correct address in the accounts setting', function(done) { app.post('/v1/accounts/'+fixtures.accounts.dan.address+'/trustlines') .send({ "secret": fixtures.accounts.dan.secret, "trustline": { "limit": "10", "currency": "USD", "counterparty": fixtures.accounts.carol.address, "allows_rippling": false } }) .expect(function(resp) { assert.equal(resp.status,201); assert.strictEqual(typeof resp.body.hash, 'string'); assert.strictEqual(typeof resp.body.ledger, 'string'); delete resp.body.hash; delete resp.body.ledger; assert.deepEqual(resp.body, { "success": true, "trustline": { "account": "rsE6ZLDkXhSvfJHvSqFPhdazsoMgCEC52V", "limit": "10", "currency": "USD", "counterparty": "r3YHFNkQRJDPc9aCkRojPLwKVwok3ihgBJ", "account_allows_rippling": true, "account_trustline_frozen": false }, "state": "pending" }); }) .end(done); }); test('get path for carol to dan 10USD/carol with trust', function(done) { app.get('/v1/accounts/'+fixtures.accounts.carol.address+'/payments/paths/'+fixtures.accounts.dan.address+'/10+USD+'+fixtures.accounts.carol.address) .end(function(err, resp) { store.paymentCarolToDan = { secret: 'asdfkje', client_resource_id : 'abc', payment: resp.body.payments[0] } done() }) }); test.skip('Posting 10USD from carol to dan with valid client resource id but incorrect secret',function(done) { app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentCarolToDan) .expect(function(resp) { assert.deepEqual(resp.body, { success: false, error_type: 'transaction', error: 'Invalid secret' }); }) .end(done); }); test('Posting 10USD from carol to dan with valid client resource id and correct secret but missing fields on payment object',function(done) { store.paymentCarolToDan.secret = fixtures.accounts.carol.secret; store.value = store.paymentCarolToDan.payment.destination_amount.value; delete store.paymentCarolToDan.payment.destination_amount.value; app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentCarolToDan) .expect(function(resp,err) { assert.equal(resp.status,400); assert.deepEqual(resp.body, { success: false, error_type: 'invalid_request', error: 'restINVALID_PARAMETER', message: 'Invalid parameter: destination_amount. Must be a valid Amount object' }); }) .end(done); }); test('Posting 10USD from carol to dan with valid client resource id and correct secret',function(done) { store.paymentCarolToDan.payment.destination_amount.value = store.value; store.paymentCarolToDan.secret = fixtures.accounts.carol.secret; store.paymentCarolToDan.client_resource_id = 'abc'; app.post('/v1/accounts/' + fixtures.accounts.alice.address + '/payments') .send(store.paymentCarolToDan) .expect(function(resp,err) { assert.equal(resp.status, 200); assert.deepEqual(resp.body,{ success: true, client_resource_id: 'abc', status_url: 'http://127.0.0.1:5990/v1/accounts/r3YHFNkQRJDPc9aCkRojPLwKVwok3ihgBJ/payments/abc' }); }) .end(done); }); });