Merge pull request #667 from embark-framework/patch/dev_funds-tests
Patch: Basic unit tests complete for dev_funds
This commit is contained in:
commit
807950d216
|
@ -170,9 +170,8 @@ Blockchain.prototype.run = function() {
|
|||
if (self.onReadyCallback && !self.readyCalled && data.indexOf('WebSocket endpoint opened') > -1) {
|
||||
if (self.isDev) {
|
||||
self.createFundAndUnlockAccounts((err) => {
|
||||
// TODO: this is never called!
|
||||
if(err) console.error('Error creating, unlocking, and funding accounts', err);
|
||||
//self.readyCalled = true;
|
||||
//self.onReadyCallback();
|
||||
});
|
||||
}
|
||||
self.readyCalled = true;
|
||||
|
@ -189,9 +188,10 @@ Blockchain.prototype.run = function() {
|
|||
};
|
||||
|
||||
Blockchain.prototype.createFundAndUnlockAccounts = function(cb) {
|
||||
let devFunds = new DevFunds(this.config);
|
||||
devFunds.createFundAndUnlockAccounts((err) => {
|
||||
cb(err);
|
||||
DevFunds.new({blockchainConfig: this.config}).then(devFunds => {
|
||||
devFunds.createFundAndUnlockAccounts((err) => {
|
||||
cb(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -4,22 +4,32 @@ const {getWeiBalanceFromString, buildUrl} = require('../../utils/utils.js');
|
|||
const {readFileSync, dappPath} = require('../../core/fs');
|
||||
|
||||
class DevFunds {
|
||||
constructor(blockchainConfig) {
|
||||
// TODO: temporary to avoid nasty suprises, should be removed
|
||||
try {
|
||||
this.web3 = null;
|
||||
this.blockchainConfig = blockchainConfig;
|
||||
this.accounts = [];
|
||||
this.numAccounts = this.blockchainConfig.account.numAccounts || 0;
|
||||
this.password = readFileSync(dappPath(blockchainConfig.account.password), 'utf8').replace('\n', '');
|
||||
this.web3 = new Web3();
|
||||
this.networkId = null;
|
||||
this.balance = Web3.utils.toWei("1", "ether");
|
||||
if (this.blockchainConfig.account.balance) {
|
||||
this.balance = getWeiBalanceFromString(this.blockchainConfig.account.balance, this.web3);
|
||||
}
|
||||
} catch(_err) {
|
||||
// empty for now
|
||||
constructor(options) {
|
||||
this.blockchainConfig = options.blockchainConfig;
|
||||
this.accounts = [];
|
||||
this.numAccounts = this.blockchainConfig.account.numAccounts || 0;
|
||||
this.password = this.blockchainConfig.account.password ? readFileSync(dappPath(this.blockchainConfig.account.password), 'utf8').replace('\n', '') : 'dev_password';
|
||||
this.networkId = null;
|
||||
this.balance = Web3.utils.toWei("1", "ether");
|
||||
this.provider = options.provider || new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), {headers: {Origin: "http://localhost:8000"}});
|
||||
this.web3 = new Web3(this.provider);
|
||||
if (this.blockchainConfig.account.balance) {
|
||||
this.balance = getWeiBalanceFromString(this.blockchainConfig.account.balance, this.web3);
|
||||
}
|
||||
this.logger = options.logger || console;
|
||||
}
|
||||
|
||||
static async new(options){
|
||||
const df = new DevFunds(options);
|
||||
await df._init();
|
||||
return df;
|
||||
}
|
||||
|
||||
async _init () {
|
||||
const accounts = await this.web3.eth.getAccounts();
|
||||
this.web3.eth.defaultAccount = accounts[0];
|
||||
if (accounts.length > 1) {
|
||||
this.accounts = accounts.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +41,7 @@ class DevFunds {
|
|||
}
|
||||
|
||||
// trigger regular txs due to a bug in geth and stuck transactions in --dev mode
|
||||
regularTxs(cb) {
|
||||
_regularTxs(cb) {
|
||||
const self = this;
|
||||
self.web3.eth.net.getId().then((networkId) => {
|
||||
self.networkId = networkId;
|
||||
|
@ -39,29 +49,16 @@ class DevFunds {
|
|||
return;
|
||||
}
|
||||
|
||||
setInterval(function() { self._sendTx(); }, 1500);
|
||||
setInterval(function () { self._sendTx(); }, 1500);
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
regularUnlocks() {
|
||||
_regularUnlocks() {
|
||||
const self = this;
|
||||
setInterval(function() { self.unlockAccounts(self.password, () => {}); }, 20000);
|
||||
}
|
||||
|
||||
connectToNode(cb) {
|
||||
|
||||
this.web3.setProvider(new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), {headers: {Origin: "http://localhost:8000"}}));
|
||||
|
||||
this.web3.eth.getAccounts().then((accounts) => {
|
||||
this.web3.eth.defaultAccount = accounts[0];
|
||||
if (accounts.length > 1) {
|
||||
this.accounts = accounts.slice(1);
|
||||
}
|
||||
cb();
|
||||
});
|
||||
setInterval(function () { self.unlockAccounts(self.password, () => { }); }, 20000);
|
||||
}
|
||||
|
||||
createAccounts(numAccounts, password, cb) {
|
||||
|
@ -86,17 +83,15 @@ class DevFunds {
|
|||
}
|
||||
|
||||
fundAccounts(balance, cb) {
|
||||
|
||||
async.each(this.accounts, (account, next) => {
|
||||
this.web3.eth.getBalance(account).then(currBalance => {
|
||||
const remainingBalance = balance - currBalance;
|
||||
if (remainingBalance <= 0) return next();
|
||||
|
||||
this.web3.eth.sendTransaction({to: account, value: remainingBalance}).then((_result) => {
|
||||
next();
|
||||
}).catch(next);
|
||||
}, cb);
|
||||
});
|
||||
this.web3.eth.sendTransaction({to: account, value: remainingBalance}).catch(next);
|
||||
next(); // don't wait for the tx receipt as it never comes!
|
||||
}).catch(cb);
|
||||
}, cb);
|
||||
}
|
||||
|
||||
createFundAndUnlockAccounts(cb) {
|
||||
|
@ -104,9 +99,6 @@ class DevFunds {
|
|||
return cb();
|
||||
}
|
||||
async.waterfall([
|
||||
(next) => {
|
||||
this.connectToNode(next);
|
||||
},
|
||||
(next) => {
|
||||
this.createAccounts(this.numAccounts, this.password, next);
|
||||
},
|
||||
|
@ -114,8 +106,8 @@ class DevFunds {
|
|||
this.unlockAccounts(this.password, next);
|
||||
},
|
||||
(next) => {
|
||||
this.regularTxs();
|
||||
this.regularUnlocks();
|
||||
this._regularTxs();
|
||||
this._regularUnlocks();
|
||||
this.fundAccounts(this.balance, next);
|
||||
}
|
||||
], cb);
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*global describe, it, before*/
|
||||
const assert = require('assert');
|
||||
let TestLogger = require('../lib/tests/test_logger.js');
|
||||
const Web3 = require('web3');
|
||||
const i18n = require('../lib/i18n/i18n.js');
|
||||
const constants = require('../lib/constants.json');
|
||||
const DevFunds = require('../lib/cmds/blockchain/dev_funds');
|
||||
const async = require('async');
|
||||
const FakeIpcProvider = require('./helpers/fakeIpcProvider');
|
||||
const utils = require('../lib/utils/utils');
|
||||
i18n.setOrDetectLocale('en');
|
||||
|
||||
describe('embark.DevFunds', function () {
|
||||
let config = {
|
||||
networkType: 'livenet',
|
||||
genesisBlock: 'foo/bar/genesis.json',
|
||||
geth_bin: 'geth',
|
||||
datadir: '/foo/datadir/',
|
||||
mineWhenNeeded: true,
|
||||
rpcHost: 'someserver',
|
||||
rpcPort: 12345,
|
||||
rpcApi: ['eth', 'web3', 'net', 'debug'],
|
||||
rpcCorsDomain: true,
|
||||
networkId: 1,
|
||||
port: 123456,
|
||||
nodiscover: true,
|
||||
maxpeers: 25,
|
||||
mine: true,
|
||||
vmdebug: false,
|
||||
whisper: false,
|
||||
account: {
|
||||
password: './test/test1/password',
|
||||
numAccounts: 3,
|
||||
balance: "5 ether"
|
||||
},
|
||||
bootnodes: "",
|
||||
wsApi: ["eth", "web3", "net", "shh", "debug"],
|
||||
wsHost: "localhost",
|
||||
wsOrigins: false,
|
||||
wsPort: 8546,
|
||||
wsRPC: true,
|
||||
targetGasLimit: false,
|
||||
syncMode: undefined,
|
||||
syncmode: undefined,
|
||||
verbosity: undefined,
|
||||
proxy: true
|
||||
};
|
||||
|
||||
if (config.proxy) {
|
||||
config.wsPort += constants.blockchain.servicePortOnProxy;
|
||||
config.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
}
|
||||
|
||||
describe('#create, fund, and unlock accounts', function () {
|
||||
let provider = new FakeIpcProvider();
|
||||
const web3 = new Web3(provider);
|
||||
let devFunds;
|
||||
|
||||
before(async () => {
|
||||
provider.injectResult(['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855']); // getAccounts: return --dev account
|
||||
devFunds = await DevFunds.new({blockchainConfig: config, provider: provider, logger: new TestLogger({})});
|
||||
});
|
||||
|
||||
it('should create correct number of accounts', function (done) {
|
||||
provider.injectResult('0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae'); // createAccount #1
|
||||
provider.injectResult('0x22f4d0a3c12e86b4b5f39b213f7e19d048276dab'); // createAccount #2
|
||||
|
||||
devFunds.createAccounts(config.account.numAccounts, 'test_password', (err) => {
|
||||
assert.equal(err, null);
|
||||
|
||||
// TODO: make FakeIpcProvider smart enough to keep track of created accounts
|
||||
provider.injectResult(['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855', '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae', '0x22f4d0a3c12e86b4b5f39b213f7e19d048276dab']);
|
||||
|
||||
web3.eth.getAccounts().then((accts) => {
|
||||
assert.equal(accts.length, config.account.numAccounts);
|
||||
assert.strictEqual(accts[0], '0x47D33b27Bb249a2DBab4C0612BF9CaF4C1950855'); // --dev acct
|
||||
assert.strictEqual(accts[1], '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe'); // created acct #1
|
||||
assert.strictEqual(accts[2], '0x22F4d0A3C12E86b4b5F39B213f7e19D048276DAb'); // created acct #2
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should unlock accounts', function (done) {
|
||||
if (devFunds.accounts.length === 0) {
|
||||
assert.equal(true, true, "no accounts to unlock");
|
||||
return done();
|
||||
}
|
||||
|
||||
devFunds.accounts.forEach(_acct => {
|
||||
provider.injectResult(true); // account unlock result
|
||||
});
|
||||
|
||||
devFunds.unlockAccounts(devFunds.password, (errUnlock) => {
|
||||
assert.equal(errUnlock, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fund accounts', function (done) {
|
||||
|
||||
if (devFunds.accounts.length === 0) {
|
||||
assert.equal(true, true, "no accounts to fund");
|
||||
return done();
|
||||
}
|
||||
devFunds.accounts.forEach(_acct => {
|
||||
provider.injectResult('1234567890'); // account balance
|
||||
// provider.injectResult('0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe'); // send tx response
|
||||
});
|
||||
|
||||
devFunds.fundAccounts(devFunds.balance, (errFundAccounts) => {
|
||||
|
||||
assert.equal(errFundAccounts, null);
|
||||
|
||||
// inject response for web3.eth.getAccounts
|
||||
// TODO: make FakeIpcProvider smart enough to keep track of created accounts
|
||||
provider.injectResult(['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855', '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae', '0x22f4d0a3c12e86b4b5f39b213f7e19d048276dab']);
|
||||
|
||||
web3.eth.getAccounts().then((accts) => {
|
||||
|
||||
const weiFromConfig = utils.getWeiBalanceFromString(config.account.balance, web3);
|
||||
|
||||
async.each(accts, (acct, cb) => {
|
||||
|
||||
// inject response for web3.eth.getBalance.
|
||||
// essentially, this will always return the amount we specified
|
||||
// in the config.
|
||||
// this is dodgy. really, we should be letting the FakeIpcProvider
|
||||
// at this point tell us how many wei we have per account (as it would
|
||||
// in a real node), but the FakeIpcProvider is not smart enough... yet.
|
||||
// TODO: make FakeIpcProvider smart enough to keep track of balances
|
||||
provider.injectResult(web3.utils.numberToHex(weiFromConfig));
|
||||
|
||||
web3.eth.getBalance(acct).then((wei) => {
|
||||
assert.equal(wei, weiFromConfig);
|
||||
cb();
|
||||
}).catch(cb);
|
||||
|
||||
}, function (errAcctsBalance) {
|
||||
if (errAcctsBalance) throw errAcctsBalance;
|
||||
done();
|
||||
});
|
||||
}).catch((errGetAccts) => {
|
||||
if (errGetAccts) throw errGetAccts;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,137 @@
|
|||
const assert = require('assert');
|
||||
const _ = require('lodash');
|
||||
|
||||
const FakeIpcProvider = function IpcProvider() {
|
||||
var _this = this;
|
||||
this.countId = 1;
|
||||
this.notificationCount = 1;
|
||||
this.getResponseStub = function () {
|
||||
return {
|
||||
jsonrpc: '2.0',
|
||||
id: _this.countId,
|
||||
result: null
|
||||
};
|
||||
};
|
||||
this.getErrorStub = function () {
|
||||
return {
|
||||
jsonrpc: '2.0',
|
||||
id: _this.countId,
|
||||
error: {
|
||||
code: 1234,
|
||||
message: 'Stub error'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
this.response = [];
|
||||
this.error = [];
|
||||
this.validation = [];
|
||||
this.notificationCallbacks = [];
|
||||
};
|
||||
|
||||
FakeIpcProvider.prototype.send = function (payload, callback) {
|
||||
var _this = this;
|
||||
|
||||
// set id
|
||||
if (payload.id)
|
||||
this.countId = payload.id;
|
||||
// else
|
||||
// this.countId++;
|
||||
|
||||
assert.equal(_.isArray(payload) || _.isObject(payload), true);
|
||||
assert.equal(_.isFunction(callback), true);
|
||||
|
||||
var validation = this.validation.shift();
|
||||
|
||||
if (validation) {
|
||||
// imitate plain json object
|
||||
validation(JSON.parse(JSON.stringify(payload)), callback);
|
||||
}
|
||||
|
||||
var response = this.getResponseOrError('response', payload);
|
||||
var error = this.getResponseOrError('error', payload);
|
||||
|
||||
setTimeout(function () {
|
||||
callback(error, response);
|
||||
}, 1);
|
||||
};
|
||||
|
||||
FakeIpcProvider.prototype.on = function (type, callback) {
|
||||
if (type === 'data') {
|
||||
this.notificationCallbacks.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
FakeIpcProvider.prototype.getResponseOrError = function (type, payload) {
|
||||
var _this = this;
|
||||
var response;
|
||||
|
||||
if (type === 'error') {
|
||||
response = this.error.shift();
|
||||
} else {
|
||||
response = this.response.shift() || this.getResponseStub();
|
||||
}
|
||||
|
||||
|
||||
if (response) {
|
||||
if (_.isArray(response)) {
|
||||
response = response.map(function (resp, index) {
|
||||
resp.id = payload[index] ? payload[index].id : _this.countId++;
|
||||
return resp;
|
||||
});
|
||||
} else
|
||||
response.id = payload.id;
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
FakeIpcProvider.prototype.injectNotification = function (notification) {
|
||||
var _this = this;
|
||||
setTimeout(function () {
|
||||
_this.notificationCallbacks.forEach(function (cb) {
|
||||
if (notification && cb)
|
||||
cb(null, notification);
|
||||
});
|
||||
}, 100 + this.notificationCount);
|
||||
|
||||
this.notificationCount += 10;
|
||||
};
|
||||
|
||||
// FakeHttpProvider.prototype.injectResponse = function (response) {
|
||||
// this.response = response;
|
||||
// };
|
||||
|
||||
FakeIpcProvider.prototype.injectBatchResults = function (results, error) {
|
||||
var _this = this;
|
||||
this.response.push(results.map(function (r) {
|
||||
if (error) {
|
||||
var response = _this.getErrorStub();
|
||||
response.error.message = r;
|
||||
} else {
|
||||
var response = _this.getResponseStub();
|
||||
response.result = r;
|
||||
}
|
||||
return response;
|
||||
}));
|
||||
};
|
||||
|
||||
FakeIpcProvider.prototype.injectResult = function (result) {
|
||||
var response = this.getResponseStub();
|
||||
response.result = result;
|
||||
|
||||
this.response.push(response);
|
||||
};
|
||||
|
||||
FakeIpcProvider.prototype.injectError = function (error) {
|
||||
var errorStub = this.getErrorStub();
|
||||
errorStub.error = error; // message, code
|
||||
|
||||
this.error.push(errorStub);
|
||||
};
|
||||
|
||||
FakeIpcProvider.prototype.injectValidation = function (callback) {
|
||||
this.validation.push(callback);
|
||||
};
|
||||
|
||||
module.exports = FakeIpcProvider;
|
|
@ -0,0 +1 @@
|
|||
dev_password
|
Loading…
Reference in New Issue