Add sol-cover implementation

This commit is contained in:
Leonid Logvinov
2018-03-04 19:05:26 -08:00
parent a6571b09d2
commit 13299158d1
110 changed files with 3704 additions and 1570 deletions

View File

@@ -1,21 +1,24 @@
import { RPC } from './rpc';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as Web3 from 'web3';
export class BlockchainLifecycle {
private _rpc: RPC;
private _web3Wrapper: Web3Wrapper;
private _snapshotIdsStack: number[];
constructor() {
this._rpc = new RPC();
constructor(web3Orweb3Wrapper: Web3Wrapper | Web3) {
this._web3Wrapper = (web3Orweb3Wrapper as Web3Wrapper).isZeroExWeb3Wrapper
? (web3Orweb3Wrapper as Web3Wrapper)
: new Web3Wrapper((web3Orweb3Wrapper as Web3).currentProvider);
this._snapshotIdsStack = [];
}
// TODO: In order to run these tests on an actual node, we should check if we are running against
// TestRPC, if so, use snapshots, otherwise re-deploy contracts before every test
public async startAsync(): Promise<void> {
const snapshotId = await this._rpc.takeSnapshotAsync();
const snapshotId = await this._web3Wrapper.takeSnapshotAsync();
this._snapshotIdsStack.push(snapshotId);
}
public async revertAsync(): Promise<void> {
const snapshotId = this._snapshotIdsStack.pop() as number;
const didRevert = await this._rpc.revertSnapshotAsync(snapshotId);
const didRevert = await this._web3Wrapper.revertSnapshotAsync(snapshotId);
if (!didRevert) {
throw new Error(`Snapshot with id #${snapshotId} failed to revert`);
}

View File

@@ -1,5 +1,5 @@
export const constants = {
RPC_URL: 'http://localhost:8545',
RPC_PORT: 8545,
GAS_ESTIMATE: 1000000,
GAS_ESTIMATE: 5000000,
};

View File

@@ -0,0 +1,14 @@
import { CoverageSubprovider } from '@0xproject/sol-cov';
import * as _ from 'lodash';
let coverageSubprovider: CoverageSubprovider;
export function getCoverageSubprovider(): CoverageSubprovider {
if (_.isUndefined(coverageSubprovider)) {
const artifactsPath = './src/artifacts';
const contractsPath = './src/contracts';
const networkId = 50;
coverageSubprovider = new CoverageSubprovider(artifactsPath, contractsPath, networkId);
}
return coverageSubprovider;
}

View File

@@ -1,4 +1,4 @@
export { RPC } from './rpc';
export { BlockchainLifecycle } from './blockchain_lifecycle';
export { web3Factory } from './web3_factory';
export { constants as devConstants } from './constants';
export { getCoverageSubprovider } from './coverage';

View File

@@ -1,62 +0,0 @@
import * as ethUtil from 'ethereumjs-util';
import * as request from 'request-promise-native';
import { constants } from './constants';
export class RPC {
private _url: string;
private _id: number;
constructor() {
this._url = constants.RPC_URL;
this._id = 0;
}
public async takeSnapshotAsync(): Promise<number> {
const method = 'evm_snapshot';
const params: any[] = [];
const payload = this._toPayload(method, params);
const snapshotIdHex = await this._sendAsync(payload);
const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex));
return snapshotId;
}
public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
const method = 'evm_revert';
const params = [snapshotId];
const payload = this._toPayload(method, params);
const didRevert = await this._sendAsync(payload);
return didRevert;
}
public async increaseTimeAsync(time: number) {
const method = 'evm_increaseTime';
const params = [time];
const payload = this._toPayload(method, params);
return this._sendAsync(payload);
}
public async mineBlockAsync(): Promise<void> {
const method = 'evm_mine';
const params: any[] = [];
const payload = this._toPayload(method, params);
await this._sendAsync(payload);
}
private _toPayload(method: string, params: any[] = []): string {
const payload = JSON.stringify({
id: this._id,
method,
params,
});
this._id += 1;
return payload;
}
private async _sendAsync(payload: string): Promise<any> {
const opts = {
method: 'POST',
uri: this._url,
body: payload,
headers: {
'content-type': 'application/json',
},
};
const bodyString = await request(opts);
const body = JSON.parse(bodyString);
return body.result;
}
}

View File

@@ -6,9 +6,13 @@
import ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import { EmptyWalletSubprovider, FakeGasEstimateSubprovider } from '@0xproject/subproviders';
import { EmptyWalletSubprovider, FakeGasEstimateSubprovider, GanacheSubprovider } from '@0xproject/subproviders';
import * as fs from 'fs';
import * as _ from 'lodash';
import * as process from 'process';
import { constants } from './constants';
import { getCoverageSubprovider } from './coverage';
// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang
// because they are using the wrong XHR package.
@@ -17,24 +21,51 @@ import { constants } from './constants';
// tslint:disable-next-line:ordered-imports
import * as Web3 from 'web3';
export interface Web3Config {
hasAddresses?: boolean; // default: true
useInProcessGanache?: boolean; // default: false
}
export const web3Factory = {
create(hasAddresses: boolean = true): Web3 {
const provider = this.getRpcProvider(hasAddresses);
create(config: Web3Config = {}): Web3 {
const provider = this.getRpcProvider(config);
const web3 = new Web3();
web3.setProvider(provider);
return web3;
},
getRpcProvider(hasAddresses: boolean = true): Web3.Provider {
getRpcProvider(config: Web3Config = {}): Web3.Provider {
const provider = new ProviderEngine();
if (process.env.COVERAGE) {
provider.addProvider(getCoverageSubprovider());
}
const hasAddresses = _.isUndefined(config.hasAddresses) || config.hasAddresses;
if (!hasAddresses) {
provider.addProvider(new EmptyWalletSubprovider());
}
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE));
provider.addProvider(
new RpcSubprovider({
rpcUrl: constants.RPC_URL,
}),
);
const logger = {
log: (arg: any) => {
fs.appendFileSync('ganache.log', `${arg}\n`);
},
};
const useInProcessGanache = config.useInProcessGanache;
if (useInProcessGanache) {
provider.addProvider(
new GanacheSubprovider({
logger,
verbose: process.env.VERBOSE_GANACHE,
port: 8545,
networkId: 50,
mnemonic: 'concert load couple harbor equip island argue ramp clarify fence smart topic',
}),
);
} else {
provider.addProvider(
new RpcSubprovider({
rpcUrl: constants.RPC_URL,
}),
);
}
provider.start();
return provider;
},