diff options
Diffstat (limited to 'packages/dev-utils')
-rw-r--r-- | packages/dev-utils/CHANGELOG.md | 6 | ||||
-rw-r--r-- | packages/dev-utils/README.md | 11 | ||||
-rw-r--r-- | packages/dev-utils/package.json | 1 | ||||
-rw-r--r-- | packages/dev-utils/src/blockchain_lifecycle.ts | 13 | ||||
-rw-r--r-- | packages/dev-utils/src/constants.ts | 3 | ||||
-rw-r--r-- | packages/dev-utils/src/coverage.ts | 22 | ||||
-rw-r--r-- | packages/dev-utils/src/env.ts | 24 | ||||
-rw-r--r-- | packages/dev-utils/src/index.ts | 3 | ||||
-rw-r--r-- | packages/dev-utils/src/rpc.ts | 62 | ||||
-rw-r--r-- | packages/dev-utils/src/web3_factory.ts | 51 | ||||
-rw-r--r-- | packages/dev-utils/test/blockchain_lifecycle_test.ts | 11 | ||||
-rw-r--r-- | packages/dev-utils/test/rpc_test.ts | 19 | ||||
-rw-r--r-- | packages/dev-utils/tslint.json | 5 |
13 files changed, 135 insertions, 96 deletions
diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index ecc5546ae..8193b78ac 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## v0.3.0 - _TBD, 2018_ + + * Add coverage subprovider if SOLIDITY_COVERAGE env variable is true (#426) + * Refactor `BlockchainLifecycle` to work with in-process ganache (#426) + * Remove `RPC` class and move it's logic to `Web3Wrapper` (#426) + ## v0.2.0 - _February 16, 2018_ * Remove subproviders (#392) diff --git a/packages/dev-utils/README.md b/packages/dev-utils/README.md index f7e30df1e..0c4175e35 100644 --- a/packages/dev-utils/README.md +++ b/packages/dev-utils/README.md @@ -2,6 +2,17 @@ Dev utils to be shared across 0x projects and packages +## Configuration + +Some env variables might be set to change the behaviour of created web3 providers/instances. + +``` +VERBOSE_GANACHE: boolean. Enables verbose Ganache logging. Every request/response payload. Slightly slower, but useful for testing. +SOLIDITY_COVERAGE: boolean. If set - adds coverage subprovider which intercepts all calls/transactions and can be later used to compute code coverage. +``` + +Boolean env variables should be either `true` or `false`. Defaults to `false` if not set. + ## Install ```bash diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 8912a7330..f9fc4e619 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -40,6 +40,7 @@ "typescript": "2.7.1" }, "dependencies": { + "@0xproject/sol-cov": "^0.0.1", "@0xproject/subproviders": "^0.7.0", "@0xproject/types": "^0.3.1", "@0xproject/utils": "^0.4.1", diff --git a/packages/dev-utils/src/blockchain_lifecycle.ts b/packages/dev-utils/src/blockchain_lifecycle.ts index c46902f76..3e35de861 100644 --- a/packages/dev-utils/src/blockchain_lifecycle.ts +++ b/packages/dev-utils/src/blockchain_lifecycle.ts @@ -1,21 +1,22 @@ -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(web3Wrapper: Web3Wrapper) { + this._web3Wrapper = web3Wrapper; 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`); } diff --git a/packages/dev-utils/src/constants.ts b/packages/dev-utils/src/constants.ts index 4f7b4202a..05bcc1638 100644 --- a/packages/dev-utils/src/constants.ts +++ b/packages/dev-utils/src/constants.ts @@ -1,5 +1,6 @@ export const constants = { RPC_URL: 'http://localhost:8545', RPC_PORT: 8545, - GAS_ESTIMATE: 1000000, + GAS_ESTIMATE: 5000000, + TESTRPC_FIRST_ADDRESS: '0x5409ed021d9299bf6814279a6a1411a7e866a631', }; diff --git a/packages/dev-utils/src/coverage.ts b/packages/dev-utils/src/coverage.ts new file mode 100644 index 000000000..40bb47e2d --- /dev/null +++ b/packages/dev-utils/src/coverage.ts @@ -0,0 +1,22 @@ +import { CoverageSubprovider } from '@0xproject/sol-cov'; +import * as _ from 'lodash'; + +import { constants } from './constants'; + +let coverageSubprovider: CoverageSubprovider; + +export const coverage = { + getCoverageSubproviderSingleton(): CoverageSubprovider { + if (_.isUndefined(coverageSubprovider)) { + coverageSubprovider = coverage._getCoverageSubprovider(); + } + return coverageSubprovider; + }, + _getCoverageSubprovider(): CoverageSubprovider { + const artifactsPath = './src/artifacts'; + const contractsPath = './src/contracts'; + const networkId = 50; + const defaultFromAddress = constants.TESTRPC_FIRST_ADDRESS; + return new CoverageSubprovider(artifactsPath, contractsPath, networkId, defaultFromAddress); + }, +}; diff --git a/packages/dev-utils/src/env.ts b/packages/dev-utils/src/env.ts new file mode 100644 index 000000000..114dbf4a8 --- /dev/null +++ b/packages/dev-utils/src/env.ts @@ -0,0 +1,24 @@ +import * as _ from 'lodash'; +import * as process from 'process'; + +export enum EnvVars { + SolidityCoverage = 'SOLIDITY_COVERAGE', + VerboseGanache = 'VERBOSE_GANACHE', +} + +export const env = { + parseBoolean(key: string): boolean { + let isTrue: boolean; + const envVarValue = process.env[key]; + if (envVarValue === 'true') { + isTrue = true; + } else if (envVarValue === 'false' || _.isUndefined(envVarValue)) { + isTrue = false; + } else { + throw new Error( + `Failed to parse ENV variable ${key} as boolean. Please make sure it's either true or false. Defaults to false`, + ); + } + return isTrue; + }, +}; diff --git a/packages/dev-utils/src/index.ts b/packages/dev-utils/src/index.ts index e899ac206..2ff2a2238 100644 --- a/packages/dev-utils/src/index.ts +++ b/packages/dev-utils/src/index.ts @@ -1,4 +1,5 @@ -export { RPC } from './rpc'; export { BlockchainLifecycle } from './blockchain_lifecycle'; export { web3Factory } from './web3_factory'; export { constants as devConstants } from './constants'; +export { coverage } from './coverage'; +export { env, EnvVars } from './env'; diff --git a/packages/dev-utils/src/rpc.ts b/packages/dev-utils/src/rpc.ts deleted file mode 100644 index 47a359263..000000000 --- a/packages/dev-utils/src/rpc.ts +++ /dev/null @@ -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; - } -} diff --git a/packages/dev-utils/src/web3_factory.ts b/packages/dev-utils/src/web3_factory.ts index b0e0e4d3f..6435f0f9a 100644 --- a/packages/dev-utils/src/web3_factory.ts +++ b/packages/dev-utils/src/web3_factory.ts @@ -6,9 +6,14 @@ 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 { coverage } from './coverage'; +import { env, EnvVars } from './env'; // HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang // because they are using the wrong XHR package. @@ -17,24 +22,52 @@ import { constants } from './constants'; // tslint:disable-next-line:ordered-imports import * as Web3 from 'web3'; +export interface Web3Config { + hasAddresses?: boolean; // default: true + shouldUseInProcessGanache?: 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(); + const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage); + if (isCoverageEnabled) { + provider.addProvider(coverage.getCoverageSubproviderSingleton()); + } + 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 shouldUseInProcessGanache = !!config.shouldUseInProcessGanache; + if (shouldUseInProcessGanache) { + provider.addProvider( + new GanacheSubprovider({ + logger, + verbose: env.parseBoolean(EnvVars.SolidityCoverage), + 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; }, diff --git a/packages/dev-utils/test/blockchain_lifecycle_test.ts b/packages/dev-utils/test/blockchain_lifecycle_test.ts index 4fdc53c87..5ed67e012 100644 --- a/packages/dev-utils/test/blockchain_lifecycle_test.ts +++ b/packages/dev-utils/test/blockchain_lifecycle_test.ts @@ -3,20 +3,19 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import 'mocha'; -import { BlockchainLifecycle, RPC, web3Factory } from '../src'; +import { BlockchainLifecycle, web3Factory } from '../src'; const expect = chai.expect; describe('BlockchainLifecycle tests', () => { - const web3 = web3Factory.create(); - const web3Wrapper = new Web3Wrapper(web3.currentProvider); - const rpc = new RPC(); - const blockchainLifecycle = new BlockchainLifecycle(); + const web3Provider = web3Factory.getRpcProvider(); + const web3Wrapper = new Web3Wrapper(web3Provider); + const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('#startAsync/revertAsync', () => { it('reverts changes in between', async () => { const blockNumberBefore = await web3Wrapper.getBlockNumberAsync(); await blockchainLifecycle.startAsync(); - await rpc.mineBlockAsync(); + await web3Wrapper.mineBlockAsync(); const blockNumberAfter = await web3Wrapper.getBlockNumberAsync(); expect(blockNumberAfter).to.be.equal(blockNumberBefore + 1); await blockchainLifecycle.revertAsync(); diff --git a/packages/dev-utils/test/rpc_test.ts b/packages/dev-utils/test/rpc_test.ts index 2f0e5ff7f..1bdea3613 100644 --- a/packages/dev-utils/test/rpc_test.ts +++ b/packages/dev-utils/test/rpc_test.ts @@ -3,18 +3,17 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import 'mocha'; -import { RPC, web3Factory } from '../src'; +import { web3Factory } from '../src'; const expect = chai.expect; describe('RPC tests', () => { - const web3 = web3Factory.create(); - const web3Wrapper = new Web3Wrapper(web3.currentProvider); - const rpc = new RPC(); + const web3Provider = web3Factory.getRpcProvider(); + const web3Wrapper = new Web3Wrapper(web3Provider); describe('#mineBlockAsync', () => { it('increases block number when called', async () => { const blockNumberBefore = await web3Wrapper.getBlockNumberAsync(); - await rpc.mineBlockAsync(); + await web3Wrapper.mineBlockAsync(); const blockNumberAfter = await web3Wrapper.getBlockNumberAsync(); expect(blockNumberAfter).to.be.equal(blockNumberBefore + 1); }); @@ -23,8 +22,8 @@ describe('RPC tests', () => { it('increases time when called', async () => { const TIME_DELTA = 1000; const blockTimestampBefore = await web3Wrapper.getBlockTimestampAsync(BlockParamLiteral.Latest); - await rpc.increaseTimeAsync(TIME_DELTA); - await rpc.mineBlockAsync(); + await web3Wrapper.increaseTimeAsync(TIME_DELTA); + await web3Wrapper.mineBlockAsync(); const blockTimestampAfter = await web3Wrapper.getBlockTimestampAsync(BlockParamLiteral.Latest); expect(blockTimestampAfter).to.be.at.least(blockTimestampBefore + TIME_DELTA); }); @@ -32,9 +31,9 @@ describe('RPC tests', () => { describe('#takeSnapshotAsync/revertSnapshotAsync', () => { it('reverts changes in between', async () => { const blockNumberBefore = await web3Wrapper.getBlockNumberAsync(); - const snapshotId = await rpc.takeSnapshotAsync(); - await rpc.mineBlockAsync(); - await rpc.revertSnapshotAsync(snapshotId); + const snapshotId = await web3Wrapper.takeSnapshotAsync(); + await web3Wrapper.mineBlockAsync(); + await web3Wrapper.revertSnapshotAsync(snapshotId); const blockNumberAfter = await web3Wrapper.getBlockNumberAsync(); expect(blockNumberAfter).to.be.equal(blockNumberBefore); }); diff --git a/packages/dev-utils/tslint.json b/packages/dev-utils/tslint.json index ffaefe83a..015dce851 100644 --- a/packages/dev-utils/tslint.json +++ b/packages/dev-utils/tslint.json @@ -1,3 +1,6 @@ { - "extends": ["@0xproject/tslint-config"] + "extends": ["@0xproject/tslint-config"], + "rules": { + "completed-docs": false + } } |