mirror of https://github.com/embarklabs/embark.git
feat(@embark/test-runner): make vm default node (#1846)
* feat: make vm default node * feat(@embark/tests): enable switching node between tests
This commit is contained in:
parent
2f9d5e6085
commit
f54fbf0b3d
|
@ -5,7 +5,7 @@ let accounts;
|
|||
|
||||
// For documentation please see https://embark.status.im/docs/contracts_testing.html
|
||||
config({
|
||||
//deployment: {
|
||||
//blockchain: {
|
||||
// accounts: [
|
||||
// // you can configure custom accounts with a custom balance
|
||||
// // see https://embark.status.im/docs/contracts_testing.html#Configuring-accounts
|
||||
|
@ -31,7 +31,7 @@ contract("SimpleStorage", function () {
|
|||
});
|
||||
|
||||
it("set storage value", async function () {
|
||||
await SimpleStorage.methods.set(150).send();
|
||||
await SimpleStorage.methods.set(150).send({from: web3.eth.defaultAccount});
|
||||
let result = await SimpleStorage.methods.get().call();
|
||||
assert.strictEqual(parseInt(result, 10), 150);
|
||||
});
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
"webpackDone": "webpackDone"
|
||||
},
|
||||
"blockchain": {
|
||||
"vm": "vm",
|
||||
"call": "eth_call",
|
||||
"clients": {
|
||||
"geth": "geth",
|
||||
|
|
|
@ -708,9 +708,7 @@ simulator(_options) {
|
|||
|
||||
const Engine = require('../lib/core/engine.js');
|
||||
const engine = new Engine({
|
||||
// TODO: this should not be necessary
|
||||
env: "development",
|
||||
//env: options.env,
|
||||
env: options.env,
|
||||
client: options.client,
|
||||
locale: options.locale,
|
||||
version: this.version,
|
||||
|
@ -743,23 +741,6 @@ simulator(_options) {
|
|||
engine.registerModuleGroup("pipeline");
|
||||
engine.registerModuleGroup("tests", options);
|
||||
|
||||
let plugin = engine.plugins.createPlugin('cmdcontrollerplugin', {});
|
||||
plugin.registerActionForEvent("embark:engine:started", async (_params, cb) => {
|
||||
try {
|
||||
await engine.events.request2("blockchain:node:start", engine.config.blockchainConfig);
|
||||
|
||||
await Promise.all([
|
||||
engine.events.request2("storage:node:start", engine.config.storageConfig),
|
||||
engine.events.request2("communication:node:start", engine.config.communicationConfig),
|
||||
engine.events.request2("namesystem:node:start", engine.config.namesystemConfig)
|
||||
]);
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
|
||||
cb();
|
||||
});
|
||||
|
||||
engine.startEngine(next);
|
||||
},
|
||||
function setupTestEnvironment(next) {
|
||||
|
|
|
@ -22,7 +22,7 @@ export function getBlockchainDefaults(env) {
|
|||
wsHost: "localhost",
|
||||
wsPort: 8546,
|
||||
networkType: "custom",
|
||||
miningMode: 'dev',
|
||||
isDev: true,
|
||||
nodiscover: true,
|
||||
maxpeers: 0,
|
||||
targetGasLimit: 8000000,
|
||||
|
|
|
@ -211,6 +211,7 @@ class Engine {
|
|||
|
||||
contractsComponents(_options) {
|
||||
this.registerModule('ethereum-blockchain-client');
|
||||
this.registerModule('ganache');
|
||||
this.registerModulePackage('embark-web3');
|
||||
this.registerModulePackage('embark-accounts-manager');
|
||||
this.registerModulePackage('embark-specialconfigs', {plugins: this.plugins});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import async from 'async';
|
||||
const {__} = require('embark-i18n');
|
||||
const constants = require('embark-core/constants');
|
||||
const Web3RequestManager = require('web3-core-requestmanager');
|
||||
|
||||
import BlockchainAPI from "./api";
|
||||
|
@ -12,7 +13,7 @@ class Blockchain {
|
|||
this.blockchainConfig = embark.config.blockchainConfig;
|
||||
this.contractConfig = embark.config.contractConfig;
|
||||
this.blockchainApi = new BlockchainAPI(embark);
|
||||
|
||||
this.startedClient = null;
|
||||
|
||||
embark.registerActionForEvent("pipeline:generateAll:before", this.addArtifactFile.bind(this));
|
||||
|
||||
|
@ -22,6 +23,16 @@ class Blockchain {
|
|||
});
|
||||
|
||||
this.events.setCommandHandler("blockchain:node:start", async (blockchainConfig, cb) => {
|
||||
const self = this;
|
||||
const clientName = blockchainConfig.client;
|
||||
function started() {
|
||||
self.startedClient = clientName;
|
||||
self.events.emit("blockchain:started", clientName);
|
||||
}
|
||||
if (clientName === constants.blockchain.vm) {
|
||||
started();
|
||||
return cb();
|
||||
}
|
||||
const requestManager = new Web3RequestManager.Manager(blockchainConfig.endpoint);
|
||||
|
||||
const ogConsoleError = console.error;
|
||||
|
@ -37,21 +48,52 @@ class Blockchain {
|
|||
console.error = ogConsoleError;
|
||||
if (!err) {
|
||||
// Node is already started
|
||||
this.events.emit("blockchain:started");
|
||||
started();
|
||||
return cb(null, true);
|
||||
}
|
||||
const clientName = blockchainConfig.client;
|
||||
const client = this.blockchainNodes[clientName];
|
||||
if (!client) return cb("client " + clientName + " not found");
|
||||
const clientFunctions = this.blockchainNodes[clientName];
|
||||
if (!clientFunctions) {
|
||||
return cb(__("Client %s not found", clientName));
|
||||
}
|
||||
|
||||
let onStart = () => {
|
||||
this.events.emit("blockchain:started", clientName);
|
||||
started();
|
||||
cb();
|
||||
};
|
||||
|
||||
client.apply(client, [onStart]);
|
||||
this.startedClient = clientName;
|
||||
clientFunctions.launchFn.apply(clientFunctions, [onStart]);
|
||||
});
|
||||
});
|
||||
|
||||
this.events.setCommandHandler("blockchain:node:stop", (clientName, cb) => {
|
||||
if (typeof clientName === 'function') {
|
||||
if (!this.startedClient) {
|
||||
return cb(__('No blockchain client is currently started'));
|
||||
}
|
||||
cb = clientName;
|
||||
clientName = this.startedClient;
|
||||
}
|
||||
|
||||
if (clientName === constants.blockchain.vm) {
|
||||
this.startedClient = null;
|
||||
this.events.emit("blockchain:stopped", clientName);
|
||||
return cb();
|
||||
}
|
||||
|
||||
const clientFunctions = this.blockchainNodes[clientName];
|
||||
if (!clientFunctions) {
|
||||
return cb(__("Client %s not found", clientName));
|
||||
}
|
||||
|
||||
clientFunctions.stopFn.apply(clientFunctions, [
|
||||
() => {
|
||||
this.events.emit("blockchain:stopped", clientName);
|
||||
cb();
|
||||
}
|
||||
]);
|
||||
this.startedClient = null;
|
||||
});
|
||||
this.blockchainApi.registerAPIs("ethereum");
|
||||
this.blockchainApi.registerRequests("ethereum");
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@ class EthereumBlockchainClient {
|
|||
this.events.request("blockchain:client:register", "ethereum", this.getClient.bind(this));
|
||||
this.events.request("deployment:deployer:register", "ethereum", this.deployer.bind(this));
|
||||
|
||||
this.events.on("blockchain:started", () => {
|
||||
this._web3 = null;
|
||||
});
|
||||
|
||||
this.registerAPIRequests();
|
||||
}
|
||||
|
||||
|
@ -54,23 +58,18 @@ class EthereumBlockchainClient {
|
|||
|
||||
async deployer(contract, done) {
|
||||
const web3 = await this.web3;
|
||||
// var web3 = new Web3("ws://localhost:8556")
|
||||
// web3.eth.getAccounts().then((accounts) => {
|
||||
let accounts = await web3.eth.getAccounts();
|
||||
let account = accounts[0];
|
||||
// let contractObject = this.blockchain.ContractObject({abi: contract.abiDefinition});
|
||||
let contractObj = new web3.eth.Contract(contract.abiDefinition, contract.address);
|
||||
// let deployObject = this.blockchain.deployContractObject(contractObject, {arguments: contractParams, data: dataCode});
|
||||
let contractObject = contractObj.deploy({arguments: (contract.args || []), data: ("0x" + contract.code)});
|
||||
const [account] = await web3.eth.getAccounts();
|
||||
const contractObj = new web3.eth.Contract(contract.abiDefinition, contract.address);
|
||||
const contractObject = contractObj.deploy({arguments: (contract.args || []), data: ("0x" + contract.code)});
|
||||
|
||||
if (contract.gas === 'auto' || !contract.gas) {
|
||||
let gasValue = await contractObject.estimateGas();
|
||||
let increase_per = 1 + (Math.random() / 10.0);
|
||||
const gasValue = await contractObject.estimateGas();
|
||||
const increase_per = 1 + (Math.random() / 10.0);
|
||||
contract.gas = Math.floor(gasValue * increase_per);
|
||||
}
|
||||
|
||||
if (!contract.gasPrice) {
|
||||
let gasPrice = await web3.eth.getGasPrice();
|
||||
const gasPrice = await web3.eth.getGasPrice();
|
||||
contract.gasPrice = contract.gasPrice || gasPrice;
|
||||
}
|
||||
|
||||
|
@ -198,8 +197,7 @@ class EthereumBlockchainClient {
|
|||
}
|
||||
|
||||
async determineAccounts(params, callback) {
|
||||
let provider = await this.events.request2("blockchain:client:provider", "ethereum");
|
||||
let web3 = new Web3(provider);
|
||||
const web3 = await this.web3;
|
||||
let accounts = await web3.eth.getAccounts();
|
||||
let deploymentAccount = accounts[0];
|
||||
let contract = params.contract;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
class Ganache {
|
||||
constructor(embark) {
|
||||
embark.events.request('proxy:vm:register', () => {
|
||||
const ganache = require('ganache-cli');
|
||||
return ganache.provider();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ganache;
|
|
@ -6,7 +6,6 @@ import {ws, rpc} from './check.js';
|
|||
const constants = require('embark-core/constants');
|
||||
|
||||
class Geth {
|
||||
|
||||
constructor(embark, options) {
|
||||
this.embark = embark;
|
||||
this.embarkConfig = embark.config.embarkConfig;
|
||||
|
@ -23,22 +22,28 @@ class Geth {
|
|||
return;
|
||||
}
|
||||
|
||||
this.events.request("blockchain:node:register", constants.blockchain.clients.geth, (readyCb) => {
|
||||
this.events.request('processes:register', 'blockchain', {
|
||||
launchFn: (cb) => {
|
||||
this.startBlockchainNode(cb);
|
||||
},
|
||||
stopFn: (cb) => {
|
||||
this.stopBlockchainNode(cb);
|
||||
}
|
||||
});
|
||||
this.events.request("processes:launch", "blockchain", (err) => {
|
||||
if (err) {
|
||||
this.logger.error(`Error launching blockchain process: ${err.message || err}`);
|
||||
}
|
||||
readyCb();
|
||||
});
|
||||
this.registerServiceCheck();
|
||||
this.events.request("blockchain:node:register", constants.blockchain.clients.geth, {
|
||||
launchFn: (readyCb) => {
|
||||
this.events.request('processes:register', 'blockchain', {
|
||||
launchFn: (cb) => {
|
||||
this.startBlockchainNode(cb);
|
||||
},
|
||||
stopFn: (cb) => {
|
||||
this.stopBlockchainNode(cb);
|
||||
}
|
||||
});
|
||||
this.events.request("processes:launch", "blockchain", (err) => {
|
||||
if (err) {
|
||||
this.logger.error(`Error launching blockchain process: ${err.message || err}`);
|
||||
}
|
||||
readyCb();
|
||||
});
|
||||
this.registerServiceCheck();
|
||||
},
|
||||
stopFn: async (cb) => {
|
||||
await this.events.request("processes:stop", "blockchain");
|
||||
cb();
|
||||
}
|
||||
});
|
||||
|
||||
this.events.request("whisper:node:register", constants.blockchain.clients.geth, readyCb => {
|
||||
|
|
|
@ -34,6 +34,10 @@ export default class AccountsManager {
|
|||
this.embark.registerActionForEvent("blockchain:proxy:request", this.checkBlockchainRequest.bind(this));
|
||||
this.embark.registerActionForEvent("blockchain:proxy:response", this.checkBlockchainResponse.bind(this));
|
||||
|
||||
this.events.on("blockchain:started", () => {
|
||||
this._web3 = null;
|
||||
});
|
||||
|
||||
// Allow to run transaction in parallel by resolving the nonce manually.
|
||||
// For each transaction, resolve the nonce by taking the max of current transaction count and the cache we keep locally.
|
||||
// Update the nonce and sign it
|
||||
|
|
|
@ -9,6 +9,10 @@ export default class DeploymentChecks {
|
|||
this.events = events;
|
||||
this.logger = logger;
|
||||
this._web3 = null;
|
||||
|
||||
this.events.on("blockchain:started", () => {
|
||||
this._web3 = null;
|
||||
});
|
||||
}
|
||||
|
||||
get web3() {
|
||||
|
|
|
@ -17,6 +17,10 @@ export default class TrackingFunctions {
|
|||
this._block = null;
|
||||
|
||||
this.ensureChainTrackerFile();
|
||||
|
||||
this.events.on("blockchain:started", () => {
|
||||
this._web3 = null;
|
||||
});
|
||||
}
|
||||
|
||||
get web3() {
|
||||
|
|
|
@ -84,6 +84,10 @@ class ENS {
|
|||
setImmediate(cb, this.isENSName(name));
|
||||
});
|
||||
|
||||
this.events.on("blockchain:started", () => {
|
||||
this._web3 = null;
|
||||
});
|
||||
|
||||
this.init(() => {});
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,14 @@
|
|||
},
|
||||
"extends": "../../../.eslintrc.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime-corejs2": "7.3.1",
|
||||
"async": "3.1.0",
|
||||
"embark-i18n": "^4.1.1",
|
||||
"embark-utils": "^4.1.1",
|
||||
"mocha": "6.2.0",
|
||||
"web3": "1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.2.3",
|
||||
"@babel/core": "7.2.2",
|
||||
|
@ -60,12 +68,7 @@
|
|||
"tslint": "5.16.0",
|
||||
"typescript": "3.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "2.6.1",
|
||||
"embarkjs": "^4.1.1",
|
||||
"mocha": "6.2.0",
|
||||
"web3": "1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.12.0 <12.0.0",
|
||||
"npm": ">=6.4.1",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {__} from 'embark-i18n';
|
||||
|
||||
const assert = require('assert').strict;
|
||||
const async = require('async');
|
||||
const EmbarkJS = require('embarkjs');
|
||||
|
@ -14,8 +16,12 @@ class MochaTestRunner {
|
|||
this.embark = embark;
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
this.logger = embark.logger;
|
||||
this.fs = embark.fs;
|
||||
|
||||
this.files = [];
|
||||
this.options = {};
|
||||
this.web3 = null;
|
||||
|
||||
this.events.request('tests:runner:register',
|
||||
'JavaScript (Mocha)',
|
||||
|
@ -37,20 +43,31 @@ class MochaTestRunner {
|
|||
return JAVASCRIPT_TEST_MATCH.test(path);
|
||||
}
|
||||
|
||||
run(options, cb) {
|
||||
const {events, plugins} = this;
|
||||
async run(options, cb) {
|
||||
const {events} = this.embark;
|
||||
const {reporter} = options;
|
||||
this.options = options;
|
||||
|
||||
const Module = require("module");
|
||||
const originalRequire = require("module").prototype.require;
|
||||
|
||||
let accounts = [];
|
||||
let compiledContracts = {};
|
||||
let web3;
|
||||
|
||||
const config = (cfg, acctCb) => {
|
||||
global.before((done) => {
|
||||
async.waterfall([
|
||||
(next) => {
|
||||
events.request("tests:deployment:check", cfg, this.options, (err, provider) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (provider) {
|
||||
this.web3.setProvider(provider);
|
||||
}
|
||||
next();
|
||||
});
|
||||
},
|
||||
(next) => {
|
||||
events.request("contracts:build", cfg, compiledContracts, next);
|
||||
},
|
||||
|
@ -86,6 +103,12 @@ class MochaTestRunner {
|
|||
}
|
||||
|
||||
next();
|
||||
},
|
||||
(next) => {
|
||||
this.web3.eth.getAccounts((err, accts) => {
|
||||
accounts = accts;
|
||||
next(err);
|
||||
});
|
||||
}
|
||||
], (err) => {
|
||||
// Reset the gas accumulator so that we don't show deployment gas on the
|
||||
|
@ -102,73 +125,79 @@ class MochaTestRunner {
|
|||
});
|
||||
};
|
||||
|
||||
const provider = await this.events.request2("tests:blockchain:start", this.options);
|
||||
this.web3 = new Web3(provider);
|
||||
accounts = await this.web3.eth.getAccounts();
|
||||
await events.request2("contracts:reset");
|
||||
let contractFiles = await events.request2("config:contractsFiles");
|
||||
|
||||
async.waterfall([
|
||||
(next) => { // request provider
|
||||
events.request("blockchain:client:provider", "ethereum", next);
|
||||
(next) => {
|
||||
this.plugins.emitAndRunActionsForEvent('tests:contracts:compile:before', contractFiles, next);
|
||||
},
|
||||
(provider, next) => { // set provider and fetch account list
|
||||
web3 = new Web3(provider);
|
||||
web3.eth.getAccounts(next);
|
||||
(_contractFiles, next) => {
|
||||
contractFiles = _contractFiles;
|
||||
events.request("compiler:contracts:compile", _contractFiles, next);
|
||||
},
|
||||
(accts, next) => { // reset contracts as we might have state leakage from other plugins
|
||||
accounts = accts;
|
||||
events.request("contracts:reset", next);
|
||||
(_compiledContracts, next) => {
|
||||
this.plugins.emitAndRunActionsForEvent('tests:contracts:compile:after', _compiledContracts, next);
|
||||
},
|
||||
(next) => { // get contract files
|
||||
events.request("config:contractsFiles", next);
|
||||
},
|
||||
(cf, next) => {
|
||||
plugins.emitAndRunActionsForEvent('tests:contracts:compile:before', cf, next);
|
||||
},
|
||||
(cf, next) => { // compile contracts
|
||||
events.request("compiler:contracts:compile", cf, next);
|
||||
},
|
||||
(cc, next) => {
|
||||
plugins.emitAndRunActionsForEvent('tests:contracts:compile:after', cc, next);
|
||||
},
|
||||
(cc, next) => { // override require
|
||||
compiledContracts = cc;
|
||||
(_compiledContracts, next) => {
|
||||
compiledContracts = _compiledContracts;
|
||||
const fns = this.files.map((file) => {
|
||||
return (seriesCb) => {
|
||||
|
||||
Module.prototype.require = function(req) {
|
||||
const prefix = "Embark/contracts/";
|
||||
if (!req.startsWith(prefix)) {
|
||||
return originalRequire.apply(this, arguments);
|
||||
}
|
||||
this.fs.readFile(file, (err, data) => {
|
||||
if (err) {
|
||||
self.logger.error(__('Error reading file %s', file));
|
||||
self.logger.error(err);
|
||||
seriesCb(null, 1);
|
||||
}
|
||||
if (data.toString().search(/contract\(|describe\(/) === -1) {
|
||||
return seriesCb(null, 0);
|
||||
}
|
||||
|
||||
const contractClass = req.replace(prefix, "");
|
||||
const instance = compiledContracts[contractClass];
|
||||
Module.prototype.require = function(req) {
|
||||
const prefix = "Embark/contracts/";
|
||||
if (!req.startsWith(prefix)) {
|
||||
return originalRequire.apply(this, arguments);
|
||||
}
|
||||
|
||||
if (!instance) {
|
||||
throw new Error(`Cannot find module '${req}'`);
|
||||
}
|
||||
const contractClass = req.replace(prefix, "");
|
||||
const instance = compiledContracts[contractClass];
|
||||
|
||||
return instance;
|
||||
};
|
||||
next();
|
||||
},
|
||||
(next) => { // initialize Mocha
|
||||
const mocha = new Mocha();
|
||||
if (!instance) {
|
||||
throw new Error(`Cannot find module '${req}'`);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
mocha.reporter(Reporter, { reporter: reporter });
|
||||
const describeWithAccounts = (scenario, cb) => {
|
||||
Mocha.describe(scenario, cb.bind(mocha, accounts));
|
||||
};
|
||||
const mocha = new Mocha();
|
||||
mocha.reporter(Reporter, {reporter: options.reporter});
|
||||
const describeWithAccounts = (scenario, cb) => {
|
||||
Mocha.describe(scenario, cb.bind(mocha, accounts));
|
||||
};
|
||||
|
||||
mocha.suite.on('pre-require', () => {
|
||||
global.describe = describeWithAccounts;
|
||||
global.contract = describeWithAccounts;
|
||||
global.assert = assert;
|
||||
global.config = config;
|
||||
mocha.suite.on('pre-require', () => {
|
||||
global.describe = describeWithAccounts;
|
||||
global.contract = describeWithAccounts;
|
||||
global.assert = assert;
|
||||
global.config = config;
|
||||
});
|
||||
|
||||
|
||||
mocha.suite.timeout(TEST_TIMEOUT);
|
||||
mocha.addFile(file);
|
||||
|
||||
mocha.run((failures) => {
|
||||
Module.prototype.require = originalRequire;
|
||||
seriesCb(null, failures);
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
mocha.suite.timeout(TEST_TIMEOUT);
|
||||
for(const file of this.files) {
|
||||
mocha.addFile(file);
|
||||
}
|
||||
|
||||
mocha.run((_failures) => {
|
||||
next();
|
||||
});
|
||||
async.series(fns, next);
|
||||
}
|
||||
], (err) => {
|
||||
events.emit('tests:finished');
|
||||
|
|
|
@ -10,6 +10,9 @@ class TransactionTracker {
|
|||
this._web3 = null;
|
||||
|
||||
embark.events.on("block:header", this.onBlockHeader.bind(this));
|
||||
this.events.on("blockchain:started", () => {
|
||||
this._web3 = null;
|
||||
});
|
||||
this.registerAPICalls();
|
||||
this.subscribeToPendingTransactions();
|
||||
}
|
||||
|
|
|
@ -40,11 +40,6 @@ class EmbarkWeb3 {
|
|||
}
|
||||
|
||||
async registerWeb3Object() {
|
||||
const checkWeb3 = `return (typeof web3 === 'undefined');`;
|
||||
const web3NotDefined = await this.events.request2('runcode:eval', checkWeb3);
|
||||
|
||||
if (!web3NotDefined) return;
|
||||
|
||||
const provider = await this.events.request2("blockchain:client:provider", "ethereum");
|
||||
const web3 = new Web3(provider);
|
||||
await this.events.request2("runcode:register", 'web3', web3);
|
||||
|
|
|
@ -44,6 +44,10 @@ class ContractsManager {
|
|||
cb(null, this.contracts[contract.className]);
|
||||
});
|
||||
|
||||
this.events.on("blockchain:started", () => {
|
||||
this._web3 = null;
|
||||
});
|
||||
|
||||
this.registerCommands();
|
||||
this.registerAPIs();
|
||||
}
|
||||
|
@ -262,6 +266,9 @@ class ContractsManager {
|
|||
function prepareContractsFromConfig(callback) {
|
||||
self.events.emit("status", __("Building..."));
|
||||
|
||||
if (contractsConfig.contracts.deploy) {
|
||||
contractsConfig.contracts = contractsConfig.contracts.deploy;
|
||||
}
|
||||
async.eachOf(contractsConfig.contracts, (contract, className, eachCb) => {
|
||||
contract = new Contract(self.logger, contract);
|
||||
if (!contract.artifact) {
|
||||
|
|
|
@ -13,7 +13,6 @@ class ContractDeployer {
|
|||
}
|
||||
|
||||
deployContract(contract, callback) {
|
||||
|
||||
async.waterfall([
|
||||
(next) => {
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:contract:beforeDeploy', {contract: contract}, (err, _params) => {
|
||||
|
@ -22,7 +21,6 @@ class ContractDeployer {
|
|||
});
|
||||
},
|
||||
(next) => {
|
||||
// self.plugins.emitAndRunActionsForEvent('deployment:contract:arguments', {contract: contract}, (_params) => {
|
||||
this.plugins.emitAndRunActionsForEvent('deployment:contract:shouldDeploy', {contract: contract, shouldDeploy: true}, (err, params) => {
|
||||
next(err, params);
|
||||
});
|
||||
|
|
|
@ -11,26 +11,29 @@ export default class ProxyManager {
|
|||
private proxy: any;
|
||||
private plugins: any;
|
||||
private readonly host: string;
|
||||
private rpcPort: number;
|
||||
private wsPort: number;
|
||||
private ready: boolean;
|
||||
private rpcPort = 0;
|
||||
private wsPort = 0;
|
||||
private ready = false;
|
||||
private isWs = false;
|
||||
private vms: any[];
|
||||
|
||||
constructor(private embark: Embark, options: any) {
|
||||
this.logger = embark.logger;
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
this.ready = false;
|
||||
this.rpcPort = 0;
|
||||
this.wsPort = 0;
|
||||
this.vms = [];
|
||||
|
||||
this.host = "localhost";
|
||||
|
||||
this.events.once("blockchain:started", async () => {
|
||||
await this.setupProxy();
|
||||
this.events.on("blockchain:started", async (clientName: string) => {
|
||||
await this.setupProxy(clientName);
|
||||
this.ready = true;
|
||||
this.events.emit("proxy:ready");
|
||||
});
|
||||
this.events.on("blockchain:stopped", async (clientName: string, node?: string) => {
|
||||
this.ready = false;
|
||||
await this.stopProxy();
|
||||
});
|
||||
|
||||
if (!this.embark.config.blockchainConfig.proxy) {
|
||||
this.logger.warn(__("The proxy has been disabled -- some Embark features will not work."));
|
||||
|
@ -48,6 +51,10 @@ export default class ProxyManager {
|
|||
}
|
||||
cb(null, buildUrl("http", this.host, this.rpcPort, "rpc"));
|
||||
});
|
||||
|
||||
this.events.setCommandHandler("proxy:vm:register", (handler: any) => {
|
||||
this.vms.push(handler);
|
||||
});
|
||||
}
|
||||
|
||||
public onReady() {
|
||||
|
@ -61,23 +68,31 @@ export default class ProxyManager {
|
|||
});
|
||||
}
|
||||
|
||||
private async setupProxy() {
|
||||
private async setupProxy(clientName: string) {
|
||||
if (!this.embark.config.blockchainConfig.proxy) {
|
||||
return;
|
||||
}
|
||||
if (this.proxy) {
|
||||
throw new Error("Proxy is already started");
|
||||
}
|
||||
const port = await findNextPort(this.embark.config.blockchainConfig.rpcPort + constants.blockchain.servicePortOnProxy);
|
||||
|
||||
this.rpcPort = port;
|
||||
this.wsPort = port + 1;
|
||||
this.isWs = (/wss?/).test(this.embark.config.blockchainConfig.endpoint);
|
||||
this.isWs = clientName === constants.blockchain.vm || (/wss?/).test(this.embark.config.blockchainConfig.endpoint);
|
||||
|
||||
this.proxy = await new Proxy({events: this.events, plugins: this.plugins, logger: this.logger})
|
||||
.serve(
|
||||
this.embark.config.blockchainConfig.endpoint,
|
||||
this.host,
|
||||
this.isWs ? this.wsPort : this.rpcPort,
|
||||
this.isWs,
|
||||
);
|
||||
return;
|
||||
this.proxy = await new Proxy({events: this.events, plugins: this.plugins, logger: this.logger, vms: this.vms});
|
||||
|
||||
await this.proxy.serve(
|
||||
clientName === constants.blockchain.vm ? constants.blockchain.vm : this.embark.config.blockchainConfig.endpoint,
|
||||
this.host,
|
||||
this.isWs ? this.wsPort : this.rpcPort,
|
||||
this.isWs,
|
||||
);
|
||||
}
|
||||
|
||||
private stopProxy() {
|
||||
this.proxy.stop();
|
||||
this.proxy = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import express from 'express';
|
|||
import expressWs from 'express-ws';
|
||||
import cors from 'cors';
|
||||
const Web3RequestManager = require('web3-core-requestmanager');
|
||||
const constants = require("embark-core/constants");
|
||||
|
||||
const ACTION_TIMEOUT = 5000;
|
||||
|
||||
|
@ -15,9 +16,15 @@ export class Proxy {
|
|||
this.timeouts = {};
|
||||
this.plugins = options.plugins;
|
||||
this.logger = options.logger;
|
||||
this.vms = options.vms;
|
||||
this.app = null;
|
||||
this.server = null;
|
||||
}
|
||||
|
||||
async serve(endpoint, localHost, localPort, ws) {
|
||||
if (endpoint === constants.blockchain.vm) {
|
||||
endpoint = this.vms[this.vms.length - 1]();
|
||||
}
|
||||
const requestManager = new Web3RequestManager.Manager(endpoint);
|
||||
|
||||
try {
|
||||
|
@ -26,17 +33,17 @@ export class Proxy {
|
|||
throw new Error(__('Unable to connect to the blockchain endpoint'));
|
||||
}
|
||||
|
||||
const app = express();
|
||||
this.app = express();
|
||||
if (ws) {
|
||||
expressWs(app);
|
||||
expressWs(this.app);
|
||||
}
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({extended: true}));
|
||||
this.app.use(cors());
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded({extended: true}));
|
||||
|
||||
if (ws) {
|
||||
app.ws('/', (ws, _wsReq) => {
|
||||
this.app.ws('/', (ws, _wsReq) => {
|
||||
ws.on('message', (msg) => {
|
||||
let jsonMsg;
|
||||
try {
|
||||
|
@ -50,7 +57,7 @@ export class Proxy {
|
|||
// Send the possibly modified request to the Node
|
||||
requestManager.send(resp.reqData, (err, result) => {
|
||||
if (err) {
|
||||
return this.logger.error(__('Error executing the request on the Node'), JSON.stringify(err));
|
||||
return this.logger.error(__('Error executing the request on the Node'), err.message || err);
|
||||
}
|
||||
this.emitActionsForResponse(resp.reqData, {jsonrpc: "2.0", id: resp.reqData.id, result}, (_err, resp) => {
|
||||
// Send back to the caller (web3)
|
||||
|
@ -62,7 +69,7 @@ export class Proxy {
|
|||
});
|
||||
} else {
|
||||
// HTTP
|
||||
app.use((req, res) => {
|
||||
this.app.use((req, res) => {
|
||||
// Modify request
|
||||
this.emitActionsForRequest(req.body, (_err, resp) => {
|
||||
// Send the possibly modified request to the Node
|
||||
|
@ -80,9 +87,9 @@ export class Proxy {
|
|||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
app.listen(localPort, localHost, null,
|
||||
this.server = this.app.listen(localPort, localHost, null,
|
||||
() => {
|
||||
resolve(app);
|
||||
resolve(this.app);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -147,4 +154,17 @@ export class Proxy {
|
|||
calledBack = true;
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (!this.server) {
|
||||
return;
|
||||
}
|
||||
this.server.close();
|
||||
this.server = null;
|
||||
this.app = null;
|
||||
this.commList = {};
|
||||
this.receipts = {};
|
||||
this.transactions = {};
|
||||
this.timeouts = {};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { __ } from 'embark-i18n';
|
||||
import {buildUrl, deconstructUrl, recursiveMerge} from "embark-utils";
|
||||
const async = require('async');
|
||||
const chalk = require('chalk');
|
||||
const path = require('path');
|
||||
const { dappPath } = require('embark-utils');
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { COVERAGE_GAS_LIMIT, GAS_LIMIT } from './constants';
|
||||
const constants = require('embark-core/constants');
|
||||
|
||||
const coverage = require('istanbul-lib-coverage');
|
||||
const reporter = require('istanbul-lib-report');
|
||||
|
@ -22,6 +25,10 @@ class TestRunner {
|
|||
this.gasLimit = options.coverage ? COVERAGE_GAS_LIMIT : GAS_LIMIT;
|
||||
this.files = [];
|
||||
|
||||
this.configObj = embark.config;
|
||||
this.originalConfigObj = cloneDeep(embark.config);
|
||||
this.simOptions = {};
|
||||
|
||||
this.events.setCommandHandler('tests:run', (options, callback) => {
|
||||
this.run(options, callback);
|
||||
});
|
||||
|
@ -32,6 +39,9 @@ class TestRunner {
|
|||
// like Jest tests and such.
|
||||
this.runners.unshift({pluginName, matchFn, addFn, runFn});
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('tests:deployment:check', this.checkDeploymentOptions.bind(this));
|
||||
this.events.setCommandHandler('tests:blockchain:start', this.startBlockchainNode.bind(this));
|
||||
}
|
||||
|
||||
run(options, cb) {
|
||||
|
@ -65,7 +75,7 @@ class TestRunner {
|
|||
});
|
||||
|
||||
async.series(runnerFns, next);
|
||||
},
|
||||
}
|
||||
], (err) => {
|
||||
reporter.footer();
|
||||
|
||||
|
@ -85,16 +95,16 @@ class TestRunner {
|
|||
open(dappPath('coverage/index.html')).then(() => {
|
||||
cb(err, reporter.passes, reporter.fails);
|
||||
});
|
||||
} catch(err) {
|
||||
process.stdout.write(chalk`{red Coverage report could not be created:}\n{white ${err.message}}\n`);
|
||||
cb(err, reporter.passes, reporter.fails);
|
||||
} catch(e) {
|
||||
process.stdout.write(chalk`{red Coverage report could not be created:}\n{white ${e.message}}\n`);
|
||||
cb(e, reporter.passes, reporter.fails);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
generateCoverageReport() {
|
||||
const coveragePath = dappPath(".embark", "coverage.json");
|
||||
const coverageMap = JSON.parse(fs.readFileSync(coveragePath));
|
||||
const coverageMap = JSON.parse(this.fs.readFileSync(coveragePath));
|
||||
const map = coverage.createCoverageMap(coverageMap);
|
||||
const tree = reporter.summarizers.nested(map);
|
||||
|
||||
|
@ -131,6 +141,77 @@ class TestRunner {
|
|||
cb(null, [filePath]);
|
||||
});
|
||||
}
|
||||
|
||||
async checkDeploymentOptions(config, options, cb = () => {}) {
|
||||
let resetServices = false;
|
||||
const blockchainConfig = config.blockchain || {};
|
||||
let {host, port, type, protocol} = blockchainConfig.endpoint ? deconstructUrl(blockchainConfig.endpoint) : {};
|
||||
const accounts = blockchainConfig.accounts;
|
||||
|
||||
if (host && port && !['rpc', 'ws'].includes(type)) {
|
||||
return cb(__("contracts config error: unknown deployment type %s", type));
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
type = constants.blockchain.vm;
|
||||
}
|
||||
|
||||
if (accounts || port !== this.simOptions.port || type !== this.simOptions.type || host !== this.simOptions.host) {
|
||||
resetServices = true;
|
||||
}
|
||||
|
||||
Object.assign(this.simOptions, {host, port, type, protocol, accounts, client: config.blockchain && config.blockchain.client});
|
||||
|
||||
if (!resetServices) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
const provider = await this.startBlockchainNode(options);
|
||||
cb(null, provider);
|
||||
return provider;
|
||||
}
|
||||
|
||||
async startBlockchainNode(options, cb = () => {}) {
|
||||
let node = options.node;
|
||||
if (!this.simOptions.host && (node && node === constants.blockchain.vm)) {
|
||||
this.simOptions.type = constants.blockchain.vm;
|
||||
this.simOptions.client = constants.blockchain.vm;
|
||||
} else if (this.simOptions.host || (node && node !== constants.blockchain.vm)) {
|
||||
let options = this.simOptions;
|
||||
if (node && node !== constants.blockchain.vm) {
|
||||
options = deconstructUrl(node);
|
||||
}
|
||||
|
||||
if (!options.protocol) {
|
||||
options.protocol = (options.type === "rpc") ? 'http' : 'ws';
|
||||
}
|
||||
Object.assign(this.simOptions, options);
|
||||
node = null;
|
||||
}
|
||||
|
||||
this.configObj.blockchainConfig = recursiveMerge({}, this.originalConfigObj.blockchainConfig, {
|
||||
endpoint: this.simOptions.host ? buildUrl(this.simOptions.protocol, this.simOptions.host, this.simOptions.port, this.simOptions.type) : null,
|
||||
type: this.simOptions.type,
|
||||
accounts: this.simOptions.accounts,
|
||||
coverage: options.coverage
|
||||
});
|
||||
if (this.simOptions.client) {
|
||||
this.configObj.blockchainConfig.client = this.simOptions.client;
|
||||
}
|
||||
this.logger.trace('Setting blockchain configs:', this.configObj.blockchainConfig);
|
||||
await this.events.request2('config:blockchainConfig:set', this.configObj.blockchainConfig);
|
||||
|
||||
try {
|
||||
await this.events.request2("blockchain:node:stop");
|
||||
} catch (e) {
|
||||
// Nothing to do here, the node probably wasn't even started
|
||||
}
|
||||
|
||||
await this.events.request2("blockchain:node:start", this.configObj.blockchainConfig);
|
||||
const provider = await this.events.request2("blockchain:client:provider", "ethereum");
|
||||
cb(null, provider);
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TestRunner;
|
||||
|
|
Loading…
Reference in New Issue