From c9704137b7b538e8dbf31c483bcdcf2dcfd7cd75 Mon Sep 17 00:00:00 2001 From: Ivan Tivonenko Date: Tue, 24 Nov 2015 09:49:41 +0200 Subject: [PATCH] fix handling memos in prepareSettings boost coverage back to 99.88% move connection tests to separate file group test fixtures into namespaces --- docs/index.md | 47 +- src/common/connection.js | 8 +- src/transaction/settings.js | 10 +- test/api-test.js | 529 ++++++------------ test/connection-test.js | 261 +++++++++ test/fixtures/requests/index.js | 59 +- .../prepare-order-cancellation-memos.json | 10 + .../fixtures/requests/prepare-order-sell.json | 9 +- test/fixtures/requests/prepare-settings.json | 9 +- test/fixtures/requests/prepare-trustline.json | 9 +- test/fixtures/responses/index.js | 61 +- .../prepare-order-cancellation-memos.json | 8 + .../responses/prepare-order-sell.json | 16 +- .../prepare-settings-no-instructions.json | 9 +- .../responses/prepare-settings-signed.json | 8 +- test/fixtures/responses/prepare-settings.json | 2 +- .../fixtures/responses/prepare-trustline.json | 2 +- ...offers-1.json => book-offers-usd-xrp.json} | 0 ...offers-2.json => book-offers-xrp-usd.json} | 0 test/fixtures/rippled/index.js | 32 +- test/mock-rippled.js | 29 +- 21 files changed, 649 insertions(+), 469 deletions(-) create mode 100644 test/connection-test.js create mode 100644 test/fixtures/requests/prepare-order-cancellation-memos.json create mode 100644 test/fixtures/responses/prepare-order-cancellation-memos.json rename test/fixtures/rippled/{book-offers-1.json => book-offers-usd-xrp.json} (100%) rename test/fixtures/rippled/{book-offers-2.json => book-offers-xrp-usd.json} (100%) diff --git a/docs/index.md b/docs/index.md index 657770bd49..41dd3efe6a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -348,7 +348,14 @@ ripplingDisabled | boolean | *Optional* If true, payments cannot ripple through "qualityIn": 0.91, "qualityOut": 0.87, "ripplingDisabled": true, - "frozen": false + "frozen": false, + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] } ``` @@ -435,7 +442,14 @@ transferRate | number,null | *Optional* The fee to charge when users transfer t ```json { - "domain": "ripple.com" + "domain": "ripple.com", + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] } ``` @@ -2826,7 +2840,14 @@ const trustline = { "qualityIn": 0.91, "qualityOut": 0.87, "ripplingDisabled": true, - "frozen": false + "frozen": false, + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] }; return api.preparePayment(address, trustline).then(prepared => {/* ... */}); @@ -2835,7 +2856,7 @@ return api.preparePayment(address, trustline).then(prepared => ```json { - "txJSON": "{\"Flags\":2149711872,\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"value\":\"10000\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"QualityIn\":910000000,\"QualityOut\":870000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "txJSON": "{\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"10000\"},\"Flags\":2149711872,\"QualityIn\":910000000,\"QualityOut\":870000000,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "instructions": { "fee": "0.000012", "sequence": 23, @@ -2997,7 +3018,14 @@ instructions | object | The instructions for how to execute the transaction afte ```javascript const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59'; const settings = { - "domain": "ripple.com" + "domain": "ripple.com", + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] }; return api.prepareSettings(address, settings) .then(prepared => {/* ... */}); @@ -3006,7 +3034,14 @@ return api.prepareSettings(address, settings) ```json { - "domain": "ripple.com" + "domain": "ripple.com", + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] } ``` diff --git a/src/common/connection.js b/src/common/connection.js index bfec45aa74..7836c20ff6 100644 --- a/src/common/connection.js +++ b/src/common/connection.js @@ -17,6 +17,10 @@ class Connection extends EventEmitter { super(); this._url = url; this._trace = options.trace; + if (this._trace) { + // for easier unit testing + this._console = console; + } this._proxyURL = options.proxy; this._proxyAuthorization = options.proxyAuthorization; this._authorization = options.authorization; @@ -54,7 +58,7 @@ class Connection extends EventEmitter { _onMessage(message) { let parameters; if (this._trace) { - console.log(message); + this._console.log(message); } try { parameters = this._parseMessage(message); @@ -198,7 +202,7 @@ class Connection extends EventEmitter { _send(message) { if (this._trace) { - console.log(message); + this._console.log(message); } return new Promise((resolve, reject) => { this._ws.send(message, undefined, (error, result) => { diff --git a/src/transaction/settings.js b/src/transaction/settings.js index 0c71284bd8..b4d09c3b35 100644 --- a/src/transaction/settings.js +++ b/src/transaction/settings.js @@ -87,15 +87,17 @@ function createSettingsTransaction(account: string, settings: Settings TransactionType: 'AccountSet', Account: account }; - setTransactionFlags(txJSON, settings); + + if (settings.memos !== undefined) { + txJSON.Memos = _.map(settings.memos, utils.convertMemo); + } + + setTransactionFlags(txJSON, _.omit(settings, 'memos')); setTransactionFields(txJSON, settings); if (txJSON.TransferRate !== undefined) { txJSON.TransferRate = convertTransferRate(txJSON.TransferRate); } - if (settings.memos !== undefined) { - txJSON.Memos = _.map(settings.memos, utils.convertMemo); - } return txJSON; } diff --git a/test/api-test.js b/test/api-test.js index 58fffdf66c..59d53fce43 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -1,7 +1,6 @@ /* eslint-disable max-nested-callbacks */ 'use strict'; const _ = require('lodash'); -const net = require('net'); const assert = require('assert-diff'); const setupAPI = require('./setup-api'); const RippleAPI = require('ripple-api').RippleAPI; @@ -35,314 +34,90 @@ function checkResult(expected, schemaName, response) { return response; } -function createServer() { - return new Promise((resolve, reject) => { - const server = net.createServer(); - server.on('listening', function() { - resolve(server); - }); - server.on('error', function(error) { - reject(error); - }); - server.listen(0, '0.0.0.0'); - }); -} - describe('RippleAPI', function() { const instructions = {maxLedgerVersionOffset: 100}; beforeEach(setupAPI.setup); afterEach(setupAPI.teardown); - describe('Connection', function() { - - it('connection default options', function() { - const connection = new utils.common.Connection('url'); - assert.strictEqual(connection._url, 'url'); - assert(_.isUndefined(connection._proxyURL)); - assert(_.isUndefined(connection._authorization)); - }); - - it('with proxy', function(done) { - createServer().then((server) => { - const port = server.address().port; - const expect = 'CONNECT localhost'; - server.on('connection', (socket) => { - socket.on('data', (data) => { - const got = data.toString('ascii', 0, expect.length); - assert.strictEqual(got, expect); - server.close(); - done(); - }); - }); - - const options = { - proxy: 'ws://localhost:' + port, - authorization: 'authorization', - trustedCertificates: 'something' - }; - const connection = - new utils.common.Connection(this.api.connection._url, options); - connection.connect().catch(done); - connection.connect().catch(done); - }, done); - }); - - it('Multiply disconnect calls', function() { - this.api.disconnect(); - return this.api.disconnect(); - }); - - it('reconnect', function() { - return this.api.connection.reconnect(); - }); - - it('NotConnectedError', function() { - const connection = new utils.common.Connection('url'); - return connection.getLedgerVersion().then(() => { - assert(false, 'Should throw NotConnectedError'); - }).catch(error => { - assert(error instanceof this.api.errors.NotConnectedError); - }); - }); - - it('DisconnectedError', function() { - this.api.connection._send = function() { - this._ws.close(); - }; - return this.api.getServerInfo().then(() => { - assert(false, 'Should throw DisconnectedError'); - }).catch(error => { - assert(error instanceof this.api.errors.DisconnectedError); - }); - }); - - it('TimeoutError', function() { - this.api.connection._send = function() { - return Promise.resolve({}); - }; - const request = {command: 'server_info'}; - return this.api.connection.request(request, 1).then(() => { - assert(false, 'Should throw TimeoutError'); - }).catch(error => { - assert(error instanceof this.api.errors.TimeoutError); - }); - }); - - it('DisconnectedError on send', function() { - this.api.connection._ws.send = function(message, options, callback) { - unused(message, options); - callback({message: 'not connected'}); - }; - return this.api.getServerInfo().then(() => { - assert(false, 'Should throw DisconnectedError'); - }).catch(error => { - assert(error instanceof this.api.errors.DisconnectedError); - assert.strictEqual(error.message, 'not connected'); - }); - }); - - it('ResponseFormatError', function() { - this.api.connection._send = function(message) { - const parsed = JSON.parse(message); - setTimeout(() => { - this._ws.emit('message', JSON.stringify({ - id: parsed.id, - type: 'response', - status: 'unrecognized' - })); - }, 2); - return new Promise(() => {}); - }; - return this.api.getServerInfo().then(() => { - assert(false, 'Should throw ResponseFormatError'); - }).catch(error => { - assert(error instanceof this.api.errors.ResponseFormatError); - }); - }); - - it('reconnect on unexpected close ', function(done) { - this.api.connection.on('connected', () => { - done(); - }); - - setTimeout(() => { - this.api.connection._ws.close(); - }, 1); - }); + it('error inspect', function() { + const error = new this.api.errors.RippleError('mess', {data: 1}); + assert.strictEqual(error.inspect(), '[RippleError(mess, { data: 1 })]'); + }); - it('Multiply connect calls', function() { - return this.api.connect().then(() => { - return this.api.connect(); - }); - }); + describe('preparePayment', function() { - it('hasLedgerVersion', function() { - return this.api.connection.hasLedgerVersion(8819951).then((result) => { - assert(result); - }); + it('normal', function() { + const localInstructions = _.defaults({ + maxFee: '0.000012' + }, instructions); + return this.api.preparePayment( + address, requests.preparePayment.normal, localInstructions).then( + _.partial(checkResult, responses.preparePayment.normal, 'prepare')); }); - it('Cannot connect because no server', function() { - const connection = new utils.common.Connection(); - return connection.connect().then(() => { - assert(false, 'Should throw ConnectionError'); - }).catch(error => { - assert(error instanceof this.api.errors.ConnectionError); - }); + it('preparePayment - min amount xrp', function() { + const localInstructions = _.defaults({ + maxFee: '0.000012' + }, instructions); + return this.api.preparePayment( + address, requests.preparePayment.minAmountXRP, localInstructions).then( + _.partial(checkResult, + responses.preparePayment.minAmountXRP, 'prepare')); }); - it('connect multiserver error', function() { - const options = { - servers: ['wss://server1.com', 'wss://server2.com'] - }; - assert.throws(function() { - const api = new RippleAPI(options); - unused(api); - }, this.api.errors.RippleError); + it('preparePayment - min amount xrp2xrp', function() { + return this.api.preparePayment( + address, requests.preparePayment.minAmount, instructions).then( + _.partial(checkResult, + responses.preparePayment.minAmountXRPXRP, 'prepare')); }); - it('connect throws error', function(done) { - this.api.once('error', (type, info) => { - assert.strictEqual(type, 'type'); - assert.strictEqual(info, 'info'); - done(); - }); - this.api.connection.emit('error', 'type', 'info'); + it('preparePayment - XRP to XRP no partial', function() { + assert.throws(() => { + this.api.preparePayment(address, requests.preparePayment.wrongPartial); + }, /XRP to XRP payments cannot be partial payments/); }); - it('connection emit stream messages', function(done) { - let transactionCount = 0; - let pathFindCount = 0; - this.api.connection.on('transaction', () => { - transactionCount++; - }); - this.api.connection.on('path_find', () => { - pathFindCount++; - }); - this.api.connection.on('1', () => { - assert.strictEqual(transactionCount, 1); - assert.strictEqual(pathFindCount, 1); - done(); - }); - - this.api.connection._onMessage(JSON.stringify({ - type: 'transaction' - })); - this.api.connection._onMessage(JSON.stringify({ - type: 'path_find' - })); - this.api.connection._onMessage(JSON.stringify({ - type: 'response', id: 1 - })); - }); - - it('connection - invalid message id', function(done) { - this.api.on('error', (type, message) => { - assert.strictEqual(type, 'badMessage'); - assert.strictEqual(message, - '{"type":"response","id":"must be integer"}'); - done(); - }); - this.api.connection._onMessage(JSON.stringify({ - type: 'response', id: 'must be integer' - })); + it('preparePayment - address must match payment.source.address', + function() { + assert.throws(() => { + this.api.preparePayment(address, requests.preparePayment.wrongAddress); + }, /address must match payment.source.address/); }); - it('connection - error message', function(done) { - this.api.on('error', (type, message) => { - assert.strictEqual(type, 'slowDown'); - assert.strictEqual(message, 'slow down'); - done(); - }); - this.api.connection._onMessage(JSON.stringify({ - error: 'slowDown', error_message: 'slow down' - })); + it('preparePayment - wrong amount', function() { + assert.throws(() => { + this.api.preparePayment(address, requests.preparePayment.wrongAmount); + }, this.api.errors.ValidationError); }); - it('connection - unrecognized message type', function(done) { - this.api.on('error', (type, message) => { - assert.strictEqual(type, 'badMessage'); - assert.strictEqual(message, '{"type":"unknown"}'); - done(); + it('preparePayment with all options specified', function() { + return this.api.getLedgerVersion().then((ver) => { + const localInstructions = { + maxLedgerVersion: ver + 100, + fee: '0.000012' + }; + return this.api.preparePayment( + address, requests.preparePayment.allOptions, localInstructions).then( + _.partial(checkResult, + responses.preparePayment.allOptions, 'prepare')); }); - - this.api.connection._onMessage(JSON.stringify({type: 'unknown'})); }); - }); - - it('error inspect', function() { - const error = new this.api.errors.RippleError('mess', {data: 1}); - assert.strictEqual(error.inspect(), '[RippleError(mess, { data: 1 })]'); - }); - - it('preparePayment', function() { - const localInstructions = _.defaults({ - maxFee: '0.000012' - }, instructions); - return this.api.preparePayment( - address, requests.preparePayment, localInstructions).then( - _.partial(checkResult, responses.preparePayment.normal, 'prepare')); - }); - - it('preparePayment - min amount xrp', function() { - const localInstructions = _.defaults({ - maxFee: '0.000012' - }, instructions); - return this.api.preparePayment( - address, requests.preparePaymentMinAmountXRP, localInstructions).then( - _.partial(checkResult, responses.preparePayment.minAmountXRP, 'prepare')); - }); - - it('preparePayment - min amount xrp2xrp', function() { - return this.api.preparePayment( - address, requests.preparePaymentMinAmount, instructions).then( - _.partial(checkResult, - responses.preparePayment.minAmountXRPXRP, 'prepare')); - }); - - it('preparePayment - XRP to XRP no partial', function() { - assert.throws(() => { - this.api.preparePayment(address, requests.preparePaymentWrongPartial); - }, /XRP to XRP payments cannot be partial payments/); - }); - it('preparePayment - address must match payment.source.address', function() { - assert.throws(() => { - this.api.preparePayment(address, requests.preparePaymentWrongAddress); - }, /address must match payment.source.address/); - }); - - it('preparePayment - wrong amount', function() { - assert.throws(() => { - this.api.preparePayment(address, requests.preparePaymentWrongAmount); - }, this.api.errors.ValidationError); - }); - - it('preparePayment with all options specified', function() { - return this.api.getLedgerVersion().then((ver) => { - const localInstructions = { - maxLedgerVersion: ver + 100, - fee: '0.000012' - }; + it('preparePayment without counterparty set', function() { + const localInstructions = _.defaults({sequence: 23}, instructions); return this.api.preparePayment( - address, requests.preparePaymentAllOptions, localInstructions).then( - _.partial(checkResult, responses.preparePayment.allOptions, 'prepare')); + address, requests.preparePayment.noCounterparty, localInstructions) + .then(_.partial(checkResult, responses.preparePayment.noCounterparty, + 'prepare')); }); - }); - it('preparePayment without counterparty set', function() { - const localInstructions = _.defaults({sequence: 23}, instructions); - return this.api.preparePayment( - address, requests.preparePaymentNoCounterparty, localInstructions).then( - _.partial(checkResult, responses.preparePayment.noCounterparty, - 'prepare')); - }); - - it('preparePayment - destination.minAmount', function() { - return this.api.preparePayment(address, responses.getPaths.sendAll[0], - instructions).then(_.partial(checkResult, - responses.preparePayment.minAmount, 'prepare')); + it('preparePayment - destination.minAmount', function() { + return this.api.preparePayment(address, responses.getPaths.sendAll[0], + instructions).then(_.partial(checkResult, + responses.preparePayment.minAmount, 'prepare')); + }); }); it('prepareOrder - buy order', function() { @@ -365,17 +140,25 @@ describe('RippleAPI', function() { }); it('prepareOrderCancellation', function() { - const request = requests.prepareOrderCancellation; + const request = requests.prepareOrderCancellation.simple; return this.api.prepareOrderCancellation(address, request, instructions) - .then(_.partial(checkResult, responses.prepareOrder.cancellation, + .then(_.partial(checkResult, responses.prepareOrderCancellation.normal, 'prepare')); }); it('prepareOrderCancellation - no instructions', function() { - const request = requests.prepareOrderCancellation; + const request = requests.prepareOrderCancellation.simple; return this.api.prepareOrderCancellation(address, request) .then(_.partial(checkResult, - responses.prepareOrder.cancellationNoInstructions, + responses.prepareOrderCancellation.noInstructions, + 'prepare')); + }); + + it('prepareOrderCancellation - with memos', function() { + const request = requests.prepareOrderCancellation.withMemos; + return this.api.prepareOrderCancellation(address, request) + .then(_.partial(checkResult, + responses.prepareOrderCancellation.withMemos, 'prepare')); }); @@ -458,63 +241,71 @@ describe('RippleAPI', function() { maxFee: '0.000012' }, instructions); return this.api.prepareSuspendedPaymentCreation( - address, requests.prepareSuspendedPaymentCreation, + address, requests.prepareSuspendedPaymentCreation.normal, localInstructions).then( - _.partial(checkResult, responses.prepareSuspendedPaymentCreation, + _.partial(checkResult, responses.prepareSuspendedPaymentCreation.normal, 'prepare')); }); it('prepareSuspendedPaymentCreation full', function() { return this.api.prepareSuspendedPaymentCreation( - address, requests.prepareSuspendedPaymentCreationFull).then( - _.partial(checkResult, responses.prepareSuspendedPaymentCreationFull, + address, requests.prepareSuspendedPaymentCreation.full).then( + _.partial(checkResult, responses.prepareSuspendedPaymentCreation.full, 'prepare')); }); it('prepareSuspendedPaymentExecution', function() { return this.api.prepareSuspendedPaymentExecution( - address, requests.prepareSuspendedPaymentExecution, instructions).then( - _.partial(checkResult, responses.prepareSuspendedPaymentExecution, - 'prepare')); + address, + requests.prepareSuspendedPaymentExecution.normal, instructions).then( + _.partial(checkResult, + responses.prepareSuspendedPaymentExecution.normal, + 'prepare')); }); it('prepareSuspendedPaymentExecution - simple', function() { return this.api.prepareSuspendedPaymentExecution( - address, requests.prepareSuspendedPaymentExecutionSimple).then( - _.partial(checkResult, responses.prepareSuspendedPaymentExecutionSimple, - 'prepare')); + address, + requests.prepareSuspendedPaymentExecution.simple).then( + _.partial(checkResult, + responses.prepareSuspendedPaymentExecution.simple, + 'prepare')); }); it('prepareSuspendedPaymentCancellation', function() { return this.api.prepareSuspendedPaymentCancellation( - address, requests.prepareSuspendedPaymentCancellation, instructions).then( - _.partial(checkResult, responses.prepareSuspendedPaymentCancellation, - 'prepare')); + address, + requests.prepareSuspendedPaymentCancellation.normal, instructions).then( + _.partial(checkResult, + responses.prepareSuspendedPaymentCancellation.normal, + 'prepare')); }); it('prepareSuspendedPaymentCancellation with memos', function() { return this.api.prepareSuspendedPaymentCancellation( - address, requests.prepareSuspendedPaymentCancellationMemos).then( - _.partial(checkResult, responses.prepareSuspendedPaymentCancellationMemos, - 'prepare')); + address, + requests.prepareSuspendedPaymentCancellation.memos).then( + _.partial(checkResult, + responses.prepareSuspendedPaymentCancellation.memos, + 'prepare')); }); it('sign', function() { const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'; - const result = this.api.sign(requests.sign.txJSON, secret); - assert.deepEqual(result, responses.sign); + const result = this.api.sign(requests.sign.normal.txJSON, secret); + assert.deepEqual(result, responses.sign.normal); schemaValidator.schemaValidate('sign', result); }); it('sign - SuspendedPaymentExecution', function() { const secret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb'; - const result = this.api.sign(requests.signSuspended.txJSON, secret); - assert.deepEqual(result, responses.signSuspended); + const result = this.api.sign(requests.sign.suspended.txJSON, secret); + assert.deepEqual(result, responses.sign.suspended); schemaValidator.schemaValidate('sign', result); }); it('submit', function() { - return this.api.submit(responses.sign.signedTransaction).then( + return this.api.submit(responses.sign.normal.signedTransaction).then( _.partial(checkResult, responses.submit, 'submit')); }); @@ -860,7 +651,7 @@ describe('RippleAPI', function() { it('getTransactions', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 2}; return this.api.getTransactions(address, options).then( - _.partial(checkResult, responses.getTransactions, + _.partial(checkResult, responses.getTransactions.normal, 'getTransactions')); }); @@ -868,7 +659,7 @@ describe('RippleAPI', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 2, earliestFirst: true }; - const expected = _.cloneDeep(responses.getTransactions) + const expected = _.cloneDeep(responses.getTransactions.normal) .sort(utils.compareTransactions); return this.api.getTransactions(address, options).then( _.partial(checkResult, expected, 'getTransactions')); @@ -951,7 +742,8 @@ describe('RippleAPI', function() { limit: 2 }; return this.api.getTransactions(address, options).then( - _.partial(checkResult, responses.getTransactions, 'getTransactions')); + _.partial(checkResult, responses.getTransactions.normal, + 'getTransactions')); }); it('getTransactions - start transaction with zero ledger version', function( @@ -966,18 +758,19 @@ describe('RippleAPI', function() { it('getTransactions - no options', function() { return this.api.getTransactions(addresses.OTHER_ACCOUNT).then( - _.partial(checkResult, responses.getTransactionsOne, 'getTransactions')); + _.partial(checkResult, responses.getTransactions.one, 'getTransactions')); }); - it('getTrustlines', function() { + it('getTrustlines - filtered', function() { const options = {currency: 'USD'}; return this.api.getTrustlines(address, options).then( - _.partial(checkResult, responses.getTrustlines, 'getTrustlines')); + _.partial(checkResult, + responses.getTrustlines.filtered, 'getTrustlines')); }); - it('getTrustlines - ono options', function() { + it('getTrustlines - no options', function() { return this.api.getTrustlines(address).then( - _.partial(checkResult, responses.getTrustlinesAll, 'getTrustlines')); + _.partial(checkResult, responses.getTrustlines.all, 'getTrustlines')); }); it('generateAddress', function() { @@ -1045,59 +838,66 @@ describe('RippleAPI', function() { }, this.api.errors.ValidationError); }); - it('getOrderbook', function() { - return this.api.getOrderbook(address, requests.getOrderbook, undefined) - .then( - _.partial(checkResult, responses.getOrderbook, 'getOrderbook')); - }); + describe('getOrderbook', function() { - it('getOrderbook - invalid options', function() { - assert.throws(() => { - this.api.getOrderbook(address, requests.getOrderbook, - {invalid: 'options'}); - }, this.api.errors.ValidationError); - }); + it('normal', function() { + return this.api.getOrderbook(address, + requests.getOrderbook.normal, undefined).then( + _.partial(checkResult, + responses.getOrderbook.normal, 'getOrderbook')); + }); + + it('invalid options', function() { + assert.throws(() => { + this.api.getOrderbook(address, requests.getOrderbook.normal, + {invalid: 'options'}); + }, this.api.errors.ValidationError); + }); - it('getOrderbook with XRP', function() { - return this.api.getOrderbook(address, requests.getOrderbookWithXRP).then( - _.partial(checkResult, responses.getOrderbookWithXRP, 'getOrderbook')); - }); - - it('getOrderbook - sorted so that best deals come first', function() { - return this.api.getOrderbook(address, requests.getOrderbook) - .then(data => { - const bidRates = data.bids.map(bid => bid.properties.makerExchangeRate); - const askRates = data.asks.map(ask => ask.properties.makerExchangeRate); - // makerExchangeRate = quality = takerPays.value/takerGets.value - // so the best deal for the taker is the lowest makerExchangeRate - // bids and asks should be sorted so that the best deals come first - assert.deepEqual(_.sortBy(bidRates, x => Number(x)), bidRates); - assert.deepEqual(_.sortBy(askRates, x => Number(x)), askRates); - }); - }); - - it('getOrderbook - currency & counterparty are correct', function() { - return this.api.getOrderbook(address, requests.getOrderbook) - .then(data => { - const orders = _.flatten([data.bids, data.asks]); - _.forEach(orders, order => { - const quantity = order.specification.quantity; - const totalPrice = order.specification.totalPrice; - const {base, counter} = requests.getOrderbook; - assert.strictEqual(quantity.currency, base.currency); - assert.strictEqual(quantity.counterparty, base.counterparty); - assert.strictEqual(totalPrice.currency, counter.currency); - assert.strictEqual(totalPrice.counterparty, counter.counterparty); + it('with XRP', function() { + return this.api.getOrderbook(address, requests.getOrderbook.withXRP).then( + _.partial(checkResult, responses.getOrderbook.withXRP, 'getOrderbook')); + }); + + it('sorted so that best deals come first', function() { + return this.api.getOrderbook(address, requests.getOrderbook.normal) + .then(data => { + const bidRates = data.bids.map(bid => bid.properties.makerExchangeRate); + const askRates = data.asks.map(ask => ask.properties.makerExchangeRate); + // makerExchangeRate = quality = takerPays.value/takerGets.value + // so the best deal for the taker is the lowest makerExchangeRate + // bids and asks should be sorted so that the best deals come first + assert.deepEqual(_.sortBy(bidRates, x => Number(x)), bidRates); + assert.deepEqual(_.sortBy(askRates, x => Number(x)), askRates); }); }); - }); - it('getOrderbook - direction is correct for bids and asks', function() { - return this.api.getOrderbook(address, requests.getOrderbook) - .then(data => { - assert(_.every(data.bids, bid => bid.specification.direction === 'buy')); - assert(_.every(data.asks, ask => ask.specification.direction === 'sell')); + it('currency & counterparty are correct', function() { + return this.api.getOrderbook(address, requests.getOrderbook.normal) + .then(data => { + const orders = _.flatten([data.bids, data.asks]); + _.forEach(orders, order => { + const quantity = order.specification.quantity; + const totalPrice = order.specification.totalPrice; + const {base, counter} = requests.getOrderbook.normal; + assert.strictEqual(quantity.currency, base.currency); + assert.strictEqual(quantity.counterparty, base.counterparty); + assert.strictEqual(totalPrice.currency, counter.currency); + assert.strictEqual(totalPrice.counterparty, counter.counterparty); + }); + }); + }); + + it('direction is correct for bids and asks', function() { + return this.api.getOrderbook(address, requests.getOrderbook.normal) + .then(data => { + assert( + _.every(data.bids, bid => bid.specification.direction === 'buy')); + assert( + _.every(data.asks, ask => ask.specification.direction === 'sell')); + }); }); + }); it('getServerInfo', function() { @@ -1455,7 +1255,8 @@ describe('RippleAPI - offline', function() { }; return api.prepareSettings(address, settings, instructions).then(data => { checkResult(responses.prepareSettings.flags, 'prepare', data); - assert.deepEqual(api.sign(data.txJSON, secret), responses.sign); + assert.deepEqual(api.sign(data.txJSON, secret), + responses.prepareSettings.signed); }); }); diff --git a/test/connection-test.js b/test/connection-test.js new file mode 100644 index 0000000000..870861ad17 --- /dev/null +++ b/test/connection-test.js @@ -0,0 +1,261 @@ +/* eslint-disable max-nested-callbacks */ +'use strict'; + +const _ = require('lodash'); +const net = require('net'); +const assert = require('assert-diff'); +const setupAPI = require('./setup-api'); +const RippleAPI = require('ripple-api').RippleAPI; +const utils = RippleAPI._PRIVATE.ledgerUtils; + + +function unused() { +} + +function createServer() { + return new Promise((resolve, reject) => { + const server = net.createServer(); + server.on('listening', function() { + resolve(server); + }); + server.on('error', function(error) { + reject(error); + }); + server.listen(0, '0.0.0.0'); + }); +} + +describe('Connection', function() { + beforeEach(setupAPI.setup); + afterEach(setupAPI.teardown); + + it('default options', function() { + const connection = new utils.common.Connection('url'); + assert.strictEqual(connection._url, 'url'); + assert(_.isUndefined(connection._proxyURL)); + assert(_.isUndefined(connection._authorization)); + }); + + it('trace', function() { + const connection = new utils.common.Connection('url', {trace: true}); + const message1 = '{"type": "transaction"}'; + const message2 = '{"type": "path_find"}'; + const messages = []; + connection._console = { + log: function(message) { + messages.push(message); + } + }; + connection._onMessage(message1); + connection._send(message2); + + assert.deepEqual(messages, [message1, message2]); + }); + + it('with proxy', function(done) { + createServer().then((server) => { + const port = server.address().port; + const expect = 'CONNECT localhost'; + server.on('connection', (socket) => { + socket.on('data', (data) => { + const got = data.toString('ascii', 0, expect.length); + assert.strictEqual(got, expect); + server.close(); + done(); + }); + }); + + const options = { + proxy: 'ws://localhost:' + port, + authorization: 'authorization', + trustedCertificates: ['path/to/pem'] + }; + const connection = + new utils.common.Connection(this.api.connection._url, options); + connection.connect().catch(done); + connection.connect().catch(done); + }, done); + }); + + it('Multiply disconnect calls', function() { + this.api.disconnect(); + return this.api.disconnect(); + }); + + it('reconnect', function() { + return this.api.connection.reconnect(); + }); + + it('NotConnectedError', function() { + const connection = new utils.common.Connection('url'); + return connection.getLedgerVersion().then(() => { + assert(false, 'Should throw NotConnectedError'); + }).catch(error => { + assert(error instanceof this.api.errors.NotConnectedError); + }); + }); + + it('DisconnectedError', function() { + this.api.connection._send = function() { + this._ws.close(); + }; + return this.api.getServerInfo().then(() => { + assert(false, 'Should throw DisconnectedError'); + }).catch(error => { + assert(error instanceof this.api.errors.DisconnectedError); + }); + }); + + it('TimeoutError', function() { + this.api.connection._send = function() { + return Promise.resolve({}); + }; + const request = {command: 'server_info'}; + return this.api.connection.request(request, 1).then(() => { + assert(false, 'Should throw TimeoutError'); + }).catch(error => { + assert(error instanceof this.api.errors.TimeoutError); + }); + }); + + it('DisconnectedError on send', function() { + this.api.connection._ws.send = function(message, options, callback) { + unused(message, options); + callback({message: 'not connected'}); + }; + return this.api.getServerInfo().then(() => { + assert(false, 'Should throw DisconnectedError'); + }).catch(error => { + assert(error instanceof this.api.errors.DisconnectedError); + assert.strictEqual(error.message, 'not connected'); + }); + }); + + it('ResponseFormatError', function() { + this.api.connection._send = function(message) { + const parsed = JSON.parse(message); + setTimeout(() => { + this._ws.emit('message', JSON.stringify({ + id: parsed.id, + type: 'response', + status: 'unrecognized' + })); + }, 2); + return new Promise(() => {}); + }; + return this.api.getServerInfo().then(() => { + assert(false, 'Should throw ResponseFormatError'); + }).catch(error => { + assert(error instanceof this.api.errors.ResponseFormatError); + }); + }); + + it('reconnect on unexpected close ', function(done) { + this.api.connection.on('connected', () => { + done(); + }); + + setTimeout(() => { + this.api.connection._ws.close(); + }, 1); + }); + + it('Multiply connect calls', function() { + return this.api.connect().then(() => { + return this.api.connect(); + }); + }); + + it('hasLedgerVersion', function() { + return this.api.connection.hasLedgerVersion(8819951).then((result) => { + assert(result); + }); + }); + + it('Cannot connect because no server', function() { + const connection = new utils.common.Connection(); + return connection.connect().then(() => { + assert(false, 'Should throw ConnectionError'); + }).catch(error => { + assert(error instanceof this.api.errors.ConnectionError); + }); + }); + + it('connect multiserver error', function() { + const options = { + servers: ['wss://server1.com', 'wss://server2.com'] + }; + assert.throws(function() { + const api = new RippleAPI(options); + unused(api); + }, this.api.errors.RippleError); + }); + + it('connect throws error', function(done) { + this.api.once('error', (type, info) => { + assert.strictEqual(type, 'type'); + assert.strictEqual(info, 'info'); + done(); + }); + this.api.connection.emit('error', 'type', 'info'); + }); + + it('emit stream messages', function(done) { + let transactionCount = 0; + let pathFindCount = 0; + this.api.connection.on('transaction', () => { + transactionCount++; + }); + this.api.connection.on('path_find', () => { + pathFindCount++; + }); + this.api.connection.on('1', () => { + assert.strictEqual(transactionCount, 1); + assert.strictEqual(pathFindCount, 1); + done(); + }); + + this.api.connection._onMessage(JSON.stringify({ + type: 'transaction' + })); + this.api.connection._onMessage(JSON.stringify({ + type: 'path_find' + })); + this.api.connection._onMessage(JSON.stringify({ + type: 'response', id: 1 + })); + }); + + it('invalid message id', function(done) { + this.api.on('error', (type, message) => { + assert.strictEqual(type, 'badMessage'); + assert.strictEqual(message, + '{"type":"response","id":"must be integer"}'); + done(); + }); + this.api.connection._onMessage(JSON.stringify({ + type: 'response', id: 'must be integer' + })); + }); + + it('propagate error message', function(done) { + this.api.on('error', (type, message) => { + assert.strictEqual(type, 'slowDown'); + assert.strictEqual(message, 'slow down'); + done(); + }); + this.api.connection._onMessage(JSON.stringify({ + error: 'slowDown', error_message: 'slow down' + })); + }); + + it('unrecognized message type', function(done) { + this.api.on('error', (type, message) => { + assert.strictEqual(type, 'badMessage'); + assert.strictEqual(message, '{"type":"unknown"}'); + done(); + }); + + this.api.connection._onMessage(JSON.stringify({type: 'unknown'})); + }); +}); diff --git a/test/fixtures/requests/index.js b/test/fixtures/requests/index.js index aaddbf9e71..84b9ca1610 100644 --- a/test/fixtures/requests/index.js +++ b/test/fixtures/requests/index.js @@ -6,35 +6,42 @@ module.exports = { sell: require('./prepare-order-sell'), expiration: require('./prepare-order-expiration') }, - prepareOrderCancellation: require('./prepare-order-cancellation'), - preparePayment: require('./prepare-payment'), - preparePaymentMinAmountXRP: require('./prepare-payment-min-xrp'), - preparePaymentMinAmount: require('./prepare-payment-min'), - preparePaymentWrongAddress: require('./prepare-payment-wrong-address'), - preparePaymentWrongAmount: require('./prepare-payment-wrong-amount'), - preparePaymentWrongPartial: require('./prepare-payment-wrong-partial'), - preparePaymentAllOptions: require('./prepare-payment-all-options'), - preparePaymentNoCounterparty: require('./prepare-payment-no-counterparty'), + prepareOrderCancellation: { + simple: require('./prepare-order-cancellation'), + withMemos: require('./prepare-order-cancellation-memos') + }, + preparePayment: { + normal: require('./prepare-payment'), + minAmountXRP: require('./prepare-payment-min-xrp'), + minAmount: require('./prepare-payment-min'), + wrongAddress: require('./prepare-payment-wrong-address'), + wrongAmount: require('./prepare-payment-wrong-amount'), + wrongPartial: require('./prepare-payment-wrong-partial'), + allOptions: require('./prepare-payment-all-options'), + noCounterparty: require('./prepare-payment-no-counterparty') + }, prepareSettings: require('./prepare-settings'), - prepareSuspendedPaymentCreation: - require('./prepare-suspended-payment-creation'), - prepareSuspendedPaymentCreationFull: - require('./prepare-suspended-payment-creation-full'), - prepareSuspendedPaymentExecution: - require('./prepare-suspended-payment-execution'), - prepareSuspendedPaymentExecutionSimple: - require('./prepare-suspended-payment-execution-simple'), - prepareSuspendedPaymentCancellation: - require('./prepare-suspended-payment-cancellation'), - prepareSuspendedPaymentCancellationMemos: - require('./prepare-suspended-payment-cancellation-memos'), + prepareSuspendedPaymentCreation: { + normal: require('./prepare-suspended-payment-creation'), + full: require('./prepare-suspended-payment-creation-full') + }, + prepareSuspendedPaymentExecution: { + normal: require('./prepare-suspended-payment-execution'), + simple: require('./prepare-suspended-payment-execution-simple') + }, + prepareSuspendedPaymentCancellation: { + normal: require('./prepare-suspended-payment-cancellation'), + memos: require('./prepare-suspended-payment-cancellation-memos') + }, prepareTrustline: { simple: require('./prepare-trustline-simple'), complex: require('./prepare-trustline'), frozen: require('./prepare-trustline-frozen.json') }, - sign: require('./sign'), - signSuspended: require('./sign-suspended.json'), + sign: { + normal: require('./sign'), + suspended: require('./sign-suspended.json') + }, getPaths: { normal: require('./getpaths/normal'), UsdToUsd: require('./getpaths/usd2usd'), @@ -47,8 +54,10 @@ module.exports = { invalid: require('./getpaths/invalid'), issuer: require('./getpaths/issuer') }, - getOrderbook: require('./get-orderbook'), - getOrderbookWithXRP: require('./get-orderbook-with-xrp'), + getOrderbook: { + normal: require('./get-orderbook'), + withXRP: require('./get-orderbook-with-xrp') + }, computeLedgerHash: { header: require('./compute-ledger-hash'), transactions: require('./compute-ledger-hash-transactions') diff --git a/test/fixtures/requests/prepare-order-cancellation-memos.json b/test/fixtures/requests/prepare-order-cancellation-memos.json new file mode 100644 index 0000000000..a170768540 --- /dev/null +++ b/test/fixtures/requests/prepare-order-cancellation-memos.json @@ -0,0 +1,10 @@ +{ + "orderSequence": 23, + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] +} diff --git a/test/fixtures/requests/prepare-order-sell.json b/test/fixtures/requests/prepare-order-sell.json index 21d7980277..6f1d587ed4 100644 --- a/test/fixtures/requests/prepare-order-sell.json +++ b/test/fixtures/requests/prepare-order-sell.json @@ -9,5 +9,12 @@ "currency": "XRP", "value": "2" }, - "immediateOrCancel": true + "immediateOrCancel": true, + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] } diff --git a/test/fixtures/requests/prepare-settings.json b/test/fixtures/requests/prepare-settings.json index 6bc5dbb4bb..ca1d626f6d 100644 --- a/test/fixtures/requests/prepare-settings.json +++ b/test/fixtures/requests/prepare-settings.json @@ -1,3 +1,10 @@ { - "domain": "ripple.com" + "domain": "ripple.com", + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] } diff --git a/test/fixtures/requests/prepare-trustline.json b/test/fixtures/requests/prepare-trustline.json index 276e217dcd..0fb0ffa3ab 100644 --- a/test/fixtures/requests/prepare-trustline.json +++ b/test/fixtures/requests/prepare-trustline.json @@ -5,5 +5,12 @@ "qualityIn": 0.91, "qualityOut": 0.87, "ripplingDisabled": true, - "frozen": false + "frozen": false, + "memos": [ + { + "type": "test", + "format": "plain/text", + "data": "texted data" + } + ] } diff --git a/test/fixtures/responses/index.js b/test/fixtures/responses/index.js index cdf16d531a..967bbfd521 100644 --- a/test/fixtures/responses/index.js +++ b/test/fixtures/responses/index.js @@ -5,8 +5,10 @@ module.exports = { getAccountInfo: require('./get-account-info.json'), getBalances: require('./get-balances.json'), getBalanceSheet: require('./get-balance-sheet.json'), - getOrderbook: require('./get-orderbook.json'), - getOrderbookWithXRP: require('./get-orderbook-with-xrp.json'), + getOrderbook: { + normal: require('./get-orderbook.json'), + withXRP: require('./get-orderbook-with-xrp.json') + }, getOrders: require('./get-orders.json'), getPaths: { XrpToUsd: require('./get-paths.json'), @@ -43,10 +45,14 @@ module.exports = { suspendedPaymentExecutionSimple: require('./get-transaction-suspended-payment-execution-simple.json') }, - getTransactions: require('./get-transactions.json'), - getTransactionsOne: require('./get-transactions-one.json'), - getTrustlines: require('./get-trustlines.json'), - getTrustlinesAll: require('./get-trustlines-all.json'), + getTransactions: { + normal: require('./get-transactions.json'), + one: require('./get-transactions-one.json') + }, + getTrustlines: { + filtered: require('./get-trustlines.json'), + all: require('./get-trustlines-all.json') + }, getLedger: { header: require('./get-ledger'), full: require('./get-ledger-full'), @@ -56,10 +62,12 @@ module.exports = { prepareOrder: { buy: require('./prepare-order.json'), sell: require('./prepare-order-sell.json'), - expiration: require('./prepare-order-expiration'), - cancellation: require('./prepare-order-cancellation.json'), - cancellationNoInstructions: - require('./prepare-order-cancellation-no-instructions.json') + expiration: require('./prepare-order-expiration') + }, + prepareOrderCancellation: { + normal: require('./prepare-order-cancellation.json'), + withMemos: require('./prepare-order-cancellation-memos.json'), + noInstructions: require('./prepare-order-cancellation-no-instructions.json') }, preparePayment: { normal: require('./prepare-payment.json'), @@ -77,27 +85,30 @@ module.exports = { flagClear: require('./prepare-settings-flag-clear.json'), setTransferRate: require('./prepare-settings-set-transfer-rate.json'), fieldClear: require('./prepare-settings-field-clear.json'), - noInstructions: require('./prepare-settings-no-instructions.json') + noInstructions: require('./prepare-settings-no-instructions.json'), + signed: require('./prepare-settings-signed.json') + }, + prepareSuspendedPaymentCreation: { + normal: require('./prepare-suspended-payment-creation'), + full: require('./prepare-suspended-payment-creation-full') + }, + prepareSuspendedPaymentExecution: { + normal: require('./prepare-suspended-payment-execution'), + simple: require('./prepare-suspended-payment-execution-simple') + }, + prepareSuspendedPaymentCancellation: { + normal: require('./prepare-suspended-payment-cancellation'), + memos: require('./prepare-suspended-payment-cancellation-memos') }, - prepareSuspendedPaymentCreation: - require('./prepare-suspended-payment-creation'), - prepareSuspendedPaymentCreationFull: - require('./prepare-suspended-payment-creation-full'), - prepareSuspendedPaymentExecution: - require('./prepare-suspended-payment-execution'), - prepareSuspendedPaymentExecutionSimple: - require('./prepare-suspended-payment-execution-simple'), - prepareSuspendedPaymentCancellation: - require('./prepare-suspended-payment-cancellation'), - prepareSuspendedPaymentCancellationMemos: - require('./prepare-suspended-payment-cancellation-memos'), prepareTrustline: { simple: require('./prepare-trustline-simple.json'), frozen: require('./prepare-trustline-frozen.json'), complex: require('./prepare-trustline.json') }, - sign: require('./sign.json'), - signSuspended: require('./sign-suspended.json'), + sign: { + normal: require('./sign.json'), + suspended: require('./sign-suspended.json') + }, submit: require('./submit.json'), ledgerEvent: require('./ledger-event.json') }; diff --git a/test/fixtures/responses/prepare-order-cancellation-memos.json b/test/fixtures/responses/prepare-order-cancellation-memos.json new file mode 100644 index 0000000000..0d5bb7b3b0 --- /dev/null +++ b/test/fixtures/responses/prepare-order-cancellation-memos.json @@ -0,0 +1,8 @@ +{ + "txJSON": "{\"TransactionType\":\"OfferCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":23,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"Flags\":2147483648,\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}", + "instructions": { + "fee": "0.000012", + "sequence": 23, + "maxLedgerVersion": 8819954 + } +} diff --git a/test/fixtures/responses/prepare-order-sell.json b/test/fixtures/responses/prepare-order-sell.json index 7fb96d1134..43afec8aeb 100644 --- a/test/fixtures/responses/prepare-order-sell.json +++ b/test/fixtures/responses/prepare-order-sell.json @@ -1,8 +1,8 @@ -{ - "txJSON": "{\"Flags\":2148139008,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"TakerPays\":\"2000000\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", - "instructions": { - "fee": "0.000012", - "sequence": 23, - "maxLedgerVersion": 8820051 - } -} +{ + "txJSON": "{\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"10.1\"},\"TakerPays\":\"2000000\",\"Flags\":2148139008,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "instructions": { + "fee": "0.000012", + "sequence": 23, + "maxLedgerVersion": 8820051 + } +} diff --git a/test/fixtures/responses/prepare-settings-no-instructions.json b/test/fixtures/responses/prepare-settings-no-instructions.json index aad61b7e61..9e22bccaa2 100644 --- a/test/fixtures/responses/prepare-settings-no-instructions.json +++ b/test/fixtures/responses/prepare-settings-no-instructions.json @@ -1 +1,8 @@ -{"txJSON":"{\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"Flags\":2147483648,\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}","instructions":{"fee":"0.000012","sequence":23,"maxLedgerVersion":8819954}} \ No newline at end of file +{ + "txJSON": "{\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"Domain\":\"726970706C652E636F6D\",\"Flags\":2147483648,\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}", + "instructions": { + "fee": "0.000012", + "sequence": 23, + "maxLedgerVersion": 8819954 + } +} diff --git a/test/fixtures/responses/prepare-settings-signed.json b/test/fixtures/responses/prepare-settings-signed.json index a060e7731b..be63f9cd9b 100644 --- a/test/fixtures/responses/prepare-settings-signed.json +++ b/test/fixtures/responses/prepare-settings-signed.json @@ -1,4 +1,4 @@ -{ - "signedTransaction": "12000322000000002400000017201B0086955368400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402207660BDEF67105CE1EBA9AD35DC7156BAB43FF1D47633199EE257D70B6B9AAFBF022045A812486A675750B5A3F37131E9F92299728D37FF6BB7195CA5EE881268CB4C770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304", - "id": "29D23159EBA79170DCA5EF467CBC15114DBD35B7A8C3DBF76809BA354D00D250" -} +{ + "signedTransaction": "12000322800000002400000017201B0086955368400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402202FBF6A6F74DFDA17C7341D532B66141206BC71A147C08DBDA6A950AA9A1741DC022055859A39F2486A46487F8DA261E3D80B4FDD26178A716A929F26377D1BEC7E43770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304F9EA7C04746573747D0B74657874656420646174617E0A706C61696E2F74657874E1F1", + "id": "4755D26FAC39E3E477870D4E03CC6783DDDF967FFBE240606755D3D03702FC16" +} \ No newline at end of file diff --git a/test/fixtures/responses/prepare-settings.json b/test/fixtures/responses/prepare-settings.json index df9ea7c0ae..8c0102475d 100644 --- a/test/fixtures/responses/prepare-settings.json +++ b/test/fixtures/responses/prepare-settings.json @@ -1,5 +1,5 @@ { - "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "txJSON": "{\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"Domain\":\"726970706C652E636F6D\",\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "instructions": { "fee": "0.000012", "sequence": 23, diff --git a/test/fixtures/responses/prepare-trustline.json b/test/fixtures/responses/prepare-trustline.json index 0aba3f6b36..bb144e69b2 100644 --- a/test/fixtures/responses/prepare-trustline.json +++ b/test/fixtures/responses/prepare-trustline.json @@ -1,5 +1,5 @@ { - "txJSON": "{\"Flags\":2149711872,\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"value\":\"10000\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"QualityIn\":910000000,\"QualityOut\":870000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", + "txJSON": "{\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"10000\"},\"Flags\":2149711872,\"QualityIn\":910000000,\"QualityOut\":870000000,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "instructions": { "fee": "0.000012", "sequence": 23, diff --git a/test/fixtures/rippled/book-offers-1.json b/test/fixtures/rippled/book-offers-usd-xrp.json similarity index 100% rename from test/fixtures/rippled/book-offers-1.json rename to test/fixtures/rippled/book-offers-usd-xrp.json diff --git a/test/fixtures/rippled/book-offers-2.json b/test/fixtures/rippled/book-offers-xrp-usd.json similarity index 100% rename from test/fixtures/rippled/book-offers-2.json rename to test/fixtures/rippled/book-offers-xrp-usd.json diff --git a/test/fixtures/rippled/index.js b/test/fixtures/rippled/index.js index 1abebc7346..9ef0d97a37 100644 --- a/test/fixtures/rippled/index.js +++ b/test/fixtures/rippled/index.js @@ -5,11 +5,13 @@ module.exports = { success: require('./submit'), failure: require('./submit-failed') }, - ledger: require('./ledger'), - ledgerNotFound: require('./ledger-not-found'), - ledgerWithoutCloseTime: require('./ledger-without-close-time'), - ledgerWithSettingsTx: require('./ledger-with-settings-tx'), - ledgerWithStateAsHashes: require('./ledger-with-state-as-hashes'), + ledger: { + normal: require('./ledger'), + notFound: require('./ledger-not-found'), + withoutCloseTime: require('./ledger-without-close-time'), + withSettingsTx: require('./ledger-with-settings-tx'), + withStateAsHashes: require('./ledger-with-state-as-hashes') + }, subscribe: require('./subscribe'), unsubscribe: require('./unsubscribe'), account_info: { @@ -17,14 +19,20 @@ module.exports = { notfound: require('./account-info-not-found') }, account_offers: require('./account-offers'), - account_tx: require('./account-tx'), - account_tx_one: require('./get-transactions-one'), + account_tx: { + normal: require('./account-tx'), + one: require('./get-transactions-one') + }, gateway_balances: require('./gateway-balances'), - book_offers: require('./book-offers'), - book_offers_1: require('./book-offers-1'), - book_offers_2: require('./book-offers-2'), - server_info: require('./server-info'), - server_info_error: require('./server-info-error'), + book_offers: { + fabric: require('./book-offers'), + usd_xrp: require('./book-offers-usd-xrp'), + xrp_usd: require('./book-offers-xrp-usd') + }, + server_info: { + normal: require('./server-info'), + error: require('./server-info-error') + }, path_find: { generate: require('./path-find'), sendUSD: require('./path-find-send-usd'), diff --git a/test/mock-rippled.js b/test/mock-rippled.js index 03d849b5bd..93f22277dd 100644 --- a/test/mock-rippled.js +++ b/test/mock-rippled.js @@ -97,9 +97,9 @@ module.exports = function(port) { mock.on('request_server_info', function(request, conn) { assert.strictEqual(request.command, 'server_info'); if (mock.returnErrorOnServerInfo) { - conn.send(createResponse(request, fixtures.server_info_error)); + conn.send(createResponse(request, fixtures.server_info.error)); } else { - conn.send(createResponse(request, fixtures.server_info)); + conn.send(createResponse(request, fixtures.server_info.normal)); } }); @@ -139,19 +139,20 @@ module.exports = function(port) { mock.on('request_ledger', function(request, conn) { assert.strictEqual(request.command, 'ledger'); if (request.ledger_index === 34) { - conn.send(createLedgerResponse(request, fixtures.ledgerNotFound)); + conn.send(createLedgerResponse(request, fixtures.ledger.notFound)); } else if (request.ledger_index === 6) { - conn.send(createResponse(request, fixtures.ledgerWithStateAsHashes)); + conn.send(createResponse(request, fixtures.ledger.withStateAsHashes)); } else if (request.ledger_index === 9038215) { - conn.send(createLedgerResponse(request, fixtures.ledgerWithoutCloseTime)); + conn.send( + createLedgerResponse(request, fixtures.ledger.withoutCloseTime)); } else if (request.ledger_index === 4181996) { - conn.send(createLedgerResponse(request, fixtures.ledgerWithSettingsTx)); + conn.send(createLedgerResponse(request, fixtures.ledger.withSettingsTx)); } else if (request.ledger_index === 38129) { - const response = _.assign({}, fixtures.ledger, + const response = _.assign({}, fixtures.ledger.normal, {result: {ledger: fullLedger}}); conn.send(createLedgerResponse(request, response)); } else { - conn.send(createLedgerResponse(request, fixtures.ledger)); + conn.send(createLedgerResponse(request, fixtures.ledger.normal)); } }); @@ -263,7 +264,7 @@ module.exports = function(port) { if (request.account === addresses.ACCOUNT) { conn.send(transactionsResponse(request)); } else if (request.account === addresses.OTHER_ACCOUNT) { - conn.send(createResponse(request, fixtures.account_tx_one)); + conn.send(createResponse(request, fixtures.account_tx.one)); } else { assert(false, 'Unrecognized account address: ' + request.account); } @@ -279,16 +280,18 @@ module.exports = function(port) { mock.on('request_book_offers', function(request, conn) { if (request.taker_pays.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') { - conn.send(createResponse(request, fixtures.book_offers_2)); + conn.send(createResponse(request, fixtures.book_offers.xrp_usd)); } else if (request.taker_gets.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') { - conn.send(createResponse(request, fixtures.book_offers_1)); + conn.send(createResponse(request, fixtures.book_offers.usd_xrp)); } else if (isBTC(request.taker_gets.currency) && isUSD(request.taker_pays.currency)) { - conn.send(fixtures.book_offers.requestBookOffersBidsResponse(request)); + conn.send( + fixtures.book_offers.fabric.requestBookOffersBidsResponse(request)); } else if (isUSD(request.taker_gets.currency) && isBTC(request.taker_pays.currency)) { - conn.send(fixtures.book_offers.requestBookOffersAsksResponse(request)); + conn.send( + fixtures.book_offers.fabric.requestBookOffersAsksResponse(request)); } else { assert(false, 'Unrecognized order book: ' + JSON.stringify(request)); }