Merge pull request #496 from embark-framework/features/wallet-in-tests
Enables specifying accounts in simulator mode in the tests
This commit is contained in:
commit
8aad260dfa
|
@ -21,10 +21,32 @@ class AccountParser {
|
|||
return accounts;
|
||||
}
|
||||
|
||||
static getHexBalance(balanceString, web3) {
|
||||
if (!balanceString) {
|
||||
return 0xFFFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
if (web3.utils.isHexStrict(balanceString)) {
|
||||
return balanceString;
|
||||
}
|
||||
const match = balanceString.match(/([0-9]+) ?([a-zA-Z]*)/);
|
||||
if (!match) {
|
||||
throw new Error(__('Unrecognized balance string "%s"', balanceString));
|
||||
}
|
||||
if (!match[2]) {
|
||||
return web3.utils.toHex(parseInt(match[1], 10));
|
||||
}
|
||||
|
||||
return web3.utils.toHex(web3.utils.toWei(match[1], match[2]));
|
||||
}
|
||||
|
||||
static getAccount(accountConfig, web3, logger) {
|
||||
if (!logger) {
|
||||
logger = console;
|
||||
}
|
||||
let hexBalance = null;
|
||||
if (accountConfig.balance) {
|
||||
hexBalance = AccountParser.getHexBalance(accountConfig.balance, web3);
|
||||
}
|
||||
if (accountConfig.privateKey) {
|
||||
if (!accountConfig.privateKey.startsWith('0x')) {
|
||||
accountConfig.privateKey = '0x' + accountConfig.privateKey;
|
||||
|
@ -33,7 +55,7 @@ class AccountParser {
|
|||
logger.warn(`Private key ending with ${accountConfig.privateKey.substr(accountConfig.privateKey.length - 5)} is not a HEX string`);
|
||||
return null;
|
||||
}
|
||||
return web3.eth.accounts.privateKeyToAccount(accountConfig.privateKey);
|
||||
return Object.assign(web3.eth.accounts.privateKeyToAccount(accountConfig.privateKey), {hexBalance});
|
||||
}
|
||||
if (accountConfig.privateKeyFile) {
|
||||
let fileContent = fs.readFileSync(fs.dappPath(accountConfig.privateKeyFile)).toString();
|
||||
|
@ -46,7 +68,7 @@ class AccountParser {
|
|||
logger.warn(`Private key is not a HEX string in file ${accountConfig.privateKeyFile} at index ${index}`);
|
||||
return null;
|
||||
}
|
||||
return web3.eth.accounts.privateKeyToAccount(key);
|
||||
return Object.assign(web3.eth.accounts.privateKeyToAccount(key), {hexBalance});
|
||||
});
|
||||
}
|
||||
if (accountConfig.mnemonic) {
|
||||
|
@ -59,7 +81,7 @@ class AccountParser {
|
|||
const accounts = [];
|
||||
for (let i = addressIndex; i < addressIndex + numAddresses; i++) {
|
||||
const wallet = hdwallet.derivePath(wallet_hdpath + i).getWallet();
|
||||
accounts.push(web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex')));
|
||||
accounts.push(Object.assign(web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex')), {hexBalance}));
|
||||
}
|
||||
return accounts;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ class DeployManager {
|
|||
async.eachOfSeries(contracts,
|
||||
function (contract, key, callback) {
|
||||
contract._gasLimit = self.gasLimit;
|
||||
self.events.request('deploy:contract', contract, () => {
|
||||
callback();
|
||||
self.events.request('deploy:contract', contract, (err) => {
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
function (err, _results) {
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
const async = require('async');
|
||||
const TARGET = 15000000000000000000;
|
||||
const TARGET = 0x7FFFFFFFFFFFFFFF;
|
||||
const ALREADY_FUNDED = 'alreadyFunded';
|
||||
|
||||
function fundAccount(web3, accountAddress, callback) {
|
||||
function fundAccount(web3, accountAddress, hexBalance, callback) {
|
||||
if (!hexBalance) {
|
||||
hexBalance = TARGET;
|
||||
}
|
||||
const targetBalance = (typeof hexBalance === 'string') ? parseInt(hexBalance, 16) : hexBalance;
|
||||
let accountBalance;
|
||||
let coinbaseAddress;
|
||||
let lastNonce;
|
||||
|
@ -14,7 +18,7 @@ function fundAccount(web3, accountAddress, callback) {
|
|||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (balance >= TARGET) {
|
||||
if (balance >= targetBalance) {
|
||||
return next(ALREADY_FUNDED);
|
||||
}
|
||||
accountBalance = balance;
|
||||
|
@ -56,7 +60,7 @@ function fundAccount(web3, accountAddress, callback) {
|
|||
web3.eth.sendTransaction({
|
||||
from: coinbaseAddress,
|
||||
to: accountAddress,
|
||||
value: TARGET - accountBalance,
|
||||
value: targetBalance - accountBalance,
|
||||
gasPrice: gasPrice,
|
||||
nonce: lastNonce
|
||||
}, next);
|
||||
|
|
|
@ -65,7 +65,7 @@ class Provider {
|
|||
return callback();
|
||||
}
|
||||
async.each(self.accounts, (account, eachCb) => {
|
||||
fundAccount(self.web3, account.address, eachCb);
|
||||
fundAccount(self.web3, account.address, account.hexBalance, eachCb);
|
||||
}, callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,6 @@ Plugin.prototype.hasContext = function(context) {
|
|||
|
||||
Plugin.prototype.loadPlugin = function() {
|
||||
if (!this.isContextValid()) {
|
||||
console.log(this.acceptedContext);
|
||||
this.logger.warn(__('Plugin {{name}} can only be loaded in the context of "{{contextes}}"', {name: this.name, contextes: this.acceptedContext.join(', ')}));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ class SolcProcess extends ProcessWrapper {
|
|||
return {contents: fs.readFileSync(path.join('./node_modules/', filename)).toString()};
|
||||
}
|
||||
if (fs.existsSync(path.join(constants.httpContractsDirectory, filename))) {
|
||||
return {contents: fs.readFileSync(path.join('./.embark/contracts', filename)).toString()};
|
||||
return {contents: fs.readFileSync(path.join(constants.httpContractsDirectory, filename)).toString()};
|
||||
}
|
||||
return {error: 'File not found'};
|
||||
}
|
||||
|
|
|
@ -37,6 +37,12 @@ module.exports = {
|
|||
global.assert = assert;
|
||||
global.config = test.config.bind(test);
|
||||
|
||||
global.deployAll = function () {
|
||||
console.error(__('%s is not supported anymore', 'deployAll').red);
|
||||
console.info(__('You can learn about the new revamped tests here: %s', 'https://embark.status.im/docs/testing.html'.underline));
|
||||
process.exit();
|
||||
};
|
||||
|
||||
// TODO: this global here might not be necessary at all
|
||||
global.web3 = global.embark.web3;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ const utils = require('../utils/utils');
|
|||
const constants = require('../constants');
|
||||
const Events = require('../core/events');
|
||||
const cloneDeep = require('clone-deep');
|
||||
const AccountParser = require('../contracts/accountParser');
|
||||
|
||||
function getSimulator() {
|
||||
try {
|
||||
|
@ -36,12 +37,7 @@ class Test {
|
|||
this.compiledContracts = {};
|
||||
|
||||
this.web3 = new Web3();
|
||||
if (this.simOptions.node) {
|
||||
this.web3.setProvider(new this.web3.providers.HttpProvider(this.simOptions.node));
|
||||
} else {
|
||||
this.sim = getSimulator();
|
||||
this.web3.setProvider(this.sim.provider(this.simOptions));
|
||||
}
|
||||
this.initWeb3Provider();
|
||||
|
||||
this.engine = new Engine({
|
||||
env: this.options.env || 'test',
|
||||
|
@ -55,11 +51,31 @@ class Test {
|
|||
});
|
||||
|
||||
this.versions_default = this.engine.config.contractsConfig.versions;
|
||||
const deploymentConfig = this.engine.config.contractsConfig.versions;
|
||||
// Reset contract config to nothing to make sure we deploy only what we want
|
||||
this.engine.config.contractsConfig = {contracts: {}, versions: this.versions_default};
|
||||
this.engine.config.contractsConfig = {contracts: {}, versions: this.versions_default, deployment: deploymentConfig};
|
||||
|
||||
this.engine.startService("libraryManager");
|
||||
this.engine.startService("codeRunner");
|
||||
this.initDeployServices();
|
||||
this.engine.startService("codeGenerator");
|
||||
}
|
||||
|
||||
initWeb3Provider() {
|
||||
if (this.simOptions.node) {
|
||||
this.web3.setProvider(new this.web3.providers.HttpProvider(this.simOptions.node));
|
||||
} else {
|
||||
if (this.simOptions.accounts) {
|
||||
this.simOptions.accounts = this.simOptions.accounts.map((account) => {
|
||||
return {balance: account.hexBalance, secretKey: account.privateKey};
|
||||
});
|
||||
}
|
||||
this.sim = getSimulator();
|
||||
this.web3.setProvider(this.sim.provider(this.simOptions));
|
||||
}
|
||||
}
|
||||
|
||||
initDeployServices() {
|
||||
this.engine.startService("web3", {
|
||||
web3: this.web3
|
||||
});
|
||||
|
@ -67,7 +83,6 @@ class Test {
|
|||
trackContracts: false,
|
||||
ipcRole: 'client'
|
||||
});
|
||||
this.engine.startService("codeGenerator");
|
||||
}
|
||||
|
||||
init(callback) {
|
||||
|
@ -100,6 +115,13 @@ class Test {
|
|||
this.simOptions = this.options.simulatorOptions || {};
|
||||
this.ready = false;
|
||||
|
||||
if (this.options.deployment && this.options.deployment.accounts) {
|
||||
// Account setup
|
||||
this.simOptions.accounts = AccountParser.parseAccountsConfig(this.options.deployment.accounts, this.web3);
|
||||
this.initWeb3Provider();
|
||||
this.initDeployServices();
|
||||
}
|
||||
|
||||
// Reset contracts
|
||||
this.engine.contractsManager.contracts = cloneDeep(this.builtContracts);
|
||||
this.engine.contractsManager.compiledContracts = cloneDeep(this.compiledContracts);
|
||||
|
|
|
@ -3,6 +3,9 @@ const assert = require('assert');
|
|||
const sinon = require('sinon');
|
||||
const AccountParser = require('../lib/contracts/accountParser');
|
||||
let TestLogger = require('../lib/tests/test_logger.js');
|
||||
const Web3 = require('web3');
|
||||
const i18n = require('../lib/i18n/i18n.js');
|
||||
i18n.setOrDetectLocale('en');
|
||||
|
||||
describe('embark.AccountParser', function () {
|
||||
describe('#getAccount', function () {
|
||||
|
@ -25,7 +28,7 @@ describe('embark.AccountParser', function () {
|
|||
privateKey: 'myKey'
|
||||
}, web3, testLogger);
|
||||
|
||||
assert.deepEqual(account, {key: '0xmyKey'});
|
||||
assert.deepEqual(account, {key: '0xmyKey', hexBalance: null});
|
||||
});
|
||||
|
||||
it('should return two accounts from the keys in the file', function () {
|
||||
|
@ -34,8 +37,8 @@ describe('embark.AccountParser', function () {
|
|||
}, web3, testLogger);
|
||||
|
||||
assert.deepEqual(account, [
|
||||
{key: '0xkey1'},
|
||||
{key: '0xkey2'}
|
||||
{key: '0xkey1', hexBalance: null},
|
||||
{key: '0xkey2', hexBalance: null}
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -45,7 +48,7 @@ describe('embark.AccountParser', function () {
|
|||
}, web3, testLogger);
|
||||
|
||||
assert.deepEqual(account,
|
||||
[{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986"}]);
|
||||
[{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986", hexBalance: null}]);
|
||||
});
|
||||
|
||||
it('should return two accounts from the mnemonic using numAddresses', function () {
|
||||
|
@ -56,8 +59,8 @@ describe('embark.AccountParser', function () {
|
|||
|
||||
assert.deepEqual(account,
|
||||
[
|
||||
{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986"},
|
||||
{key: "0x88f37cfbaed8c0c515c62a17a3a1ce2f397d08bbf20dcc788b69f11b5a5c9791"}
|
||||
{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986", hexBalance: null},
|
||||
{key: "0x88f37cfbaed8c0c515c62a17a3a1ce2f397d08bbf20dcc788b69f11b5a5c9791", hexBalance: null}
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -68,6 +71,46 @@ describe('embark.AccountParser', function () {
|
|||
|
||||
assert.strictEqual(account, null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getHexBalance', () => {
|
||||
it('should return default if no balance', () => {
|
||||
const hexBalance = AccountParser.getHexBalance(null, Web3);
|
||||
|
||||
assert.strictEqual(hexBalance, 0xFFFFFFFFFFFFFFFFFF);
|
||||
});
|
||||
|
||||
it('should return the balance string if already hexadecimal', () => {
|
||||
const hexBalance = AccountParser.getHexBalance('0xFFF', Web3);
|
||||
|
||||
assert.strictEqual(hexBalance, '0xFFF');
|
||||
});
|
||||
|
||||
it('should convert to hex when decimal', () => {
|
||||
const hexBalance = AccountParser.getHexBalance('500', Web3);
|
||||
|
||||
assert.strictEqual(hexBalance, '0x1f4');
|
||||
});
|
||||
|
||||
it('should convert to hex with eth string', () => {
|
||||
const hexBalance = AccountParser.getHexBalance('4ether', Web3);
|
||||
|
||||
assert.strictEqual(hexBalance, '0x3782dace9d900000');
|
||||
});
|
||||
|
||||
it('should convert to hex with eth string with space', () => {
|
||||
const hexBalance = AccountParser.getHexBalance('673 shannon', Web3);
|
||||
|
||||
assert.strictEqual(hexBalance, '0x9cb1ed0a00');
|
||||
});
|
||||
|
||||
it('should fail when string is not good', () => {
|
||||
try {
|
||||
AccountParser.getHexBalance('nogood', Web3);
|
||||
assert.fail('Should have failed at getHexBalance');
|
||||
} catch (e) {
|
||||
// Ok
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
/*global contract, config, it, embark*/
|
||||
/*global contract, config, it, embark, web3*/
|
||||
const assert = require('assert');
|
||||
const AnotherStorage = embark.require('Embark/contracts/AnotherStorage');
|
||||
const SimpleStorage = embark.require('Embark/contracts/SimpleStorage');
|
||||
|
||||
let accounts;
|
||||
|
||||
config({
|
||||
deployment: {
|
||||
"accounts": [
|
||||
{
|
||||
"mnemonic": "example exile argue silk regular smile grass bomb merge arm assist farm",
|
||||
balance: "5ether"
|
||||
}
|
||||
]
|
||||
},
|
||||
contracts: {
|
||||
"SimpleStorage": {
|
||||
args: [100]
|
||||
|
@ -12,6 +22,8 @@ config({
|
|||
args: ["$SimpleStorage"]
|
||||
}
|
||||
}
|
||||
}, (err, theAccounts) => {
|
||||
accounts = theAccounts;
|
||||
});
|
||||
|
||||
contract("AnotherStorage", function() {
|
||||
|
@ -21,4 +33,10 @@ contract("AnotherStorage", function() {
|
|||
let result = await AnotherStorage.methods.simpleStorageAddress().call();
|
||||
assert.equal(result.toString(), SimpleStorage.options.address);
|
||||
});
|
||||
|
||||
it('should set the balance correctly', async function () {
|
||||
const balance = await web3.eth.getBalance(accounts[0]);
|
||||
assert.ok(balance < 5000000000000000000);
|
||||
assert.ok(balance > 4000000000000000000);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue