make code coverage work with refactored tests
This commit is contained in:
parent
7516bad619
commit
f4d7636b7a
|
@ -557,6 +557,8 @@ class EmbarkController {
|
||||||
engine.startService("web3", {wait: true}); // Empty web3 as Test changes it
|
engine.startService("web3", {wait: true}); // Empty web3 as Test changes it
|
||||||
engine.startService("deployment");
|
engine.startService("deployment");
|
||||||
engine.startService("codeGenerator");
|
engine.startService("codeGenerator");
|
||||||
|
engine.startService("codeRunner");
|
||||||
|
engine.startService("codeCoverage");
|
||||||
engine.startService("testRunner");
|
engine.startService("testRunner");
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,6 +34,11 @@ var Config = function(options) {
|
||||||
cb(self.contractsConfig);
|
cb(self.contractsConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.events.setCommandHandler("config:contractsConfig:set", (config, cb) => {
|
||||||
|
self.contractsConfig = config;
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
|
||||||
self.events.setCommandHandler("config:contractsFiles", (cb) => {
|
self.events.setCommandHandler("config:contractsFiles", (cb) => {
|
||||||
cb(self.contractsFiles);
|
cb(self.contractsFiles);
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,7 @@ const utils = require('../../utils/utils');
|
||||||
const constants = require('../../constants');
|
const constants = require('../../constants');
|
||||||
const embarkJsUtils = require('embarkjs').Utils;
|
const embarkJsUtils = require('embarkjs').Utils;
|
||||||
|
|
||||||
const WEB3_READY = 'web3Ready';
|
const WEB3_READY = 'blockchain:ready';
|
||||||
|
|
||||||
// TODO: consider another name, this is the blockchain connector
|
// TODO: consider another name, this is the blockchain connector
|
||||||
class BlockchainConnector {
|
class BlockchainConnector {
|
||||||
|
@ -40,6 +40,7 @@ class BlockchainConnector {
|
||||||
this.registerRequests();
|
this.registerRequests();
|
||||||
this.registerWeb3Object();
|
this.registerWeb3Object();
|
||||||
this.registerEvents();
|
this.registerEvents();
|
||||||
|
this.subscribeToPendingTransactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
initWeb3(cb) {
|
initWeb3(cb) {
|
||||||
|
@ -67,10 +68,46 @@ class BlockchainConnector {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'vm') {
|
if (type === 'vm') {
|
||||||
const sim = this._getSimulator();
|
const sim = self._getSimulator();
|
||||||
this.provider = sim.provider(this.contractsConfig.deployment);
|
self.provider = sim.provider(self.contractsConfig.deployment);
|
||||||
this.web3.setProvider(this.provider);
|
|
||||||
this._emitWeb3Ready();
|
if (self.coverage) {
|
||||||
|
// Here we patch the sendAsync method on the provider. The goal behind this is to force pure/constant/view calls to become
|
||||||
|
// transactions, so that we can pull in execution traces and account for those executions in code coverage.
|
||||||
|
//
|
||||||
|
// Instead of a simple call, here's what happens:
|
||||||
|
//
|
||||||
|
// 1) A transaction is sent with the same payload, and a pre-defined gas price;
|
||||||
|
// 2) We wait for the transaction to be mined by asking for the receipt;
|
||||||
|
// 3) Once we get the receipt back, we dispatch the real call and pass the original callback;
|
||||||
|
//
|
||||||
|
// This will still allow tests to get the return value from the call and run contracts unmodified.
|
||||||
|
self.provider.realSendAsync = self.provider.sendAsync.bind(self.provider);
|
||||||
|
self.provider.sendAsync = function(payload, cb) {
|
||||||
|
if(payload.method !== 'eth_call') {
|
||||||
|
return self.provider.realSendAsync(payload, cb);
|
||||||
|
}
|
||||||
|
self.events.request('reporter:toggleGasListener');
|
||||||
|
let newParams = Object.assign({}, payload.params[0], {gasPrice: '0x77359400'});
|
||||||
|
let newPayload = {
|
||||||
|
id: payload.id + 1,
|
||||||
|
method: 'eth_sendTransaction',
|
||||||
|
params: [newParams],
|
||||||
|
jsonrpc: payload.jsonrpc
|
||||||
|
};
|
||||||
|
|
||||||
|
self.provider.realSendAsync(newPayload, (_err, response) => {
|
||||||
|
let txHash = response.result;
|
||||||
|
self.web3.eth.getTransactionReceipt(txHash, (_err, _res) => {
|
||||||
|
self.events.request('reporter:toggleGasListener');
|
||||||
|
self.provider.realSendAsync(payload, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
self.web3.setProvider(self.provider);
|
||||||
|
self._emitWeb3Ready();
|
||||||
return cb();
|
return cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +152,7 @@ class BlockchainConnector {
|
||||||
this.isWeb3Ready = true;
|
this.isWeb3Ready = true;
|
||||||
this.events.emit(WEB3_READY);
|
this.events.emit(WEB3_READY);
|
||||||
this.registerWeb3Object();
|
this.registerWeb3Object();
|
||||||
|
this.subscribeToPendingTransactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
_getSimulator() {
|
_getSimulator() {
|
||||||
|
|
|
@ -12,7 +12,7 @@ class ContractSource {
|
||||||
this.lineCount = this.lineLengths.length;
|
this.lineCount = this.lineLengths.length;
|
||||||
|
|
||||||
this.lineOffsets = this.lineLengths.reduce((sum, _elt, i) => {
|
this.lineOffsets = this.lineLengths.reduce((sum, _elt, i) => {
|
||||||
sum[i] = (i == 0) ? 0 : self.lineLengths[i-1] + sum[i-1] + 1;
|
sum[i] = (i === 0) ? 0 : self.lineLengths[i-1] + sum[i-1] + 1;
|
||||||
return sum;
|
return sum;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,6 @@
|
||||||
const fs = require('../../core/fs');
|
const fs = require('../../core/fs');
|
||||||
const ContractSources = require('./contract_sources');
|
const ContractSources = require('./contract_sources');
|
||||||
|
|
||||||
// Set up the web3 extension
|
|
||||||
web3.extend({
|
|
||||||
property: 'debug',
|
|
||||||
methods: [{name: 'traceTransaction', call: 'debug_traceTransaction', params: 2}]
|
|
||||||
});
|
|
||||||
|
|
||||||
class CodeCoverage {
|
class CodeCoverage {
|
||||||
constructor(embark, _options) {
|
constructor(embark, _options) {
|
||||||
|
@ -18,9 +13,18 @@ class CodeCoverage {
|
||||||
embark.events.on('contracts:run:solc', this.runSolc.bind(this));
|
embark.events.on('contracts:run:solc', this.runSolc.bind(this));
|
||||||
embark.events.on('block:header', this.runSolc.bind(this));
|
embark.events.on('block:header', this.runSolc.bind(this));
|
||||||
|
|
||||||
// These events are emitted from a test-specific Embark instance, so we need to
|
embark.events.on('tests:finished', this.updateCoverageReport.bind(this));
|
||||||
// pull it in from global.
|
|
||||||
global.embark.events.on('tests:finished', this.updateCoverageReport.bind(this));
|
embark.events.on('blockchain:ready', () => {
|
||||||
|
embark.events.request('blockchain:get', (web3) => {
|
||||||
|
// Set up the web3 extension
|
||||||
|
web3.extend({
|
||||||
|
property: 'debug',
|
||||||
|
methods: [{name: 'traceTransaction', call: 'debug_traceTransaction', params: 2}]
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
this.seenTransactions = {};
|
this.seenTransactions = {};
|
||||||
this.coverageReport = {};
|
this.coverageReport = {};
|
||||||
|
@ -48,7 +52,7 @@ class CodeCoverage {
|
||||||
|
|
||||||
async runSolc(receipt) {
|
async runSolc(receipt) {
|
||||||
let block = await web3.eth.getBlock(receipt.number);
|
let block = await web3.eth.getBlock(receipt.number);
|
||||||
if(block.transactions.length == 0) return;
|
if(block.transactions.length === 0) return;
|
||||||
|
|
||||||
let requests = [];
|
let requests = [];
|
||||||
for(let i in block.transactions) {
|
for(let i in block.transactions) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ const EmptySourceMap = {
|
||||||
|
|
||||||
class SourceMap {
|
class SourceMap {
|
||||||
constructor(sourceMapStringOrOffset, length, id, jump) {
|
constructor(sourceMapStringOrOffset, length, id, jump) {
|
||||||
if(typeof sourceMapStringOrOffset == 'string') {
|
if(typeof sourceMapStringOrOffset === 'string') {
|
||||||
let [offset, length, id, jump] = sourceMapStringOrOffset.split(":");
|
let [offset, length, id, jump] = sourceMapStringOrOffset.split(":");
|
||||||
|
|
||||||
this.offset = parseInt(offset, 10);
|
this.offset = parseInt(offset, 10);
|
||||||
|
@ -46,7 +46,7 @@ class SourceMap {
|
||||||
toString(defaultId) {
|
toString(defaultId) {
|
||||||
let parts = [this.offset, this.length];
|
let parts = [this.offset, this.length];
|
||||||
|
|
||||||
if(this.id !== undefined && this.id != '') {
|
if(this.id !== undefined && this.id !== '') {
|
||||||
parts.push(this.id);
|
parts.push(this.id);
|
||||||
} else if(defaultId !== undefined) {
|
} else if(defaultId !== undefined) {
|
||||||
parts.push(defaultId);
|
parts.push(defaultId);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const AccountParser = require('../../utils/accountParser');
|
const AccountParser = require('../../utils/accountParser');
|
||||||
|
const EmbarkJS = require('embarkjs');
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
@ -46,42 +47,10 @@ class Test {
|
||||||
this.blockchainConnector.contractsConfig = this.configObj.contractsConfig;
|
this.blockchainConnector.contractsConfig = this.configObj.contractsConfig;
|
||||||
this.blockchainConnector.isWeb3Ready = false;
|
this.blockchainConnector.isWeb3Ready = false;
|
||||||
this.blockchainConnector.wait = false;
|
this.blockchainConnector.wait = false;
|
||||||
|
this.blockchainConnector.coverage = this.options.coverage;
|
||||||
|
|
||||||
// TODO change this
|
// TODO change this
|
||||||
/*if (this.options.coverage) {
|
|
||||||
// Here we patch the sendAsync method on the provider. The goal behind this is to force pure/constant/view calls to become
|
|
||||||
// transactions, so that we can pull in execution traces and account for those executions in code coverage.
|
|
||||||
//
|
|
||||||
// Instead of a simple call, here's what happens:
|
|
||||||
//
|
|
||||||
// 1) A transaction is sent with the same payload, and a pre-defined gas price;
|
|
||||||
// 2) We wait for the transaction to be mined by asking for the receipt;
|
|
||||||
// 3) Once we get the receipt back, we dispatch the real call and pass the original callback;
|
|
||||||
//
|
|
||||||
// This will still allow tests to get the return value from the call and run contracts unmodified.
|
|
||||||
simProvider.realSendAsync = simProvider.sendAsync.bind(simProvider);
|
|
||||||
simProvider.sendAsync = function(payload, cb) {
|
|
||||||
if(payload.method !== 'eth_call') {
|
|
||||||
return simProvider.realSendAsync(payload, cb);
|
|
||||||
}
|
|
||||||
self.events.request('reporter:toggleGasListener');
|
|
||||||
let newParams = Object.assign({}, payload.params[0], {gasPrice: '0x77359400'});
|
|
||||||
let newPayload = {
|
|
||||||
id: payload.id + 1,
|
|
||||||
method: 'eth_sendTransaction',
|
|
||||||
params: [newParams],
|
|
||||||
jsonrpc: payload.jsonrpc
|
|
||||||
};
|
|
||||||
|
|
||||||
simProvider.realSendAsync(newPayload, (_err, response) => {
|
|
||||||
let txHash = response.result;
|
|
||||||
self.web3.eth.getTransactionReceipt(txHash, (_err, _res) => {
|
|
||||||
self.events.request('reporter:toggleGasListener');
|
|
||||||
simProvider.realSendAsync(payload, cb);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}*/
|
|
||||||
|
|
||||||
this.blockchainConnector.initWeb3(callback);
|
this.blockchainConnector.initWeb3(callback);
|
||||||
}
|
}
|
||||||
|
@ -203,6 +172,12 @@ class Test {
|
||||||
function checkDeploymentOpts(next) {
|
function checkDeploymentOpts(next) {
|
||||||
self.checkDeploymentOptions(options, next);
|
self.checkDeploymentOptions(options, next);
|
||||||
},
|
},
|
||||||
|
function changeGlobalWeb3(next) {
|
||||||
|
self.events.request('blockchain:get', (web3) => {
|
||||||
|
global.web3 = web3;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
function compileContracts(next) {
|
function compileContracts(next) {
|
||||||
if (!self.firstDeployment) {
|
if (!self.firstDeployment) {
|
||||||
return next();
|
return next();
|
||||||
|
@ -242,9 +217,8 @@ class Test {
|
||||||
const self = this;
|
const self = this;
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function getConfig(next) {
|
function getConfig(next) {
|
||||||
// TODO use events instead of modifying directly
|
self.events.request('config:contractsConfig:set',
|
||||||
self.configObj.contractsConfig = {contracts: config.contracts, versions: self.versions_default};
|
{contracts: config.contracts, versions: self.versions_default}, next);
|
||||||
next();
|
|
||||||
},
|
},
|
||||||
function getAccounts(next) {
|
function getAccounts(next) {
|
||||||
self.events.request('blockchain:getAccounts', (err, accounts) => {
|
self.events.request('blockchain:getAccounts', (err, accounts) => {
|
||||||
|
@ -281,13 +255,19 @@ class Test {
|
||||||
self.contracts[contract.className] = {};
|
self.contracts[contract.className] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
self.events.request('blockchain:contract:create', {
|
|
||||||
abi: contract.abiDefinition,
|
self.events.request('blockchain:get', (web3) => {
|
||||||
address: contract.deployedAddress
|
let newContract = new EmbarkJS.Blockchain.Contract({
|
||||||
}, (newContract) => {
|
abi: contract.abiDefinition,
|
||||||
|
address: contract.deployedAddress,
|
||||||
|
from: web3.eth.defaultAccount,
|
||||||
|
gas: 6000000,
|
||||||
|
web3: web3
|
||||||
|
});
|
||||||
|
|
||||||
if (newContract.options) {
|
if (newContract.options) {
|
||||||
|
newContract.options.from = web3.eth.defaultAccount;
|
||||||
newContract.options.data = contract.code;
|
newContract.options.data = contract.code;
|
||||||
newContract.options.from = accounts[0];
|
|
||||||
if (!newContract.options.data.startsWith('0x')) {
|
if (!newContract.options.data.startsWith('0x')) {
|
||||||
newContract.options.data = '0x' + newContract.options.data;
|
newContract.options.data = '0x' + newContract.options.data;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +275,6 @@ class Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.setPrototypeOf(self.contracts[contract.className], newContract);
|
Object.setPrototypeOf(self.contracts[contract.className], newContract);
|
||||||
|
|
||||||
eachCb();
|
eachCb();
|
||||||
});
|
});
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
|
|
|
@ -3,3 +3,4 @@ node_modules/
|
||||||
dist/
|
dist/
|
||||||
config/production/password
|
config/production/password
|
||||||
config/livenet/password
|
config/livenet/password
|
||||||
|
coverage/
|
||||||
|
|
Loading…
Reference in New Issue