mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-05 05:15:48 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fafa493a2 | ||
|
|
7617c3005c | ||
|
|
5cdbb71277 | ||
|
|
f9339c36bf | ||
|
|
67dc57e9d0 | ||
|
|
757f3190d1 | ||
|
|
0d94a15ee7 | ||
|
|
7f1c80da1b | ||
|
|
f74e11bce0 | ||
|
|
d4c843e8e3 | ||
|
|
bae190b282 | ||
|
|
d2cbd70da8 | ||
|
|
5da78ce583 | ||
|
|
14bbe3e30b | ||
|
|
e52e2bbc68 | ||
|
|
b56752e45b | ||
|
|
4632f511ab | ||
|
|
e17b6f172d |
@@ -5,6 +5,7 @@ machine:
|
||||
testripple.circleci.com: 127.0.0.1
|
||||
dependencies:
|
||||
pre:
|
||||
- npm -g install npm@latest-2
|
||||
- wget https://s3-us-west-2.amazonaws.com/ripple-debs/rippled_0.30.1-b11-1.deb
|
||||
- sudo dpkg -i rippled_0.30.1-b11-1.deb
|
||||
test:
|
||||
|
||||
@@ -211,7 +211,7 @@ A *value* is a quantity of a currency represented as a decimal string. Be carefu
|
||||
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
|
||||
|
||||
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
|
||||
|
||||
## Amount
|
||||
@@ -498,7 +498,7 @@ signers | object | *Optional* Settings that determine what sets of accounts can
|
||||
*signers.* weights[] | object | An association of an address and a weight.
|
||||
*signers.weights[].* address | [address](#ripple-address) | A Ripple account address
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, represented as billionths of a unit. Use `null` to set no fee.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -2684,7 +2684,7 @@ signers | object | *Optional* Settings that determine what sets of accounts can
|
||||
*signers.* weights[] | object | An association of an address and a weight.
|
||||
*signers.weights[].* address | [address](#ripple-address) | A Ripple account address
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, represented as billionths of a unit. Use `null` to set no fee.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ A *value* is a quantity of a currency represented as a decimal string. Be carefu
|
||||
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
|
||||
|
||||
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
|
||||
|
||||
## Amount
|
||||
|
||||
4237
npm-shrinkwrap.json
generated
4237
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.16.9",
|
||||
"version": "0.17.2",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -15,7 +15,8 @@
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^1.4.8",
|
||||
"ajv": "^4.0.5",
|
||||
"ajv-i18n": "^1.2.0",
|
||||
"babel-polyfill": "^6.3.14",
|
||||
"babel-runtime": "^6.3.19",
|
||||
"bignumber.js": "^2.0.3",
|
||||
@@ -23,7 +24,7 @@
|
||||
"jayson": "^1.2.2",
|
||||
"lodash": "^3.1.0",
|
||||
"ripple-address-codec": "^2.0.1",
|
||||
"ripple-binary-codec": "^0.1.2",
|
||||
"ripple-binary-codec": "^0.1.3",
|
||||
"ripple-hashes": "^0.1.0",
|
||||
"ripple-keypairs": "^0.10.0",
|
||||
"ripple-lib-transactionparser": "^0.6.0",
|
||||
@@ -33,7 +34,7 @@
|
||||
"assert-diff": "^1.0.1",
|
||||
"babel-cli": "^6.4.0",
|
||||
"babel-core": "^6.4.0",
|
||||
"babel-eslint": "^4.1.8",
|
||||
"babel-eslint": "^6.0.4",
|
||||
"babel-loader": "^6.2.1",
|
||||
"babel-plugin-syntax-flow": "^6.3.13",
|
||||
"babel-plugin-transform-flow-strip-types": "^6.4.0",
|
||||
@@ -43,9 +44,9 @@
|
||||
"coveralls": "^2.10.0",
|
||||
"doctoc": "^0.15.0",
|
||||
"ejs": "^2.3.4",
|
||||
"eslint": "^2.1.0",
|
||||
"eslint": "^2.9.0",
|
||||
"eventemitter2": "^0.4.14",
|
||||
"flow-bin": "^0.14",
|
||||
"flow-bin": "^0.24.2",
|
||||
"gulp": "^3.8.10",
|
||||
"gulp-bump": "^0.1.13",
|
||||
"gulp-rename": "^1.2.0",
|
||||
@@ -56,7 +57,6 @@
|
||||
"json-schema-to-markdown-table": "^0.4.0",
|
||||
"mocha": "^2.1.0",
|
||||
"mocha-junit-reporter": "^1.9.1",
|
||||
"mocha-phantomjs": "^4.0.1",
|
||||
"mocha-in-sauce": "^0.0.1",
|
||||
"null-loader": "^0.1.1",
|
||||
"webpack": "^1.5.3",
|
||||
|
||||
@@ -39,10 +39,10 @@ unittest() {
|
||||
gulp build-min build-tests
|
||||
node --harmony test-compiled/mocked-server.js > /dev/null &
|
||||
|
||||
echo "Running tests in PhantomJS"
|
||||
mocha-phantomjs test/localrunner.html
|
||||
echo "Running tests using minified version in PhantomJS"
|
||||
mocha-phantomjs test/localrunnermin.html
|
||||
#echo "Running tests in PhantomJS"
|
||||
#mocha-phantomjs test/localrunner.html
|
||||
#echo "Running tests using minified version in PhantomJS"
|
||||
#mocha-phantomjs test/localrunnermin.html
|
||||
|
||||
echo "Running tests in SauceLabs"
|
||||
http-server &
|
||||
@@ -58,9 +58,9 @@ integrationtest() {
|
||||
mocha test/integration/http-integration-test.js
|
||||
|
||||
# run integration tests in PhantomJS
|
||||
gulp build-tests build-min
|
||||
echo "Running integragtion tests in PhantomJS"
|
||||
mocha-phantomjs test/localintegrationrunner.html
|
||||
#gulp build-tests build-min
|
||||
#echo "Running integragtion tests in PhantomJS"
|
||||
#mocha-phantomjs test/localintegrationrunner.html
|
||||
}
|
||||
|
||||
doctest() {
|
||||
|
||||
@@ -40,6 +40,10 @@ function main() {
|
||||
version: '43'});
|
||||
sauce.browser({browserName: 'safari', platform: 'OS X 10.11',
|
||||
version: '9'});
|
||||
sauce.browser({browserName: 'safari', platform: 'OS X 10.10',
|
||||
version: '8'});
|
||||
sauce.browser({browserName: 'safari', platform: 'OS X 10.9',
|
||||
version: '7'});
|
||||
sauce.browser({browserName: 'chrome', platform: 'OS X 10.11',
|
||||
version: '47'});
|
||||
sauce.browser({browserName: 'chrome', platform: 'Linux',
|
||||
|
||||
@@ -92,8 +92,8 @@ class RippleAPI extends EventEmitter {
|
||||
this.connection.on('connected', () => {
|
||||
this.emit('connected');
|
||||
});
|
||||
this.connection.on('disconnected', onError => {
|
||||
this.emit('disconnected', onError);
|
||||
this.connection.on('disconnected', code => {
|
||||
this.emit('disconnected', code);
|
||||
});
|
||||
} else {
|
||||
// use null object pattern to provide better error message if user
|
||||
|
||||
@@ -6,7 +6,8 @@ const WebSocket = require('ws');
|
||||
const parseURL = require('url').parse;
|
||||
const RangeSet = require('./rangeset').RangeSet;
|
||||
const {RippledError, DisconnectedError, NotConnectedError,
|
||||
TimeoutError, ResponseFormatError, ConnectionError} = require('./errors');
|
||||
TimeoutError, ResponseFormatError, ConnectionError,
|
||||
RippledNotInitializedError} = require('./errors');
|
||||
|
||||
function isStreamMessageType(type) {
|
||||
return type === 'ledgerClosed' ||
|
||||
@@ -39,6 +40,8 @@ class Connection extends EventEmitter {
|
||||
this._nextRequestID = 1;
|
||||
this._retry = 0;
|
||||
this._retryTimer = null;
|
||||
this._onOpenErrorBound = null;
|
||||
this._onUnexpectedCloseBound = null;
|
||||
}
|
||||
|
||||
_updateLedgerVersions(data) {
|
||||
@@ -104,6 +107,8 @@ class Connection extends EventEmitter {
|
||||
this._ws.removeListener('error', this._onOpenErrorBound);
|
||||
this._onOpenErrorBound = null;
|
||||
}
|
||||
// just in case
|
||||
this._ws.removeAllListeners('open');
|
||||
this._ws = null;
|
||||
this._isReady = false;
|
||||
if (beforeOpen) {
|
||||
@@ -136,6 +141,7 @@ class Connection extends EventEmitter {
|
||||
this._retry += 1;
|
||||
const retryTimeout = this._calculateTimeout(this._retry);
|
||||
this._retryTimer = setTimeout(() => {
|
||||
this.emit('reconnecting', this._retry);
|
||||
this.connect().catch(this._retryConnect.bind(this));
|
||||
}, retryTimeout);
|
||||
}
|
||||
@@ -146,30 +152,65 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
_onOpen() {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
this._onUnexpectedCloseBound =
|
||||
this._onUnexpectedClose.bind(this, false, null, null);
|
||||
this._ws.once('close', this._onUnexpectedCloseBound);
|
||||
|
||||
this._ws.removeListener('error', this._onOpenErrorBound);
|
||||
this._onOpenErrorBound = null;
|
||||
this._retry = 0;
|
||||
this._ws.on('error', error =>
|
||||
this.emit('error', 'websocket', error.message, error));
|
||||
if (!this._ws) {
|
||||
return Promise.reject(new DisconnectedError());
|
||||
}
|
||||
if (this._onOpenErrorBound) {
|
||||
this._ws.removeListener('error', this._onOpenErrorBound);
|
||||
this._onOpenErrorBound = null;
|
||||
}
|
||||
|
||||
const request = {
|
||||
command: 'subscribe',
|
||||
streams: ['ledger']
|
||||
};
|
||||
return this.request(request).then(data => {
|
||||
if (_.isEmpty(data) || !data.ledger_index) {
|
||||
// rippled instance doesn't have validated ledgers
|
||||
return this._disconnect(false).then(() => {
|
||||
throw new RippledNotInitializedError('Rippled not initialized');
|
||||
});
|
||||
}
|
||||
|
||||
this._updateLedgerVersions(data);
|
||||
this._rebindOnUnxpectedClose();
|
||||
|
||||
this._retry = 0;
|
||||
this._ws.on('error', error => {
|
||||
if (process.browser && error && error.type === 'error') {
|
||||
// we are in browser, ignore error - `close` event will be fired
|
||||
// after error
|
||||
return;
|
||||
}
|
||||
this.emit('error', 'websocket', error.message, error);
|
||||
});
|
||||
|
||||
this._isReady = true;
|
||||
this.emit('connected');
|
||||
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
_rebindOnUnxpectedClose() {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
}
|
||||
this._onUnexpectedCloseBound =
|
||||
this._onUnexpectedClose.bind(this, false, null, null);
|
||||
this._ws.once('close', this._onUnexpectedCloseBound);
|
||||
}
|
||||
|
||||
_unbindOnUnxpectedClose() {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
}
|
||||
this._onUnexpectedCloseBound = null;
|
||||
}
|
||||
|
||||
_onOpenError(reject, error) {
|
||||
this._onOpenErrorBound = null;
|
||||
this._unbindOnUnxpectedClose();
|
||||
reject(new NotConnectedError(error && error.message));
|
||||
}
|
||||
|
||||
@@ -252,19 +293,30 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this._clearReconnectTimer();
|
||||
this._retry = 0;
|
||||
return this._disconnect(true);
|
||||
}
|
||||
|
||||
_disconnect(calledByUser) {
|
||||
if (calledByUser) {
|
||||
this._clearReconnectTimer();
|
||||
this._retry = 0;
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
if (this._state === WebSocket.CLOSED) {
|
||||
resolve();
|
||||
} else if (this._state === WebSocket.CLOSING) {
|
||||
this._ws.once('close', resolve);
|
||||
} else {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
this._onUnexpectedCloseBound = null;
|
||||
}
|
||||
this._ws.once('close', code => {
|
||||
this._ws = null;
|
||||
this._isReady = false;
|
||||
this.emit('disconnected', code || 1000); // 1000 - CLOSE_NORMAL
|
||||
if (calledByUser) {
|
||||
this.emit('disconnected', code || 1000); // 1000 - CLOSE_NORMAL
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
this._ws.close();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const util = require('util');
|
||||
const browserHacks = require('./browser-hacks');
|
||||
|
||||
@@ -53,6 +53,8 @@ class NotConnectedError extends ConnectionError {}
|
||||
|
||||
class DisconnectedError extends ConnectionError {}
|
||||
|
||||
class RippledNotInitializedError extends ConnectionError {}
|
||||
|
||||
class TimeoutError extends ConnectionError {}
|
||||
|
||||
class ResponseFormatError extends ConnectionError {}
|
||||
@@ -85,6 +87,7 @@ module.exports = {
|
||||
RippledError,
|
||||
NotConnectedError,
|
||||
DisconnectedError,
|
||||
RippledNotInitializedError,
|
||||
TimeoutError,
|
||||
ResponseFormatError,
|
||||
ValidationError,
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
"description": " The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase."
|
||||
},
|
||||
"transferRate": {
|
||||
"description": " The fee to charge when users transfer this account’s issuances, represented as billionths of a unit. Use `null` to set no fee.",
|
||||
"description": " The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.",
|
||||
"oneOf": [
|
||||
{"type": "null"},
|
||||
{"type": "number", "minimum": 1, "maximum": 4.294967295}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const {convertKeysFromSnakeCaseToCamelCase} = require('./utils');
|
||||
import type {Connection} from './connection';
|
||||
@@ -43,18 +43,20 @@ function getServerInfo(connection: Connection): Promise<GetServerInfoResponse> {
|
||||
return connection.request({command: 'server_info'}).then(response => {
|
||||
const info = convertKeysFromSnakeCaseToCamelCase(response.info);
|
||||
renameKeys(info, {hostid: 'hostID'});
|
||||
renameKeys(info.validatedLedger, {
|
||||
baseFeeXrp: 'baseFeeXRP',
|
||||
reserveBaseXrp: 'reserveBaseXRP',
|
||||
reserveIncXrp: 'reserveIncrementXRP',
|
||||
seq: 'ledgerVersion'
|
||||
});
|
||||
info.validatedLedger.baseFeeXRP =
|
||||
info.validatedLedger.baseFeeXRP.toString();
|
||||
info.validatedLedger.reserveBaseXRP =
|
||||
info.validatedLedger.reserveBaseXRP.toString();
|
||||
info.validatedLedger.reserveIncrementXRP =
|
||||
info.validatedLedger.reserveIncrementXRP.toString();
|
||||
if (info.validatedLedger) {
|
||||
renameKeys(info.validatedLedger, {
|
||||
baseFeeXrp: 'baseFeeXRP',
|
||||
reserveBaseXrp: 'reserveBaseXRP',
|
||||
reserveIncXrp: 'reserveIncrementXRP',
|
||||
seq: 'ledgerVersion'
|
||||
});
|
||||
info.validatedLedger.baseFeeXRP =
|
||||
info.validatedLedger.baseFeeXRP.toString();
|
||||
info.validatedLedger.reserveBaseXRP =
|
||||
info.validatedLedger.reserveBaseXRP.toString();
|
||||
info.validatedLedger.reserveIncrementXRP =
|
||||
info.validatedLedger.reserveIncrementXRP.toString();
|
||||
}
|
||||
return info;
|
||||
});
|
||||
}
|
||||
|
||||
9
src/ledger/parse/amendment.js
Normal file
9
src/ledger/parse/amendment.js
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'; // eslint-disable-line strict
|
||||
|
||||
function parseAmendment(tx: Object) {
|
||||
return {
|
||||
amendment: tx.Amendment
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = parseAmendment;
|
||||
15
src/ledger/parse/fee-update.js
Normal file
15
src/ledger/parse/fee-update.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const BigNumber = require('bignumber.js');
|
||||
const {dropsToXrp} = require('./utils');
|
||||
|
||||
function parseFeeUpdate(tx: Object) {
|
||||
const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString();
|
||||
return {
|
||||
baseFeeXRP: dropsToXrp(baseFeeDrops),
|
||||
referenceFeeUnits: tx.ReferenceFeeUnits,
|
||||
reserveBaseXRP: dropsToXrp(tx.ReserveBase),
|
||||
reserveIncrementXRP: dropsToXrp(tx.ReserveIncrement)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = parseFeeUpdate;
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const parsePayment = require('./payment');
|
||||
@@ -11,6 +11,8 @@ const parseSuspendedPaymentCreation = require('./suspended-payment-creation');
|
||||
const parseSuspendedPaymentExecution = require('./suspended-payment-execution');
|
||||
const parseSuspendedPaymentCancellation =
|
||||
require('./suspended-payment-cancellation');
|
||||
const parseFeeUpdate = require('./fee-update');
|
||||
const parseAmendment = require('./amendment');
|
||||
|
||||
function parseTransactionType(type) {
|
||||
const mapping = {
|
||||
@@ -23,7 +25,9 @@ function parseTransactionType(type) {
|
||||
SuspendedPaymentCreate: 'suspendedPaymentCreation',
|
||||
SuspendedPaymentFinish: 'suspendedPaymentExecution',
|
||||
SuspendedPaymentCancel: 'suspendedPaymentCancellation',
|
||||
SignerListSet: 'settings'
|
||||
SignerListSet: 'settings',
|
||||
SetFee: 'feeUpdate', // pseudo-transaction
|
||||
EnableAmendment: 'amendment' // pseudo-transaction
|
||||
};
|
||||
return mapping[type] || null;
|
||||
}
|
||||
@@ -38,7 +42,9 @@ function parseTransaction(tx: Object): Object {
|
||||
'settings': parseSettings,
|
||||
'suspendedPaymentCreation': parseSuspendedPaymentCreation,
|
||||
'suspendedPaymentExecution': parseSuspendedPaymentExecution,
|
||||
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation
|
||||
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation,
|
||||
'feeUpdate': parseFeeUpdate,
|
||||
'amendment': parseAmendment
|
||||
};
|
||||
const parser = mapping[type];
|
||||
assert(parser !== undefined, 'Unrecognized transaction type');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const parseTransaction = require('./parse/transaction');
|
||||
@@ -13,15 +13,18 @@ function attachTransactionDate(connection: Connection, tx: Object
|
||||
return Promise.resolve(tx);
|
||||
}
|
||||
|
||||
if (!tx.ledger_index) {
|
||||
const ledgerVersion = tx.ledger_index || tx.LedgerSequence;
|
||||
|
||||
if (!ledgerVersion) {
|
||||
return new Promise(() => {
|
||||
throw new errors.NotFoundError('ledger_index not found in tx');
|
||||
throw new errors.NotFoundError(
|
||||
'ledger_index and LedgerSequence not found in tx');
|
||||
});
|
||||
}
|
||||
|
||||
const request = {
|
||||
command: 'ledger',
|
||||
ledger_index: tx.ledger_index
|
||||
ledger_index: ledgerVersion
|
||||
};
|
||||
|
||||
return connection.request(request).then(data => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
@@ -12,7 +12,7 @@ function isImmediateRejection(engineResult: string): boolean {
|
||||
// if the required fee changes (this does not occur at the time of
|
||||
// this writing, but it could change in the future)
|
||||
// all other error classes can potentially result in transcation validation
|
||||
return _.startsWith(engineResult, 'tem') || _.startsWith(engineResult, 'tej');
|
||||
return _.startsWith(engineResult, 'tem');
|
||||
}
|
||||
|
||||
function formatSubmitResponse(response) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert-diff');
|
||||
const setupAPI = require('./setup-api');
|
||||
@@ -708,6 +708,21 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('getTransaction - amendment', function() {
|
||||
const hash =
|
||||
'A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F';
|
||||
return this.api.getTransaction(hash).then(result => {
|
||||
assert.deepEqual(result, responses.getTransaction.amendment);
|
||||
});
|
||||
});
|
||||
|
||||
it('getTransaction - feeUpdate', function() {
|
||||
const hash =
|
||||
'C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF';
|
||||
return this.api.getTransaction(hash).then(result => {
|
||||
assert.deepEqual(result, responses.getTransaction.feeUpdate);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('getTransactions', function() {
|
||||
@@ -981,6 +996,19 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('getServerInfo - no validated ledger', function() {
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: {serverInfoWithoutValidated: true}
|
||||
}));
|
||||
|
||||
return this.api.getServerInfo().then(info => {
|
||||
assert.strictEqual(info.networkLedger, 'waiting');
|
||||
}).catch(error => {
|
||||
assert(false, 'Should not throw Error, got ' + String(error));
|
||||
});
|
||||
});
|
||||
|
||||
it('getFee', function() {
|
||||
return this.api.getFee().then(fee => {
|
||||
assert.strictEqual(fee, '0.000012');
|
||||
|
||||
@@ -194,49 +194,81 @@ describe('Connection', function() {
|
||||
}, 1);
|
||||
});
|
||||
|
||||
it('reconnect on several unexpected close', function(done) {
|
||||
if (process.browser) {
|
||||
// can't be tested in browser this way, so skipping
|
||||
done();
|
||||
return;
|
||||
}
|
||||
this.timeout(7000);
|
||||
const self = this;
|
||||
function breakConnection() {
|
||||
setTimeout(() => {
|
||||
self.mockRippled.close();
|
||||
setTimeout(() => {
|
||||
self.mockRippled = setupAPI.createMockRippled(self._mockedServerPort);
|
||||
}, 1500);
|
||||
}, 21);
|
||||
}
|
||||
|
||||
let connectsCount = 0;
|
||||
let disconnectsCount = 0;
|
||||
let code = 0;
|
||||
this.api.connection.on('disconnected', _code => {
|
||||
code = _code;
|
||||
disconnectsCount += 1;
|
||||
describe('reconnection test', function() {
|
||||
beforeEach(function() {
|
||||
this.api.connection.__workingUrl = this.api.connection._url;
|
||||
this.api.connection.__doReturnBad = function() {
|
||||
this._url = this.__badUrl;
|
||||
const self = this;
|
||||
function onReconnect(num) {
|
||||
if (num >= 2) {
|
||||
self._url = self.__workingUrl;
|
||||
self.removeListener('reconnecting', onReconnect);
|
||||
}
|
||||
}
|
||||
this.on('reconnecting', onReconnect);
|
||||
};
|
||||
});
|
||||
this.api.connection.on('connected', () => {
|
||||
connectsCount += 1;
|
||||
if (connectsCount < 3) {
|
||||
breakConnection();
|
||||
}
|
||||
if (connectsCount === 3) {
|
||||
if (disconnectsCount !== 3) {
|
||||
done(new Error('disconnectsCount must be equal to 3 (got ' +
|
||||
disconnectsCount + ' instead)'));
|
||||
} else if (code !== 1006) {
|
||||
done(new Error('disconnect must send code 1006 (got ' + code +
|
||||
' instead)'));
|
||||
} else {
|
||||
|
||||
afterEach(function() {
|
||||
|
||||
});
|
||||
|
||||
it('reconnect on several unexpected close', function(done) {
|
||||
if (process.browser) {
|
||||
const phantomTest = /PhantomJS/;
|
||||
if (phantomTest.test(navigator.userAgent)) {
|
||||
// inside PhantomJS this one just hangs, so skip as not very relevant
|
||||
done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.timeout(70001);
|
||||
const self = this;
|
||||
self.api.connection.__badUrl = 'ws://testripple.circleci.com:129';
|
||||
function breakConnection() {
|
||||
self.api.connection.__doReturnBad();
|
||||
self.api.connection._send(JSON.stringify({
|
||||
command: 'test_command',
|
||||
data: {disconnectIn: 10}
|
||||
}));
|
||||
}
|
||||
|
||||
breakConnection();
|
||||
let connectsCount = 0;
|
||||
let disconnectsCount = 0;
|
||||
let reconnectsCount = 0;
|
||||
let code = 0;
|
||||
this.api.connection.on('reconnecting', () => {
|
||||
reconnectsCount += 1;
|
||||
});
|
||||
this.api.connection.on('disconnected', _code => {
|
||||
code = _code;
|
||||
disconnectsCount += 1;
|
||||
});
|
||||
const num = 3;
|
||||
this.api.connection.on('connected', () => {
|
||||
connectsCount += 1;
|
||||
if (connectsCount < num) {
|
||||
breakConnection();
|
||||
}
|
||||
if (connectsCount === num) {
|
||||
if (disconnectsCount !== num) {
|
||||
done(new Error('disconnectsCount must be equal to ' + num +
|
||||
'(got ' + disconnectsCount + ' instead)'));
|
||||
} else if (reconnectsCount !== num * 2) {
|
||||
done(new Error('reconnectsCount must be equal to ' + num * 2 +
|
||||
' (got ' + reconnectsCount + ' instead)'));
|
||||
} else if (code !== 1006) {
|
||||
done(new Error('disconnect must send code 1006 (got ' + code +
|
||||
' instead)'));
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
breakConnection();
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit disconnected event with code 1000 (CLOSE_NORMAL)',
|
||||
@@ -252,16 +284,17 @@ describe('Connection', function() {
|
||||
it('should emit disconnected event with code 1006 (CLOSE_ABNORMAL)',
|
||||
function(done
|
||||
) {
|
||||
if (process.browser) {
|
||||
// can't be tested in browser this way, so skipping
|
||||
done();
|
||||
return;
|
||||
}
|
||||
this.api.once('error', error => {
|
||||
done(new Error('should not throw error, got ' + String(error)));
|
||||
});
|
||||
this.api.once('disconnected', code => {
|
||||
assert.strictEqual(code, 1006);
|
||||
done();
|
||||
});
|
||||
this.mockRippled.close();
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'test_command',
|
||||
data: {disconnectIn: 10}
|
||||
}));
|
||||
});
|
||||
|
||||
it('should emit connected event on after reconnect', function(done) {
|
||||
@@ -379,4 +412,50 @@ describe('Connection', function() {
|
||||
});
|
||||
this.api.connection._ws.emit('message', JSON.stringify(message));
|
||||
});
|
||||
|
||||
it('should throw RippledNotInitializedError if server does not have ' +
|
||||
'validated ledgers',
|
||||
function() {
|
||||
this.timeout(3000);
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'global_config',
|
||||
data: {returnEmptySubscribeRequest: 1}
|
||||
}));
|
||||
|
||||
const api = new RippleAPI({server: this.api.connection._url});
|
||||
return api.connect().then(() => {
|
||||
assert(false, 'Must have thrown!');
|
||||
}, error => {
|
||||
assert(error instanceof this.api.errors.RippledNotInitializedError,
|
||||
'Must throw RippledNotInitializedError, got instead ' + String(error));
|
||||
});
|
||||
});
|
||||
|
||||
it('should try to reconnect on empty subscribe response on reconnect',
|
||||
function(done) {
|
||||
this.timeout(23000);
|
||||
|
||||
this.api.on('error', error => {
|
||||
done(error || new Error('Should not emit error.'));
|
||||
});
|
||||
let disconncedCount = 0;
|
||||
this.api.on('connected', () => {
|
||||
done(disconncedCount !== 1 ?
|
||||
new Error('Wrong number of disconnects') : undefined);
|
||||
});
|
||||
this.api.on('disconnected', () => {
|
||||
disconncedCount++;
|
||||
});
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'global_config',
|
||||
data: {returnEmptySubscribeRequest: 3}
|
||||
}));
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'test_command',
|
||||
data: {disconnectIn: 10}
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
17
test/fixtures/responses/get-transaction-amendment.json
vendored
Normal file
17
test/fixtures/responses/get-transaction-amendment.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"type": "amendment",
|
||||
"address": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||
"sequence": 0,
|
||||
"id": "A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F",
|
||||
"specification": {
|
||||
"amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE"
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2016-05-05T16:33:30.000Z",
|
||||
"fee": "0",
|
||||
"balanceChanges": {},
|
||||
"orderbookChanges": {},
|
||||
"indexInLedger": 0
|
||||
}
|
||||
}
|
||||
21
test/fixtures/responses/get-transaction-fee-update.json
vendored
Normal file
21
test/fixtures/responses/get-transaction-fee-update.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"type": "feeUpdate",
|
||||
"address": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||
"sequence": 0,
|
||||
"id": "C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF",
|
||||
"specification": {
|
||||
"baseFeeXRP": "0.00001",
|
||||
"referenceFeeUnits": 10,
|
||||
"reserveBaseXRP": "50",
|
||||
"reserveIncrementXRP": "12.5"
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2014-08-08T16:57:50.000Z",
|
||||
"fee": "0",
|
||||
"balanceChanges": {},
|
||||
"orderbookChanges": {},
|
||||
"ledgerVersion": 3717633,
|
||||
"indexInLedger": 3
|
||||
}
|
||||
}
|
||||
6
test/fixtures/responses/index.js
vendored
6
test/fixtures/responses/index.js
vendored
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line strict
|
||||
|
||||
module.exports = {
|
||||
generateAddress: require('./generate-address.json'),
|
||||
@@ -43,7 +43,9 @@ module.exports = {
|
||||
suspendedPaymentExecution:
|
||||
require('./get-transaction-suspended-payment-execution.json'),
|
||||
suspendedPaymentExecutionSimple:
|
||||
require('./get-transaction-suspended-payment-execution-simple.json')
|
||||
require('./get-transaction-suspended-payment-execution-simple.json'),
|
||||
amendment: require('./get-transaction-amendment.json'),
|
||||
feeUpdate: require('./get-transaction-fee-update.json')
|
||||
},
|
||||
getTransactions: {
|
||||
normal: require('./get-transactions.json'),
|
||||
|
||||
7
test/fixtures/rippled/empty.json
vendored
Normal file
7
test/fixtures/rippled/empty.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
}
|
||||
}
|
||||
9
test/fixtures/rippled/index.js
vendored
9
test/fixtures/rippled/index.js
vendored
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
module.exports = {
|
||||
submit: {
|
||||
@@ -12,6 +12,7 @@ module.exports = {
|
||||
withSettingsTx: require('./ledger-with-settings-tx'),
|
||||
withStateAsHashes: require('./ledger-with-state-as-hashes')
|
||||
},
|
||||
empty: require('./empty'),
|
||||
subscribe: require('./subscribe'),
|
||||
unsubscribe: require('./unsubscribe'),
|
||||
account_info: {
|
||||
@@ -31,6 +32,8 @@ module.exports = {
|
||||
},
|
||||
server_info: {
|
||||
normal: require('./server-info'),
|
||||
noValidated: require('./server-info-no-validated'),
|
||||
syncing: require('./server-info-syncing'),
|
||||
error: require('./server-info-error')
|
||||
},
|
||||
path_find: {
|
||||
@@ -69,6 +72,8 @@ module.exports = {
|
||||
require('./tx/suspended-payment-execution-simple.json'),
|
||||
Unrecognized: require('./tx/unrecognized.json'),
|
||||
NoMeta: require('./tx/no-meta.json'),
|
||||
LedgerZero: require('./tx/ledger-zero.json')
|
||||
LedgerZero: require('./tx/ledger-zero.json'),
|
||||
Amendment: require('./tx/amendment.json'),
|
||||
SetFee: require('./tx/set-fee.json')
|
||||
}
|
||||
};
|
||||
|
||||
31
test/fixtures/rippled/server-info-no-validated.json
vendored
Normal file
31
test/fixtures/rippled/server-info-no-validated.json
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"info": {
|
||||
"build_version": "0.30.1-hf2",
|
||||
"complete_ledgers": "empty",
|
||||
"hostid": "ARTS",
|
||||
"io_latency_ms": 1,
|
||||
"last_close": {
|
||||
"converge_time_s": 2.007,
|
||||
"proposers": 4
|
||||
},
|
||||
"load_factor": 1,
|
||||
"peers": 53,
|
||||
"pubkey_node": "n94wWvFUmaKGYrKUGgpv1DyYgDeXRGdACkNQaSe7zJiy5Znio7UC",
|
||||
"server_state": "connected",
|
||||
"network_ledger" : "waiting",
|
||||
"closed_ledger": {
|
||||
"age": 5,
|
||||
"base_fee_xrp": 0.00001,
|
||||
"hash": "4482DEE5362332F54A4036ED57EE1767C9F33CF7CE5A6670355C16CECE381D46",
|
||||
"reserve_base_xrp": 20,
|
||||
"reserve_inc_xrp": 5,
|
||||
"seq": 6595042
|
||||
},
|
||||
"validation_quorum": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
30
test/fixtures/rippled/server-info-syncing.json
vendored
Normal file
30
test/fixtures/rippled/server-info-syncing.json
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"info": {
|
||||
"build_version": "0.24.0-rc1",
|
||||
"complete_ledgers": "32570-6595042",
|
||||
"hostid": "ARTS",
|
||||
"io_latency_ms": 1,
|
||||
"last_close": {
|
||||
"converge_time_s": 2.007,
|
||||
"proposers": 4
|
||||
},
|
||||
"load_factor": 1,
|
||||
"peers": 53,
|
||||
"pubkey_node": "n94wWvFUmaKGYrKUGgpv1DyYgDeXRGdACkNQaSe7zJiy5Znio7UC",
|
||||
"server_state": "syncing",
|
||||
"validated_ledger": {
|
||||
"age": 5,
|
||||
"base_fee_xrp": 0.00001,
|
||||
"hash": "4482DEE5362332F54A4036ED57EE1767C9F33CF7CE5A6670355C16CECE381D46",
|
||||
"reserve_base_xrp": 20,
|
||||
"reserve_inc_xrp": 5,
|
||||
"seq": 6595042
|
||||
},
|
||||
"validation_quorum": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
40
test/fixtures/rippled/tx/amendment.json
vendored
Normal file
40
test/fixtures/rippled/tx/amendment.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||
"Amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE",
|
||||
"Fee": "0",
|
||||
"Flags": 65536,
|
||||
"date": 515781210,
|
||||
"LedgerSequence": 20889601,
|
||||
"Sequence": 0,
|
||||
"SigningPubKey": "",
|
||||
"TransactionType": "EnableAmendment",
|
||||
"hash": "A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Amendments",
|
||||
"LedgerIndex": "7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4",
|
||||
"NewFields": {
|
||||
"Majorities": [
|
||||
{
|
||||
"Majority": {
|
||||
"Amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE",
|
||||
"CloseTime": 515781202
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
43
test/fixtures/rippled/tx/set-fee.json
vendored
Normal file
43
test/fixtures/rippled/tx/set-fee.json
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"hash": "C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF",
|
||||
"ledger_index": 3717633,
|
||||
"date": 460832270,
|
||||
"TransactionType": "SetFee",
|
||||
"Sequence": 0,
|
||||
"ReferenceFeeUnits": 10,
|
||||
"ReserveBase": 50000000,
|
||||
"ReserveIncrement": 12500000,
|
||||
"BaseFee": "000000000000000A",
|
||||
"Fee": "0",
|
||||
"SigningPubKey": "",
|
||||
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||
"meta": {
|
||||
"TransactionIndex": 3,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "FeeSettings",
|
||||
"LedgerIndex": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651",
|
||||
"PreviousFields": {
|
||||
"ReserveBase": 20000000,
|
||||
"ReserveIncrement": 5000000
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"ReferenceFeeUnits": 10,
|
||||
"ReserveBase": 50000000,
|
||||
"ReserveIncrement": 12500000,
|
||||
"BaseFee": "000000000000000A"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
const WebSocketServer = require('ws').Server;
|
||||
@@ -9,6 +9,7 @@ const hashes = require('./fixtures/hashes');
|
||||
const transactionsResponse = require('./fixtures/rippled/account-tx');
|
||||
const accountLinesResponse = require('./fixtures/rippled/account-lines');
|
||||
const fullLedger = require('./fixtures/rippled/ledger-full-38129.json');
|
||||
const {getFreePort} = require('./utils/net-utils');
|
||||
|
||||
function isUSD(json) {
|
||||
return json === 'USD' || json === '0000000000000000000000005553440000000000';
|
||||
@@ -46,7 +47,7 @@ function createLedgerResponse(request, response) {
|
||||
return JSON.stringify(newResponse);
|
||||
}
|
||||
|
||||
module.exports = function(port) {
|
||||
module.exports = function createMockRippled(port) {
|
||||
const mock = new WebSocketServer({port: port});
|
||||
_.assign(mock, EventEmitter2.prototype);
|
||||
|
||||
@@ -71,6 +72,11 @@ module.exports = function(port) {
|
||||
};
|
||||
|
||||
mock.on('connection', function(conn) {
|
||||
if (mock.config.breakNextConnection) {
|
||||
mock.config.breakNextConnection = false;
|
||||
conn.terminate();
|
||||
return;
|
||||
}
|
||||
this.socket = conn;
|
||||
conn.config = {};
|
||||
conn.on('message', function(requestJSON) {
|
||||
@@ -79,6 +85,8 @@ module.exports = function(port) {
|
||||
});
|
||||
});
|
||||
|
||||
mock.config = {};
|
||||
|
||||
mock.onAny(function() {
|
||||
if (this.event.indexOf('request_') !== 0) {
|
||||
return;
|
||||
@@ -101,6 +109,34 @@ module.exports = function(port) {
|
||||
conn.config = _.assign(conn.config, request.data);
|
||||
});
|
||||
|
||||
mock.on('request_test_command', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'test_command');
|
||||
if (request.data.disconnectIn) {
|
||||
setTimeout(conn.terminate.bind(conn), request.data.disconnectIn);
|
||||
} else if (request.data.openOnOtherPort) {
|
||||
getFreePort().then(newPort => {
|
||||
createMockRippled(newPort);
|
||||
conn.send(createResponse(request, {status: 'success', type: 'response',
|
||||
result: {port: newPort}}
|
||||
));
|
||||
});
|
||||
} else if (request.data.closeServerAndReopen) {
|
||||
setTimeout(() => {
|
||||
conn.terminate();
|
||||
close.call(mock, () => {
|
||||
setTimeout(() => {
|
||||
createMockRippled(port);
|
||||
}, request.data.closeServerAndReopen);
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
|
||||
mock.on('request_global_config', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'global_config');
|
||||
mock.config = _.assign(conn.config, request.data);
|
||||
});
|
||||
|
||||
mock.on('request_echo', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'echo');
|
||||
conn.send(JSON.stringify(request.data));
|
||||
@@ -112,6 +148,11 @@ module.exports = function(port) {
|
||||
conn.send(createResponse(request, fixtures.server_info.error));
|
||||
} else if (conn.config.disconnectOnServerInfo) {
|
||||
conn.close();
|
||||
} else if (conn.config.serverInfoWithoutValidated) {
|
||||
conn.send(createResponse(request, fixtures.server_info.noValidated));
|
||||
} else if (mock.config.returnSyncingServerInfo) {
|
||||
mock.config.returnSyncingServerInfo--;
|
||||
conn.send(createResponse(request, fixtures.server_info.syncing));
|
||||
} else {
|
||||
conn.send(createResponse(request, fixtures.server_info.normal));
|
||||
}
|
||||
@@ -119,7 +160,10 @@ module.exports = function(port) {
|
||||
|
||||
mock.on('request_subscribe', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'subscribe');
|
||||
if (request.accounts) {
|
||||
if (mock.config.returnEmptySubscribeRequest) {
|
||||
mock.config.returnEmptySubscribeRequest--;
|
||||
conn.send(createResponse(request, fixtures.empty));
|
||||
} else if (request.accounts) {
|
||||
assert(_.indexOf(_.values(addresses), request.accounts[0]) !== -1);
|
||||
}
|
||||
conn.send(createResponse(request, fixtures.subscribe));
|
||||
@@ -248,6 +292,12 @@ module.exports = function(port) {
|
||||
} else if (request.transaction ===
|
||||
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA13') {
|
||||
conn.send(createResponse(request, fixtures.tx.LedgerZero));
|
||||
} else if (request.transaction ===
|
||||
'A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F') {
|
||||
conn.send(createResponse(request, fixtures.tx.Amendment));
|
||||
} else if (request.transaction ===
|
||||
'C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF') {
|
||||
conn.send(createResponse(request, fixtures.tx.SetFee));
|
||||
} else {
|
||||
assert(false, 'Unrecognized transaction hash: ' + request.transaction);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const {RippleAPI, RippleAPIBroadcast} = require('ripple-api');
|
||||
const ledgerClosed = require('./fixtures/rippled/ledger-close');
|
||||
@@ -8,12 +8,22 @@ const port = 34371;
|
||||
const baseUrl = 'ws://testripple.circleci.com:';
|
||||
|
||||
function setup(port_ = port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api = new RippleAPI({server: baseUrl + port_});
|
||||
this.api.connect().then(() => {
|
||||
this.api.once('ledger', () => resolve());
|
||||
this.api.connection._ws.emit('message', JSON.stringify(ledgerClosed));
|
||||
}).catch(reject);
|
||||
const tapi = new RippleAPI({server: baseUrl + port_});
|
||||
return tapi.connect().then(() => {
|
||||
return tapi.connection.request({
|
||||
command: 'test_command',
|
||||
data: {openOnOtherPort: true}
|
||||
});
|
||||
}).then(got => {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api = new RippleAPI({server: baseUrl + got.port});
|
||||
this.api.connect().then(() => {
|
||||
this.api.once('ledger', () => resolve());
|
||||
this.api.connection._ws.emit('message', JSON.stringify(ledgerClosed));
|
||||
}).catch(reject);
|
||||
});
|
||||
}).then(() => {
|
||||
return tapi.disconnect();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,6 +43,7 @@ function teardown() {
|
||||
if (this.api.isConnected()) {
|
||||
return this.api.disconnect();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -1,29 +1,11 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const net = require('net');
|
||||
const RippleAPI = require('ripple-api').RippleAPI;
|
||||
const RippleAPIBroadcast = require('ripple-api').RippleAPIBroadcast;
|
||||
const ledgerClosed = require('./fixtures/rippled/ledger-close');
|
||||
const createMockRippled = require('./mock-rippled');
|
||||
const {getFreePort} = require('./utils/net-utils');
|
||||
|
||||
// using a free port instead of a constant port enables parallelization
|
||||
function getFreePort() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = net.createServer();
|
||||
let port;
|
||||
server.on('listening', function() {
|
||||
port = server.address().port;
|
||||
server.close();
|
||||
});
|
||||
server.on('close', function() {
|
||||
resolve(port);
|
||||
});
|
||||
server.on('error', function(error) {
|
||||
reject(error);
|
||||
});
|
||||
server.listen(0);
|
||||
});
|
||||
}
|
||||
|
||||
function setupMockRippledConnection(testcase, port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
26
test/utils/net-utils.js
Normal file
26
test/utils/net-utils.js
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const net = require('net');
|
||||
|
||||
// using a free port instead of a constant port enables parallelization
|
||||
function getFreePort() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = net.createServer();
|
||||
let port;
|
||||
server.on('listening', function() {
|
||||
port = server.address().port;
|
||||
server.close();
|
||||
});
|
||||
server.on('close', function() {
|
||||
resolve(port);
|
||||
});
|
||||
server.on('error', function(error) {
|
||||
reject(error);
|
||||
});
|
||||
server.listen(0);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFreePort
|
||||
};
|
||||
Reference in New Issue
Block a user