From eb4da28a6114f1acb6976dd566d9c9fcb1503add Mon Sep 17 00:00:00 2001 From: emizzle Date: Wed, 23 Jan 2019 15:57:24 +1100 Subject: [PATCH] fix(@embark/core): Fix tests for shim/monorepo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When embark was running as module inside the dapp’s `node_modules`, the tests were failing due to several issues: 1. `web3` was not being set in the global namespace of vm2. `EmbarkJS.Blockchain.setProvider` was therefore failing because it relies on `global.web3` to be set. I guess somehow this works when the test app was running in a child tree of the executing program. maybe this is a security feature of vm2, but i’m not sure. 2. `embarkjs` provider code being injected to the vm twice. This really was the initial point of failure, as this piece of code is requiring embarkjs, so i’m assuming, but again not sure, that maybe it was getting a second instance of `EmbarkJS` which did not have it’s providers set up correctly (hence the error with `ENS provider not set`). Fixes for those issues in this PR: 1. To circumvent the web3 issue, we are now setting `global.web3` for tests only (the global web3 accessible in the tests), and `web3` is now explicitly passed in to `EmbarkJS.Blockchain.setProvider` 2. To fix the `embarkjs` code being called twice, we are not re-injecting this code to the VM during test initialisations --- .../lib/core/modules/coderunner/codeRunner.js | 19 +++++ .../embark/src/lib/modules/tests/index.js | 28 ++++-- .../embark/src/lib/modules/tests/solc_test.js | 10 ++- packages/embark/src/lib/modules/tests/test.js | 85 ++++++++----------- packages/web3Connector/web3Connector.js | 1 + 5 files changed, 83 insertions(+), 60 deletions(-) diff --git a/packages/embark/src/lib/core/modules/coderunner/codeRunner.js b/packages/embark/src/lib/core/modules/coderunner/codeRunner.js index 1310f8d7c..8ce7f67b7 100644 --- a/packages/embark/src/lib/core/modules/coderunner/codeRunner.js +++ b/packages/embark/src/lib/core/modules/coderunner/codeRunner.js @@ -3,6 +3,7 @@ const fs = require('../../fs'); class CodeRunner { constructor(options) { + this.ready = false; this.config = options.config; this.plugins = options.plugins; this.logger = options.logger; @@ -38,6 +39,7 @@ class CodeRunner { this.registerEvents(); this.registerCommands(); this.events.emit('runcode:ready'); + this.ready = true; } registerIpcEvents() { @@ -74,6 +76,23 @@ class CodeRunner { cb(this.vm.options.sandbox); }); this.events.setCommandHandler('runcode:eval', this.evalCode.bind(this)); + this.events.setCommandHandler('runcode:ready', (cb) => { + if (this.ready) { + return cb(); + } + this.events.once("runcode:ready", cb); + }); + this.events.setCommandHandler('runcode:embarkjs:reset', this.resetEmbarkJS.bind(this)); + } + + resetEmbarkJS(cb) { + this.events.request('blockchain:get', (web3) => { + this.events.emit("runcode:register", "web3", web3, false, () => { + this.events.request("code-generator:embarkjs:init-provider-code", async (code) => { + await this.evalCode(code, cb, true); + }); + }); + }); } registerVar(varName, code, toRecord = true, cb = () => {}) { diff --git a/packages/embark/src/lib/modules/tests/index.js b/packages/embark/src/lib/modules/tests/index.js index eb2e2d445..500524254 100644 --- a/packages/embark/src/lib/modules/tests/index.js +++ b/packages/embark/src/lib/modules/tests/index.js @@ -16,6 +16,7 @@ class TestRunner { this.fs = embark.fs; this.ipc = options.ipc; this.runResults = []; + this.embarkjs = null; this.events.setCommandHandler('tests:run', (options, callback) => { this.run(options, callback); @@ -145,10 +146,10 @@ class TestRunner { runJSTests(files, options, cb) { const self = this; + const test = new Test({loglevel: options.loglevel, node: options.node, events: self.events, logger: self.logger, + config: self.embark.config, ipc: self.ipc, coverage: options.coverage, inProcess: options.inProcess}); async.waterfall([ function setupGlobalNamespace(next) { - const test = new Test({loglevel: options.loglevel, node: options.node, events: self.events, logger: self.logger, - config: self.embark.config, ipc: self.ipc, coverage: options.coverage, inProcess: options.inProcess}); global.embark = test; global.assert = assert; global.config = test.config.bind(test); @@ -162,20 +163,27 @@ class TestRunner { global.deployAll = deprecatedWarning; global.EmbarkSpec = {}; global.EmbarkSpec.deployAll = deprecatedWarning; - + global.contract = function (describeName, callback) { + return Mocha.describe(describeName, callback); + }; + next(); + }, + function overrideRequire (next) { // Override require to enable `require('Embark/contracts/contractName');` const Module = require('module'); const originalRequire = require('module').prototype.require; Module.prototype.require = function (requireName) { + if (requireName.startsWith('Embark/EmbarkJS')) { + return self.embarkjs; + } if (requireName.startsWith('Embark')) { return test.require(...arguments); } return originalRequire.apply(this, arguments); }; - - global.contract = function (describeName, callback) { - return Mocha.describe(describeName, callback); - }; + next(); + }, + function initTest(next) { test.init((err) => { next(err, files); @@ -200,7 +208,11 @@ class TestRunner { global.config({}); } global.embark.onReady((err) => { - done(err); + if(err) return done(err); + self.events.request('runcode:eval', 'EmbarkJS', (err, embarkjs) => { + self.embarkjs = embarkjs; + done(err); + }); }); }); mocha.run(function (fails) { diff --git a/packages/embark/src/lib/modules/tests/solc_test.js b/packages/embark/src/lib/modules/tests/solc_test.js index c0e2463bf..2a58b8f9a 100644 --- a/packages/embark/src/lib/modules/tests/solc_test.js +++ b/packages/embark/src/lib/modules/tests/solc_test.js @@ -120,10 +120,16 @@ class SolcTest extends Test { methodIdentifiers: contract.functionHashes } }; - remixTests.runTest(contract.className, Test.getWeb3Contract(contract, web3), contractDetails, {accounts}, - self._prettyPrint.bind(self), _callback); + this.getWeb3Contract(contract, web3, (err, web3contract) => { + if(err) { + return _callback(err); + } + remixTests.runTest(contract.className, web3contract, contractDetails, {accounts}, + self._prettyPrint.bind(self), _callback); + }); }; fns.push(fn); + }); async.series(fns, next); } diff --git a/packages/embark/src/lib/modules/tests/test.js b/packages/embark/src/lib/modules/tests/test.js index 2afe347d5..da42da92f 100644 --- a/packages/embark/src/lib/modules/tests/test.js +++ b/packages/embark/src/lib/modules/tests/test.js @@ -2,13 +2,10 @@ import * as utilsContractsConfig from "../../utils/contractsConfig"; const async = require('async'); const AccountParser = require('../../utils/accountParser'); -const EmbarkJS = require('embarkjs'); const utils = require('../../utils/utils'); const constants = require('../../constants'); const web3Utils = require('web3-utils'); -const VM = require('../../core/modules/coderunner/vm'); -const Web3 = require('web3'); -const IpfsApi = require("ipfs-api"); +const EmbarkJS = require('embarkjs'); const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000'; @@ -32,24 +29,26 @@ class Test { } init(callback) { - this.gasLimit = constants.tests.gasLimit; - this.events.request('deploy:setGasLimit', this.gasLimit); - const waitingForReady = setTimeout(() => { - this.logger.warn('Waiting for the blockchain connector to be ready...'); - // TODO add docs link to how to install one - this.logger.warn('If you did not install a blockchain connector, stop this process and install one'); - }, 5000); - this.events.request('blockchain:connector:ready', () => { - clearTimeout(waitingForReady); - if (this.options.node !== 'embark') { - this.showNodeHttpWarning(); - return callback(); - } - if (!this.ipc.connected) { - this.logger.error("Could not connect to Embark's IPC. Is embark running?"); - if (!this.options.inProcess) process.exit(1); - } - this.connectToIpcNode(callback); + this.events.request('runcode:ready', () => { + this.gasLimit = constants.tests.gasLimit; + this.events.request('deploy:setGasLimit', this.gasLimit); + const waitingForReady = setTimeout(() => { + this.logger.warn('Waiting for the blockchain connector to be ready...'); + // TODO add docs link to how to install one + this.logger.warn('If you did not install a blockchain connector, stop this process and install one'); + }, 5000); + this.events.request('blockchain:connector:ready', () => { + clearTimeout(waitingForReady); + if (this.options.node !== 'embark') { + this.showNodeHttpWarning(); + return callback(); + } + if (!this.ipc.connected) { + this.logger.error("Could not connect to Embark's IPC. Is embark running?"); + if (!this.options.inProcess) process.exit(1); + } + this.connectToIpcNode(callback); + }); }); } @@ -229,7 +228,6 @@ class Test { } self.ready = true; self.error = false; - self.events.emit('tests:ready'); next(null, accounts); }); }, @@ -243,31 +241,16 @@ class Test { // TODO Do not exit in case of not a normal run (eg after a change) if (!self.options.inProcess) process.exit(1); } + self.events.emit('tests:ready'); callback(null, accounts); }); } resetEmbarkJS(cb) { this.events.request('blockchain:get', (web3) => { + // global web3 used in the tests, not in the vm global.web3 = web3; - this.vm = new VM({ - sandbox: { - EmbarkJS, - web3: web3, - Web3: Web3, - IpfsApi - } - }); - this.events.request("code-generator:embarkjs:provider-code", (code) => { - this.vm.doEval(code, false, (err, _result) => { - if(err) return cb(err); - this.events.request("code-generator:embarkjs:init-provider-code", (code) => { - this.vm.doEval(code, false, (err, _result) => { - cb(err); - }); - }); - }); - }); + this.events.request("runcode:embarkjs:reset", cb); }); } @@ -339,7 +322,14 @@ class Test { const testContractFactoryPlugin = self.plugins.getPluginsFor('testContractFactory').slice(-1)[0]; - const newContract = testContractFactoryPlugin ? testContractFactoryPlugin.testContractFactory(contract, web3) : Test.getWeb3Contract(contract, web3); + if (!testContractFactoryPlugin) { + return self.getWeb3Contract(contract, web3, (err, web3Contract) => { + Object.setPrototypeOf(self.contracts[contract.className], web3Contract); + eachCb(); + }); + } + + const newContract = testContractFactoryPlugin.testContractFactory(contract, web3); Object.setPrototypeOf(self.contracts[contract.className], newContract); eachCb(); @@ -359,7 +349,7 @@ class Test { }); } - static getWeb3Contract(contract, web3) { + getWeb3Contract(contract, web3, cb) { const newContract = new EmbarkJS.Blockchain.Contract({ abi: contract.abiDefinition, address: contract.deployedAddress, @@ -378,11 +368,11 @@ class Test { newContract.options.gas = constants.tests.gasLimit; } - return newContract; + cb(null, newContract); } require(path) { - const [contractsPrefix, embarkJSPrefix] = ['Embark/contracts/', 'Embark/EmbarkJS']; + const contractsPrefix = 'Embark/contracts/'; // Contract require if (path.startsWith(contractsPrefix)) { @@ -397,11 +387,6 @@ class Test { return newContract; } - // EmbarkJS require - if (path.startsWith(embarkJSPrefix)) { - return EmbarkJS; - } - throw new Error(__('Unknown module %s', path)); } } diff --git a/packages/web3Connector/web3Connector.js b/packages/web3Connector/web3Connector.js index e107b1e9a..d7e2b9e52 100644 --- a/packages/web3Connector/web3Connector.js +++ b/packages/web3Connector/web3Connector.js @@ -2,6 +2,7 @@ const web3Connector = {}; web3Connector.init = function(_config) { + global.web3 = config.web3 || global.web3; // Check if the global web3 object uses the old web3 (0.x) if (global.web3 && typeof global.web3.version !== 'string') { // If so, use a new instance using 1.0, but use its provider