docs: mock-provider (#2011)
* MockProvider example + mdbook reference * review: use eyre::Result Co-authored-by: Andrea Simeoni <>
This commit is contained in:
parent
3ed83d5dd3
commit
7e6c3ba983
|
@ -9,7 +9,7 @@
|
||||||
- [Providers]()
|
- [Providers]()
|
||||||
- [Http](./providers/http.md)
|
- [Http](./providers/http.md)
|
||||||
- [IPC](./providers/ipc.md)
|
- [IPC](./providers/ipc.md)
|
||||||
- [Mock]()
|
- [Mock](./providers/mock.md)
|
||||||
- [Quorum](./providers/quorum.md)
|
- [Quorum](./providers/quorum.md)
|
||||||
- [Retry](./providers/retry.md)
|
- [Retry](./providers/retry.md)
|
||||||
- [RW](./providers/rw.md)
|
- [RW](./providers/rw.md)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Mock provider
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{{#include ../../examples/providers/examples/mock.rs}}
|
||||||
|
```
|
|
@ -34,10 +34,10 @@
|
||||||
- [x] Signer
|
- [x] Signer
|
||||||
- [ ] Time lag
|
- [ ] Time lag
|
||||||
- [ ] Transformer
|
- [ ] Transformer
|
||||||
- [ ] Providers
|
- [x] Providers
|
||||||
- [x] Http
|
- [x] Http
|
||||||
- [x] IPC
|
- [x] IPC
|
||||||
- [ ] Mock
|
- [x] Mock
|
||||||
- [x] Quorum
|
- [x] Quorum
|
||||||
- [x] Retry
|
- [x] Retry
|
||||||
- [x] RW
|
- [x] RW
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
use ethers::prelude::*;
|
||||||
|
|
||||||
|
/// `MockProvider` is a mock Ethereum provider that can be used for testing purposes.
|
||||||
|
/// It allows to simulate Ethereum state and behavior, by explicitly instructing
|
||||||
|
/// provider's responses on client requests.
|
||||||
|
///
|
||||||
|
/// This can be useful for testing code that relies on providers without the need to
|
||||||
|
/// connect to a real network or spend real Ether. It also allows to test code in a
|
||||||
|
/// deterministic manner, as you can control the state and behavior of the provider.
|
||||||
|
///
|
||||||
|
/// In these examples we use the common Arrange, Act, Assert (AAA) test approach.
|
||||||
|
/// It is a useful pattern for well-structured, understandable and maintainable tests.
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
mocked_block_number().await?;
|
||||||
|
mocked_provider_dependency().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn mocked_block_number() -> eyre::Result<()> {
|
||||||
|
// Arrange
|
||||||
|
let mock = MockProvider::new();
|
||||||
|
let block_num_1 = U64::from(1);
|
||||||
|
let block_num_2 = U64::from(2);
|
||||||
|
let block_num_3 = U64::from(3);
|
||||||
|
// Mock responses are organized in a stack (LIFO)
|
||||||
|
mock.push(block_num_1)?;
|
||||||
|
mock.push(block_num_2)?;
|
||||||
|
mock.push(block_num_3)?;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
let ret_block_3: U64 = JsonRpcClient::request(&mock, "eth_blockNumber", ()).await?;
|
||||||
|
let ret_block_2: U64 = JsonRpcClient::request(&mock, "eth_blockNumber", ()).await?;
|
||||||
|
let ret_block_1: U64 = JsonRpcClient::request(&mock, "eth_blockNumber", ()).await?;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assert_eq!(block_num_1, ret_block_1);
|
||||||
|
assert_eq!(block_num_2, ret_block_2);
|
||||||
|
assert_eq!(block_num_3, ret_block_3);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Here we test the `OddBlockOracle` struct (defined below) that relies
|
||||||
|
/// on a Provider to perform some logics.
|
||||||
|
/// The Provider reference is expressed with trait bounds, enforcing lose coupling,
|
||||||
|
/// maintainability and testability.
|
||||||
|
async fn mocked_provider_dependency() -> eyre::Result<()> {
|
||||||
|
// Arrange
|
||||||
|
let (provider, mock) = crate::Provider::mocked();
|
||||||
|
mock.push(U64::from(2))?;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// Let's mock the provider dependency (we ❤️ DI!) then ask for the answer
|
||||||
|
let oracle = OddBlockOracle::new(provider);
|
||||||
|
let answer: bool = oracle.is_odd_block().await?;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assert!(answer);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OddBlockOracle<P> {
|
||||||
|
provider: Provider<P>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> OddBlockOracle<P>
|
||||||
|
where
|
||||||
|
P: JsonRpcClient,
|
||||||
|
{
|
||||||
|
fn new(provider: Provider<P>) -> Self {
|
||||||
|
Self { provider }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// We want to test this!
|
||||||
|
async fn is_odd_block(&self) -> eyre::Result<bool> {
|
||||||
|
let block: U64 = self.provider.get_block_number().await?;
|
||||||
|
Ok(block % 2 == U64::zero())
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,20 +4,18 @@ use ethers::prelude::*;
|
||||||
|
|
||||||
const WSS_URL: &str = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27";
|
const WSS_URL: &str = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27";
|
||||||
|
|
||||||
type BoxErr = Box<dyn std::error::Error>;
|
|
||||||
|
|
||||||
/// The Ws transport allows you to send JSON-RPC requests and receive responses over WebSocket
|
/// The Ws transport allows you to send JSON-RPC requests and receive responses over WebSocket
|
||||||
/// connections. It is useful for connecting to Ethereum nodes that support WebSockets.
|
/// connections. It is useful for connecting to Ethereum nodes that support WebSockets.
|
||||||
/// This allows to interact with the Ethereum network in real-time without the need for HTTP
|
/// This allows to interact with the Ethereum network in real-time without the need for HTTP
|
||||||
/// polling.
|
/// polling.
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), BoxErr> {
|
async fn main() -> eyre::Result<()> {
|
||||||
create_instance().await?;
|
create_instance().await?;
|
||||||
watch_blocks().await?;
|
watch_blocks().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_instance() -> Result<(), BoxErr> {
|
async fn create_instance() -> eyre::Result<()> {
|
||||||
// An Ws provider can be created from an ws(s) URI.
|
// An Ws provider can be created from an ws(s) URI.
|
||||||
// In case of wss you must add the "rustls" or "openssl" feature
|
// In case of wss you must add the "rustls" or "openssl" feature
|
||||||
// to the ethers library dependency in `Cargo.toml`.
|
// to the ethers library dependency in `Cargo.toml`.
|
||||||
|
@ -39,7 +37,7 @@ async fn create_instance() -> Result<(), BoxErr> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Let's show how the Ws connection enables listening for blocks using a persistent TCP connection
|
/// Let's show how the Ws connection enables listening for blocks using a persistent TCP connection
|
||||||
async fn watch_blocks() -> Result<(), BoxErr> {
|
async fn watch_blocks() -> eyre::Result<()> {
|
||||||
let provider = Provider::<Ws>::connect(WSS_URL).await?;
|
let provider = Provider::<Ws>::connect(WSS_URL).await?;
|
||||||
let mut stream = provider.watch_blocks().await?.take(1);
|
let mut stream = provider.watch_blocks().await?.take(1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue