mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 03:26:01 +00:00
Support a "no_server" flag in test config.
* Will use a running instance of rippled (possibly in a debugger). * Modify all tests to respect the server_default value. * Fail test if new account already exists and has a balance. * README.md with instructions for advanced test debugging, particularly using no_server.
This commit is contained in:
committed by
Nik Bougalis
parent
7f5f73887d
commit
a5df3f1747
79
test/README.md
Normal file
79
test/README.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Integration tests
|
||||||
|
|
||||||
|
## Basic usage.
|
||||||
|
|
||||||
|
Documentation for installation of dependencies and running these
|
||||||
|
tests can be found with the
|
||||||
|
[_Rippled build instructions_][unit_testing].
|
||||||
|
(Also for [_Windows_][windows_unit_testing],
|
||||||
|
[_OS X_][osx_unit_testing],
|
||||||
|
or [_Ubuntu_][ubuntu_unit_testing].)
|
||||||
|
|
||||||
|
## Advanced usage.
|
||||||
|
|
||||||
|
These instructions assume familiarity with the instructions linked above.
|
||||||
|
|
||||||
|
### Debugging rippled
|
||||||
|
|
||||||
|
By default, each test will start and stop an independent instance of `rippled`.
|
||||||
|
This ensures that each test is run against the known
|
||||||
|
[_genesis ledger_][genesis_ledger].
|
||||||
|
|
||||||
|
To use a running `rippled`, particularly one running in a debugger, follow
|
||||||
|
these steps:
|
||||||
|
|
||||||
|
1. Make a copy the example configuration file: `cp -i test/config-example.js test/config.js`
|
||||||
|
|
||||||
|
2. Edit `test/config.js` to select the "debug" server configuration.
|
||||||
|
* Change the existing default server to: `exports.server_default = "debug";`
|
||||||
|
(near the top of the file).
|
||||||
|
|
||||||
|
3. Create a `rippled.cfg` file for the tests.
|
||||||
|
1. Run `npm test`. The tests will fail. **This failure is expected.**
|
||||||
|
2. Copy and/or rename the `tmp/server/debug/rippled.cfg` file to somewhere
|
||||||
|
convenient.
|
||||||
|
|
||||||
|
4. Start `rippled` (in a debugger) with command line options
|
||||||
|
`-a -v --conf <rippled-created-above.cfg>`.
|
||||||
|
|
||||||
|
5. Set any desired breakpoints in the `rippled` source.
|
||||||
|
|
||||||
|
6. Running one test per [_genesis ledger_][genesis_ledger] is highly recommended.
|
||||||
|
If the relevant `.js` file contains more than one test, change `test(` to
|
||||||
|
`test.only(` for the single desired test.
|
||||||
|
* To run multiple tests, change `test(` to `test.skip(` for any undesired tests
|
||||||
|
in the .js file.
|
||||||
|
|
||||||
|
7. Start test(s) in the [_node-inspector_][node_inspector] debugger.
|
||||||
|
(Note that the tests can be run without the debugger, but there will probably
|
||||||
|
be problems with timeouts or reused ledgers).
|
||||||
|
1. `node_modules/node-inspector/bin/inspector.js &`
|
||||||
|
2. `mocha --debug --debug-brk test/<testfile.js>`
|
||||||
|
3. Browse to http://127.0.0.1:8080/debug?port=5858 in a browser supported
|
||||||
|
by [_node-inspector_][node_inspector] (i.e. Chrome or Safari).
|
||||||
|
|
||||||
|
8. To run multiple tests, put a breakpoint in the following function:
|
||||||
|
* File `testutils.js` -> function `build_teardown()` -> nested function
|
||||||
|
`teardown()` -> nested series function `stop_server()`.
|
||||||
|
* When this breakpoint is
|
||||||
|
hit, stop and restart `rippled`.
|
||||||
|
|
||||||
|
9. Use the [_node-inspector UI_][node_inspector_ui] to step through and run
|
||||||
|
the test(s) until control is handed off to `rippled`. When the request is
|
||||||
|
finished control will be handed back to node-inspector, which may or may not
|
||||||
|
stop depending on which breakpoints are set.
|
||||||
|
|
||||||
|
### After debugging
|
||||||
|
|
||||||
|
1. To return to the default behavior, edit `test/config.js` and change the
|
||||||
|
default server back to its original value: `exports.server_default = "alpha";`.
|
||||||
|
* Alternately, delete `test/config.js`.
|
||||||
|
|
||||||
|
[unit_testing]: https://wiki.ripple.com/Rippled_build_instructions#Unit_testing
|
||||||
|
[windows_unit_testing]: https://wiki.ripple.com/Visual_Studio_2013_Build_Instructions#Unit_Tests_.28Recommended.29
|
||||||
|
[osx_unit_testing]: https://wiki.ripple.com/OSX_Build_Instructions#System_Tests_.28Recommended.29
|
||||||
|
[ubuntu_unit_testing]: https://wiki.ripple.com/Ubuntu_build_instructions#System_Tests_.28Recommended.29
|
||||||
|
[genesis_ledger]: https://wiki.ripple.com/Genesis_ledger
|
||||||
|
[node_inspector]: https://wiki.ripple.com/Rippled_build_instructions#node-inspector
|
||||||
|
[node_inspector_ui]: https://github.com/node-inspector/node-inspector/blob/master/README.md
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
|
var extend = require('extend');
|
||||||
var testconfig = require("./testconfig.js");
|
var testconfig = require("./testconfig.js");
|
||||||
|
|
||||||
exports.accounts = testconfig.accounts;
|
exports.accounts = testconfig.accounts;
|
||||||
@@ -59,6 +60,11 @@ exports.servers = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.servers.debug = extend({
|
||||||
|
no_server: true,
|
||||||
|
debug_logfile: "debug.log"
|
||||||
|
}, exports.servers.alpha);
|
||||||
|
|
||||||
exports.http_servers = {
|
exports.http_servers = {
|
||||||
// A local test server
|
// A local test server
|
||||||
"zed" : {
|
"zed" : {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ suite('JSON-RPC', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('server info', function(done) {
|
test('server info', function(done) {
|
||||||
var rippled_config = config.servers.alpha;
|
var rippled_config = testutils.get_server_config(config);
|
||||||
var client = jsonrpc.client("http://" + rippled_config.rpc_ip + ":" + rippled_config.rpc_port);
|
var client = jsonrpc.client("http://" + rippled_config.rpc_ip + ":" + rippled_config.rpc_port);
|
||||||
|
|
||||||
client.call('server_info', [ ], function (result) {
|
client.call('server_info', [ ], function (result) {
|
||||||
@@ -82,7 +82,7 @@ suite('JSON-RPC', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('subscribe server', function(done) {
|
test('subscribe server', function(done) {
|
||||||
var rippled_config = config.servers.alpha;
|
var rippled_config = testutils.get_server_config(config);
|
||||||
var client = jsonrpc.client("http://" + rippled_config.rpc_ip + ":" + rippled_config.rpc_port);
|
var client = jsonrpc.client("http://" + rippled_config.rpc_ip + ":" + rippled_config.rpc_port);
|
||||||
var http_config = config.http_servers["zed"];
|
var http_config = config.http_servers["zed"];
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ suite('JSON-RPC', function() {
|
|||||||
test('subscribe ledger', function(done) {
|
test('subscribe ledger', function(done) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var rippled_config = config.servers.alpha;
|
var rippled_config = testutils.get_server_config(config);
|
||||||
var client = jsonrpc.client("http://" + rippled_config.rpc_ip + ":" + rippled_config.rpc_port);
|
var client = jsonrpc.client("http://" + rippled_config.rpc_ip + ":" + rippled_config.rpc_port);
|
||||||
var http_config = config.http_servers["zed"];
|
var http_config = config.http_servers["zed"];
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ var config = testutils.init_config();
|
|||||||
|
|
||||||
suite('Standalone server startup', function() {
|
suite('Standalone server startup', function() {
|
||||||
test('server start and stop', function(done) {
|
test('server start and stop', function(done) {
|
||||||
var cfg = extend({}, config.default_server_config, config.servers.alpha);
|
var host = config.server_default;
|
||||||
var alpha = Server.from_config("alpha", cfg);
|
var cfg = testutils.get_server_config(config, host);
|
||||||
|
var alpha = Server.from_config(host, cfg);
|
||||||
alpha.on('started', function () {
|
alpha.on('started', function () {
|
||||||
alpha.on('stopped', function () {
|
alpha.on('stopped', function () {
|
||||||
done();
|
done();
|
||||||
|
|||||||
@@ -23,6 +23,14 @@ function init_config() {
|
|||||||
return require('ripple-lib').config.load(get_config());
|
return require('ripple-lib').config.load(get_config());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.get_server_config =
|
||||||
|
get_server_config =
|
||||||
|
function(config, host) {
|
||||||
|
config = config || init_config();
|
||||||
|
host = host || config.server_default;
|
||||||
|
return extend({}, config.default_server_config, config.servers[host]);
|
||||||
|
}
|
||||||
|
|
||||||
function prepare_tests(tests, fn) {
|
function prepare_tests(tests, fn) {
|
||||||
var tests = typeof tests === 'string' ? [ tests ] : tests;
|
var tests = typeof tests === 'string' ? [ tests ] : tests;
|
||||||
var result = [ ];
|
var result = [ ];
|
||||||
@@ -88,12 +96,12 @@ function build_setup(opts, host) {
|
|||||||
|
|
||||||
var steps = [
|
var steps = [
|
||||||
function run_server(callback) {
|
function run_server(callback) {
|
||||||
if (opts.no_server) {
|
var server_config = get_server_config(config, host);
|
||||||
|
|
||||||
|
if (opts.no_server || server_config.no_server) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
var server_config = extend({}, config.default_server_config, config.servers[host]);
|
|
||||||
|
|
||||||
data.server = Server.from_config(host, server_config, !!opts.verbose_server);
|
data.server = Server.from_config(host, server_config, !!opts.verbose_server);
|
||||||
|
|
||||||
// Setting undefined is a noop here
|
// Setting undefined is a noop here
|
||||||
@@ -151,6 +159,7 @@ function build_teardown(host) {
|
|||||||
function teardown(done) {
|
function teardown(done) {
|
||||||
var data = this.store[host];
|
var data = this.store[host];
|
||||||
var opts = data.opts;
|
var opts = data.opts;
|
||||||
|
var server_config = get_server_config(config, host);
|
||||||
|
|
||||||
var series = [
|
var series = [
|
||||||
function disconnect_websocket(callback) {
|
function disconnect_websocket(callback) {
|
||||||
@@ -162,7 +171,7 @@ function build_teardown(host) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
function stop_server(callback) {
|
function stop_server(callback) {
|
||||||
if (opts.no_server) {
|
if (opts.no_server || server_config.no_server) {
|
||||||
callback();
|
callback();
|
||||||
} else {
|
} else {
|
||||||
data.server.once('stopped', callback)
|
data.server.once('stopped', callback)
|
||||||
@@ -172,7 +181,7 @@ function build_teardown(host) {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!opts.no_server && data.server.stopped) {
|
if (!(opts.no_server || server_config.no_server) && data.server.stopped) {
|
||||||
done()
|
done()
|
||||||
} else {
|
} else {
|
||||||
async.series(series, done);
|
async.series(series, done);
|
||||||
@@ -206,12 +215,9 @@ function account_dump(remote, account, callback) {
|
|||||||
// construct a json result
|
// construct a json result
|
||||||
};
|
};
|
||||||
|
|
||||||
function create_accounts(remote, src, amount, accounts, callback) {
|
exports.fund_account =
|
||||||
assert.strictEqual(arguments.length, 5);
|
fund_account =
|
||||||
|
function(remote, src, account, amount, callback) {
|
||||||
remote.set_account_seq(src, 1);
|
|
||||||
|
|
||||||
async.forEach(accounts, function (account, callback) {
|
|
||||||
// Cache the seq as 1.
|
// Cache the seq as 1.
|
||||||
// Otherwise, when other operations attempt to opperate async against the account they may get confused.
|
// Otherwise, when other operations attempt to opperate async against the account they may get confused.
|
||||||
remote.set_account_seq(account, 1);
|
remote.set_account_seq(account, 1);
|
||||||
@@ -220,17 +226,52 @@ function create_accounts(remote, src, amount, accounts, callback) {
|
|||||||
|
|
||||||
tx.payment(src, account, amount);
|
tx.payment(src, account, amount);
|
||||||
|
|
||||||
tx.once('proposed', function (m) {
|
tx.once('proposed', function (result) {
|
||||||
//console.log('proposed: %s', JSON.stringify(m));
|
//console.log('proposed: %s', JSON.stringify(result));
|
||||||
callback(m.engine_result === 'tesSUCCESS' ? null : new Error());
|
callback(result.engine_result === 'tesSUCCESS' ? null : new Error());
|
||||||
});
|
});
|
||||||
|
|
||||||
tx.once('error', function (m) {
|
tx.once('error', function (result) {
|
||||||
//console.log('error: %s', JSON.stringify(m));
|
//console.log('error: %s', JSON.stringify(result));
|
||||||
callback(m);
|
callback(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
tx.submit();
|
tx.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.create_account =
|
||||||
|
create_account =
|
||||||
|
function(remote, src, account, amount, callback) {
|
||||||
|
// Before creating the account, check if it exists in the ledger.
|
||||||
|
// If it does, regardless of the balance, fail the test, because
|
||||||
|
// the ledger is not in the expected state.
|
||||||
|
var info = remote.requestAccountInfo(account);
|
||||||
|
|
||||||
|
info.once('success', function(result) {
|
||||||
|
// The account exists. Fail by returning an error to callback.
|
||||||
|
callback(new Error("Account " + account + " already exists"));
|
||||||
|
});
|
||||||
|
|
||||||
|
info.once('error', function(result) {
|
||||||
|
if (result.error === "remoteError" && result.remote.error === "actNotFound") {
|
||||||
|
// rippled indicated the account does not exist. Create it by funding it.
|
||||||
|
fund_account(remote, src, account, amount, callback);
|
||||||
|
} else {
|
||||||
|
// Some other error occurred. Pass it up to the callback.
|
||||||
|
callback(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
info.request();
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_accounts(remote, src, amount, accounts, callback) {
|
||||||
|
assert.strictEqual(arguments.length, 5);
|
||||||
|
|
||||||
|
remote.set_account_seq(src, 1);
|
||||||
|
|
||||||
|
async.forEach(accounts, function (account, callback) {
|
||||||
|
create_account(remote, src, account, amount, callback);
|
||||||
}, callback);
|
}, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ suite('WebSocket connection', function() {
|
|||||||
setup(function(done) {
|
setup(function(done) {
|
||||||
this.timeout(2000);
|
this.timeout(2000);
|
||||||
|
|
||||||
var cfg = extend({}, config.default_server_config, config.servers.alpha);
|
var host = config.server_default;
|
||||||
|
var cfg = testutils.get_server_config(config, host);
|
||||||
if (cfg.no_server) {
|
if (cfg.no_server) {
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
server = Server.from_config("alpha", cfg);
|
server = Server.from_config(host, cfg);
|
||||||
server.once('started', done)
|
server.once('started', done)
|
||||||
server.start();
|
server.start();
|
||||||
}
|
}
|
||||||
@@ -24,7 +25,8 @@ suite('WebSocket connection', function() {
|
|||||||
teardown(function(done) {
|
teardown(function(done) {
|
||||||
this.timeout(2000);
|
this.timeout(2000);
|
||||||
|
|
||||||
if (config.servers.alpha.no_server) {
|
var cfg = testutils.get_server_config(config);
|
||||||
|
if (cfg.no_server) {
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
server.on('stopped', done);
|
server.on('stopped', done);
|
||||||
@@ -39,7 +41,8 @@ suite('WebSocket connection', function() {
|
|||||||
// push the measured time out this far.
|
// push the measured time out this far.
|
||||||
this.timeout(3000);
|
this.timeout(3000);
|
||||||
|
|
||||||
var alpha = Remote.from_config("alpha");
|
var host = config.server_default;
|
||||||
|
var alpha = Remote.from_config(host);
|
||||||
|
|
||||||
alpha.on('connected', function () {
|
alpha.on('connected', function () {
|
||||||
alpha.on('disconnected', function () {
|
alpha.on('disconnected', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user