-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial provider API tests for Infura client
We are working on migrating the extension to a unified network controller, but before we do so we want to extract some of the existing pieces, specifically `createInfuraClient` and `createJsonRpcClient`, which provide the majority of the behavior exhibited within the provider API that the existing NetworkController exposes. This necessitates that we understand and test that behavior as a whole. With that in mind, this commit starts with the Infura-specific network client and adds some initial functional tests for `createInfuraClient`, specifically covering three pieces of middleware provided by `eth-json-rpc-middleware`: `createNetworkAndChainIdMiddleware`, `createBlockCacheMiddleware`, and `createBlockRefMiddleware`. These tests exercise logic that originate from multiple different places and combine in sometimes surprising ways, and as a result, understanding the nature of the tests can be tricky. I've tried to explain the logic (both of the implementation and the tests) via comments. Additionally, debugging why a certain test is failing is not the most fun thing in the world, so to aid with this, I've added some logging to the underlying packages used when a request passes through the middleware stack. Because some middleware change the request being made, or make new requests altogether, this greatly helps to peel back the curtain, as failures from Nock do not supply much meaningful information on their own. This logging is disabled by default, but can be activated by setting `DEBUG_PROVIDER_TESTS=1` alongside the `jest` command. Also note that we are using a custom version of `eth-block-tracker` which provides a `destroy` method, which we use in tests to properly ensure that the block tracker is stopped before moving on to the next step. This change comes from [this PR][1] which has yet to be merged. [1]: MetaMask/eth-block-tracker#106
- Loading branch information
Showing
10 changed files
with
1,479 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
233 changes: 233 additions & 0 deletions
233
app/scripts/controllers/network/createInfuraClient.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
/** | ||
* @jest-environment node | ||
*/ | ||
|
||
import { withInfuraClient } from './provider-api-tests/helpers'; | ||
import { | ||
testsForRpcMethodThatDoesNotSupportParams, | ||
testsForRpcMethodsThatCheckForBlockHashInResponse, | ||
testsForRpcMethodThatSupportsMultipleParams, | ||
} from './provider-api-tests/shared-tests'; | ||
|
||
describe('createInfuraClient', () => { | ||
// The first time an RPC method is requested, the latest block number is | ||
// pulled from the block tracker, the RPC method is delegated to Infura, and | ||
// the result is cached under that block number, as long as the result is | ||
// "non-empty". The next time the same request takes place, Infura is not hit, | ||
// and the result is pulled from the cache. | ||
// | ||
// For most RPC methods here, a "non-empty" result is a result that is not | ||
// null, undefined, or a non-standard "nil" value that geth produces. | ||
// | ||
// Some RPC methods are cacheable. Consult the definitive list of cacheable | ||
// RPC methods in `cacheTypeForPayload` within `eth-json-rpc-middleware`. | ||
|
||
describe('when the RPC method is eth_chainId', () => { | ||
it('does not hit Infura, instead returning the chain id that maps to the Infura network, as a hex string', async () => { | ||
const chainId = await withInfuraClient( | ||
{ network: 'ropsten' }, | ||
({ makeRpcCall }) => { | ||
return makeRpcCall({ | ||
method: 'eth_chainId', | ||
}); | ||
}, | ||
); | ||
|
||
expect(chainId).toStrictEqual('0x3'); | ||
}); | ||
}); | ||
|
||
describe('when the RPC method is net_version', () => { | ||
it('does not hit Infura, instead returning the chain id that maps to the Infura network, as a decimal string', async () => { | ||
const chainId = await withInfuraClient( | ||
{ network: 'ropsten' }, | ||
({ makeRpcCall }) => { | ||
return makeRpcCall({ | ||
method: 'net_version', | ||
}); | ||
}, | ||
); | ||
|
||
expect(chainId).toStrictEqual('3'); | ||
}); | ||
}); | ||
|
||
// == RPC methods that do not support params | ||
// | ||
// For `eth_getTransactionByHash` and `eth_getTransactionReceipt`, a | ||
// "non-empty" result is not only one that is not null, undefined, or a | ||
// geth-specific "nil", but additionally a result that has a `blockHash` that | ||
// is not 0x0. | ||
|
||
describe('eth_blockNumber', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_blockNumber'); | ||
}); | ||
|
||
describe('eth_compileLLL', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_compileLLL'); | ||
}); | ||
|
||
describe('eth_compileSerpent', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_compileSerpent'); | ||
}); | ||
|
||
describe('eth_compileSolidity', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_compileSolidity'); | ||
}); | ||
|
||
describe('eth_estimateGas', () => { | ||
const method = 'eth_estimateGas'; | ||
testsForRpcMethodThatDoesNotSupportParams('eth_estimateGas'); | ||
}); | ||
|
||
describe('eth_gasPrice', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_gasPrice'); | ||
}); | ||
|
||
describe('eth_getBlockByHash', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_getBlockByHash'); | ||
}); | ||
|
||
describe('eth_getBlockTransactionCountByHash', () => { | ||
testsForRpcMethodThatDoesNotSupportParams( | ||
'eth_getBlockTransactionCountByHash', | ||
); | ||
}); | ||
|
||
describe('eth_getBlockTransactionCountByNumber', () => { | ||
testsForRpcMethodThatDoesNotSupportParams( | ||
'eth_getBlockTransactionCountByNumber', | ||
); | ||
}); | ||
|
||
describe('eth_getCompilers', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_getCompilers'); | ||
}); | ||
|
||
describe('eth_getFilterLogs', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_getFilterLogs'); | ||
}); | ||
|
||
describe('eth_getTransactionByBlockHashAndIndex', () => { | ||
testsForRpcMethodThatDoesNotSupportParams( | ||
'eth_getTransactionByBlockHashAndIndex', | ||
); | ||
}); | ||
|
||
describe('eth_getTransactionByBlockNumberAndIndex', () => { | ||
testsForRpcMethodThatDoesNotSupportParams( | ||
'eth_getTransactionByBlockNumberAndIndex', | ||
); | ||
}); | ||
|
||
describe('eth_getTransactionByHash', () => { | ||
testsForRpcMethodsThatCheckForBlockHashInResponse( | ||
'eth_getTransactionByHash', | ||
); | ||
}); | ||
|
||
describe('eth_getTransactionReceipt', () => { | ||
testsForRpcMethodsThatCheckForBlockHashInResponse( | ||
'eth_getTransactionReceipt', | ||
); | ||
}); | ||
|
||
describe('eth_getUncleByBlockHashAndIndex', () => { | ||
testsForRpcMethodThatDoesNotSupportParams( | ||
'eth_getUncleByBlockHashAndIndex', | ||
); | ||
}); | ||
|
||
describe('eth_getUncleByBlockNumberAndIndex', () => { | ||
testsForRpcMethodThatDoesNotSupportParams( | ||
'eth_getUncleByBlockNumberAndIndex', | ||
); | ||
}); | ||
|
||
describe('eth_getUncleCountByBlockHash', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_getUncleCountByBlockHash'); | ||
}); | ||
|
||
describe('eth_getUncleCountByBlockNumber', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_getUncleCountByBlockNumber'); | ||
}); | ||
|
||
describe('eth_protocolVersion', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('eth_protocolVersion'); | ||
}); | ||
|
||
describe('shh_version', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('shh_version'); | ||
}); | ||
|
||
describe('test_blockCache', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('test_blockCache'); | ||
}); | ||
|
||
describe('test_forkCache', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('test_forkCache'); | ||
}); | ||
|
||
describe('test_permaCache', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('test_permaCache'); | ||
}); | ||
|
||
describe('web3_clientVersion', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('web3_clientVersion'); | ||
}); | ||
|
||
describe('web3_sha3', () => { | ||
testsForRpcMethodThatDoesNotSupportParams('web3_sha3'); | ||
}); | ||
|
||
// == RPC methods that support multiple params (including a "block" param) | ||
// | ||
// RPC methods in this category take a non-empty `params` array, and more | ||
// importantly, one of these items can specify which block the method applies | ||
// to. This block param may either be a tag ("earliest", "latest", or | ||
// "pending"), or a specific block number; or this param may not be | ||
// provided altogether, in which case it defaults to "latest". Also, | ||
// "earliest" is just a synonym for "0x00". | ||
// | ||
// The fact that these methods support arguments affects the caching strategy, | ||
// because if two requests are made with the same method but with different | ||
// arguments, then they will be cached separately. Also, the block param | ||
// changes the caching strategy slightly: if "pending" is specified, then the | ||
// request is never cached. | ||
|
||
describe('eth_getBlockByNumber', () => { | ||
testsForRpcMethodThatSupportsMultipleParams('eth_getBlockByNumber', { | ||
numberOfParams: 0, | ||
}); | ||
}); | ||
|
||
describe('eth_getBalance', () => { | ||
testsForRpcMethodThatSupportsMultipleParams('eth_getBalance', { | ||
numberOfParams: 1, | ||
}); | ||
}); | ||
|
||
describe('eth_getCode', () => { | ||
testsForRpcMethodThatSupportsMultipleParams('eth_getCode', { | ||
numberOfParams: 1, | ||
}); | ||
}); | ||
|
||
describe('eth_getTransactionCount', () => { | ||
testsForRpcMethodThatSupportsMultipleParams('eth_getTransactionCount', { | ||
numberOfParams: 1, | ||
}); | ||
}); | ||
|
||
describe('eth_call', () => { | ||
testsForRpcMethodThatSupportsMultipleParams('eth_call', { | ||
numberOfParams: 1, | ||
}); | ||
}); | ||
|
||
describe('eth_getStorageAt', () => { | ||
testsForRpcMethodThatSupportsMultipleParams('eth_getStorageAt', { | ||
numberOfParams: 2, | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.