Skip to content

Commit 12304ea

Browse files
committed
Adding in unit tests for dev_funds (WIP)
1 parent c577ad6 commit 12304ea

File tree

4 files changed

+299
-28
lines changed

4 files changed

+299
-28
lines changed

lib/cmds/blockchain/dev_funds.js

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,29 @@
11
const async = require('async');
22
const Web3 = require('web3');
3-
const {getWeiBalanceFromString, buildUrl} = require('../../utils/utils.js');
4-
const {readFileSync, dappPath} = require('../../core/fs');
3+
const { getWeiBalanceFromString, buildUrl } = require('../../utils/utils.js');
4+
const { readFileSync, dappPath } = require('../../core/fs');
55

66
class DevFunds {
7-
constructor(blockchainConfig) {
8-
// TODO: temporary to avoid nasty suprises, should be removed
9-
try {
10-
this.web3 = null;
11-
this.blockchainConfig = blockchainConfig;
12-
this.accounts = [];
13-
this.numAccounts = this.blockchainConfig.account.numAccounts || 0;
14-
this.password = readFileSync(dappPath(blockchainConfig.account.password), 'utf8').replace('\n', '');
15-
this.web3 = new Web3();
16-
this.networkId = null;
17-
this.balance = Web3.utils.toWei("1", "ether");
18-
if (this.blockchainConfig.account.balance) {
19-
this.balance = getWeiBalanceFromString(this.blockchainConfig.account.balance, this.web3);
20-
}
21-
} catch(_err) {
22-
// empty for now
7+
constructor(blockchainConfig, provider, logger) {
8+
this.blockchainConfig = blockchainConfig;
9+
this.accounts = [];
10+
this.numAccounts = this.blockchainConfig.account.numAccounts || 0;
11+
this.password = blockchainConfig.account.password ? readFileSync(dappPath(blockchainConfig.account.password), 'utf8').replace('\n', '') : 'dev_password';
12+
this.networkId = null;
13+
this.balance = Web3.utils.toWei("1", "ether");
14+
this.provider = provider || new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), { headers: { Origin: "http://localhost:8000" } });
15+
this.web3 = new Web3(provider);
16+
if (this.blockchainConfig.account.balance) {
17+
this.balance = getWeiBalanceFromString(this.blockchainConfig.account.balance, this.web3);
2318
}
19+
this.logger = logger || console;
2420
}
2521

2622
_sendTx() {
2723
if (this.networkId !== 1337) {
2824
return;
2925
}
30-
this.web3.eth.sendTransaction({value: "1000000000000000", to: "0xA2817254cb8E7b6269D1689c3E0eBadbB78889d1", from: this.web3.eth.defaultAccount});
26+
this.web3.eth.sendTransaction({ value: "1000000000000000", to: "0xA2817254cb8E7b6269D1689c3E0eBadbB78889d1", from: this.web3.eth.defaultAccount });
3127
}
3228

3329
// trigger regular txs due to a bug in geth and stuck transactions in --dev mode
@@ -39,7 +35,7 @@ class DevFunds {
3935
return;
4036
}
4137

42-
setInterval(function() { self._sendTx(); }, 1500);
38+
setInterval(function () { self._sendTx(); }, 1500);
4339
if (cb) {
4440
cb();
4541
}
@@ -48,12 +44,10 @@ class DevFunds {
4844

4945
regularUnlocks() {
5046
const self = this;
51-
setInterval(function() { self.unlockAccounts(self.password, () => {}); }, 20000);
47+
setInterval(function () { self.unlockAccounts(self.password, () => { }); }, 20000);
5248
}
5349

54-
connectToNode(cb) {
55-
56-
this.web3.setProvider(new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), {headers: {Origin: "http://localhost:8000"}}));
50+
getCurrentAccounts(cb) {
5751

5852
this.web3.eth.getAccounts().then((accounts) => {
5953
this.web3.eth.defaultAccount = accounts[0];
@@ -86,16 +80,24 @@ class DevFunds {
8680
}
8781

8882
fundAccounts(balance, cb) {
89-
83+
this.logger.info('[dev_funds]: funding accounts');
9084
async.each(this.accounts, (account, next) => {
85+
this.logger.info('[dev_funds]: funding acct ' + account);
9186
this.web3.eth.getBalance(account).then(currBalance => {
87+
this.logger.info('[dev_funds]: acct ' + account + ' current balance ' + currBalance);
9288
const remainingBalance = balance - currBalance;
9389
if (remainingBalance <= 0) return next();
9490

95-
this.web3.eth.sendTransaction({to: account, value: remainingBalance}).then((_result) => {
91+
this.logger.info('[dev_funds]: funding acct ' + account + ' with ' + remainingBalance);
92+
93+
this.web3.eth.sendTransaction({ to: account, value: remainingBalance }).then((_result) => {
94+
this.logger.info('[dev_funds]: funding result ' + JSON.stringify(_result));
9695
next();
9796
}).catch(next);
98-
}, cb);
97+
}, (err) => {
98+
this.logger.info('[dev_funds]: done funding');
99+
cb(err);
100+
});
99101
});
100102
}
101103

@@ -105,7 +107,7 @@ class DevFunds {
105107
}
106108
async.waterfall([
107109
(next) => {
108-
this.connectToNode(next);
110+
this.getCurrentAccounts(next);
109111
},
110112
(next) => {
111113
this.createAccounts(this.numAccounts, this.password, next);

test/devFunds.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*global describe, it*/
2+
const assert = require('assert');
3+
let TestLogger = require('../lib/tests/test_logger.js');
4+
const Web3 = require('web3');
5+
const i18n = require('../lib/i18n/i18n.js');
6+
const constants = require('../lib/constants.json');
7+
const Test = require('../lib/tests/test');
8+
const DevFunds = require('../lib/cmds/blockchain/dev_funds');
9+
const async = require('async');
10+
const FakeIpcProvider = require('./helpers/fakeIpcProvider');
11+
const utils = require('../lib/utils/utils');
12+
i18n.setOrDetectLocale('en');
13+
14+
describe('embark.DevFunds', function () {
15+
let config = {
16+
networkType: 'livenet',
17+
genesisBlock: 'foo/bar/genesis.json',
18+
geth_bin: 'geth',
19+
datadir: '/foo/datadir/',
20+
mineWhenNeeded: true,
21+
rpcHost: 'someserver',
22+
rpcPort: 12345,
23+
rpcApi: ['eth', 'web3', 'net', 'debug'],
24+
rpcCorsDomain: true,
25+
networkId: 1,
26+
port: 123456,
27+
nodiscover: true,
28+
maxpeers: 25,
29+
mine: true,
30+
vmdebug: false,
31+
whisper: false,
32+
account: {
33+
password: './test/test1/password',
34+
numAccounts: 3,
35+
balance: "5 ether"
36+
},
37+
bootnodes: "",
38+
wsApi: ["eth", "web3", "net", "shh", "debug"],
39+
wsHost: "localhost",
40+
wsOrigins: false,
41+
wsPort: 8546,
42+
wsRPC: true,
43+
targetGasLimit: false,
44+
syncMode: undefined,
45+
syncmode: undefined,
46+
verbosity: undefined,
47+
proxy: true
48+
};
49+
50+
if (config.proxy) {
51+
config.wsPort += constants.blockchain.servicePortOnProxy;
52+
config.rpcPort += constants.blockchain.servicePortOnProxy;
53+
}
54+
55+
// TODO put default config
56+
const test = new Test({ loglevel: 'trace' });
57+
58+
59+
test.initWeb3Provider((err) => {
60+
if (err) throw err;
61+
describe('#create, fund, and unlock accounts', function () {
62+
let provider = new FakeIpcProvider();
63+
let devFunds = new DevFunds(config, provider, new TestLogger({}));
64+
const web3 = new Web3(provider);
65+
66+
it('should create correct number of accounts', function (done) {
67+
provider.injectResult(['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855']); // getAccounts - return --dev account
68+
devFunds.getCurrentAccounts(() => {
69+
70+
provider.injectResult('0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae'); // createAccount #1
71+
provider.injectResult('0x22f4d0a3c12e86b4b5f39b213f7e19d048276dab'); // createAccount #2
72+
73+
74+
devFunds.createAccounts(config.account.numAccounts, 'test_password', (err) => {
75+
assert.equal(err, null);
76+
77+
provider.injectResult(['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855', '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae', '0x22f4d0a3c12e86b4b5f39b213f7e19d048276dab']);
78+
web3.eth.getAccounts().then((accts) => {
79+
console.log('got accts: ' + JSON.stringify(accts));
80+
assert.equal(accts.length, config.account.numAccounts);
81+
assert.strictEqual(accts[0], '0x47D33b27Bb249a2DBab4C0612BF9CaF4C1950855');
82+
assert.strictEqual(accts[1], '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe');
83+
assert.strictEqual(accts[2], '0x22F4d0A3C12E86b4b5F39B213f7e19D048276DAb');
84+
done();
85+
});
86+
});
87+
});
88+
});
89+
90+
it('should fund accounts', function (done) {
91+
console.dir('funding accounts...');
92+
93+
provider.injectResult('1234567890'); // account #1 balance
94+
provider.injectResult('1234567890'); // account #2 balance
95+
provider.injectResult('0xfff12345678976543213456786543212345675432'); // send tx #1
96+
provider.injectResult('0xfff12345678976543213456786543212345675433'); // send tx #2
97+
98+
try {
99+
devFunds.fundAccounts(devFunds.balance, (err) => {
100+
console.dir('accounts funded...');
101+
assert.equal(err, null);
102+
103+
provider.injectResult(['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855', '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae', '0x22f4d0a3c12e86b4b5f39b213f7e19d048276dab']);
104+
web3.eth.getAccounts().then((accts) => {
105+
console.log('got accts: ' + JSON.stringify(accts));
106+
107+
const weiFromConfig = utils.getWeiBalanceFromString(config.account.balance);
108+
async.each(accts, (acct, cb) => {
109+
provider.injectResult(web3.utils.numberToHex(weiFromConfig));
110+
devFunds.web3.eth.getBalance(acct).then((wei) => {
111+
assert.equal(wei, weiFromConfig);
112+
cb();
113+
}).catch(cb);
114+
}, function(err) { done(); });
115+
}).catch(() => {
116+
done();
117+
});
118+
});
119+
} catch (errFundAccts) {
120+
throw errFundAccts;
121+
}
122+
});
123+
});
124+
});
125+
});

test/helpers/fakeIpcProvider.js

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
var assert = require('assert');
2+
var _ = require('lodash');
3+
4+
5+
6+
7+
var FakeIpcProvider = function IpcProvider() {
8+
var _this = this;
9+
this.countId = 1;
10+
this.notificationCount = 1;
11+
this.getResponseStub = function () {
12+
return {
13+
jsonrpc: '2.0',
14+
id: _this.countId,
15+
result: null
16+
};
17+
};
18+
this.getErrorStub = function () {
19+
return {
20+
jsonrpc: '2.0',
21+
id: _this.countId,
22+
error: {
23+
code: 1234,
24+
message: 'Stub error'
25+
}
26+
};
27+
};
28+
29+
this.response = [];
30+
this.error = [];
31+
this.validation = [];
32+
this.notificationCallbacks = [];
33+
};
34+
35+
36+
FakeIpcProvider.prototype.send = function (payload, callback) {
37+
var _this = this;
38+
39+
// set id
40+
if(payload.id)
41+
this.countId = payload.id;
42+
// else
43+
// this.countId++;
44+
45+
assert.equal(_.isArray(payload) || _.isObject(payload), true);
46+
assert.equal(_.isFunction(callback), true);
47+
48+
var validation = this.validation.shift();
49+
50+
if (validation) {
51+
// imitate plain json object
52+
validation(JSON.parse(JSON.stringify(payload)), callback);
53+
}
54+
55+
var response = this.getResponseOrError('response', payload);
56+
var error = this.getResponseOrError('error', payload);
57+
58+
setTimeout(function(){
59+
callback(error, response);
60+
}, 1);
61+
};
62+
63+
FakeIpcProvider.prototype.on = function (type, callback) {
64+
if(type === 'data') {
65+
this.notificationCallbacks.push(callback);
66+
}
67+
};
68+
69+
FakeIpcProvider.prototype.getResponseOrError = function (type, payload) {
70+
var _this = this;
71+
var response;
72+
73+
if(type === 'error') {
74+
response = this.error.shift();
75+
} else {
76+
response = this.response.shift() || this.getResponseStub();
77+
}
78+
79+
80+
if(response) {
81+
if(_.isArray(response)) {
82+
response = response.map(function(resp, index) {
83+
resp.id = payload[index] ? payload[index].id : _this.countId++;
84+
return resp;
85+
});
86+
} else
87+
response.id = payload.id;
88+
}
89+
90+
return response;
91+
};
92+
93+
FakeIpcProvider.prototype.injectNotification = function (notification) {
94+
var _this = this;
95+
setTimeout(function(){
96+
_this.notificationCallbacks.forEach(function(cb){
97+
if(notification && cb)
98+
cb(null, notification);
99+
});
100+
}, 100 + this.notificationCount);
101+
102+
this.notificationCount += 10;
103+
};
104+
105+
// FakeHttpProvider.prototype.injectResponse = function (response) {
106+
// this.response = response;
107+
// };
108+
109+
110+
111+
FakeIpcProvider.prototype.injectBatchResults = function (results, error) {
112+
var _this = this;
113+
this.response.push(results.map(function (r) {
114+
if(error) {
115+
var response = _this.getErrorStub();
116+
response.error.message = r;
117+
} else {
118+
var response = _this.getResponseStub();
119+
response.result = r;
120+
}
121+
return response;
122+
}));
123+
};
124+
125+
FakeIpcProvider.prototype.injectResult = function (result) {
126+
var response = this.getResponseStub();
127+
response.result = result;
128+
129+
this.response.push(response);
130+
};
131+
132+
FakeIpcProvider.prototype.injectError = function (error) {
133+
var errorStub = this.getErrorStub();
134+
errorStub.error = error; // message, code
135+
136+
this.error.push(errorStub);
137+
};
138+
139+
FakeIpcProvider.prototype.injectValidation = function (callback) {
140+
this.validation.push(callback);
141+
};
142+
143+
module.exports = FakeIpcProvider;

test/test1/password

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dev_password

0 commit comments

Comments
 (0)