Testing with gclient
gclient
is intended to be used as a tool for testing Gear programs with a real blockchain network. It allows you to send extrinsics and RPCs by connecting to the network. We recommend using gclient
for end-to-end testing to ensure the program works as expected in the real blockchain world.
It is essential to underline that testing with gclient
requires the running node as the second part of the test suite. The gclient
interacts with the node over the WebSocket protocol. Depending on the purpose of testing, gclient
can communicate with either a local or a remote node. The best choice is to use the local node in developer mode for initial debugging and continuous integration.
Testing with gclient
is slower than gtest
and produces more build artifacts, so it is better suited as the last mile in quality control. However, gclient
gives the most accurate test results.
Import gclient
lib
To use the gclient
library, you must import it into your Cargo.toml
file in the [dev-dependencies]
block. Also, you need to add some external crates that are used together with gclient
:
[package]
name = "first-gear-app"
version = "0.1.0"
authors = ["Your Name"]
edition = "2021"
[dependencies]
gstd = { git = "https://github.com/gear-tech/gear.git", tag = "v1.1.1", features = ["debug"] }
[build-dependencies]
gear-wasm-builder = { git = "https://github.com/gear-tech/gear.git", tag = "v1.1.1" }
[dev-dependencies]
gclient = { git = "https://github.com/gear-tech/gear.git", tag = "v1.1.1" }
tokio = { version = "1", features = ["full"] }
Running the node
The best way is to download the latest node binary for your operating system from https://get.gear.rs. Then unpack the package and run the node. Here and below, we assume the node is running in developer mode.
- Linux x86-64
- macOS ARM
- macOS x86-64
- Windows x86-64
Terminal:
curl https://get.gear.rs/gear-v1.1.1-x86_64-unknown-linux-gnu.tar.xz | tar xJ
or
Linux x86-64: gear-v1.1.1-x86_64-unknown-linux-gnu.tar.xz
You can try to run the node:
❯ ./gear --version
gear 1.1.1-33ee05d5aab
Terminal:
curl https://get.gear.rs/gear-v1.1.1-aarch64-apple-darwin.tar.xz | tar xJ
or
macOS ARM: gear-v1.1.1-aarch64-apple-darwin.tar.xz
You can try to run the node:
❯ ./gear --version
gear 1.1.1-33ee05d5aab
Terminal:
curl https://get.gear.rs/gear-v1.1.1-x86_64-apple-darwin.tar.xz | tar xJ
or
macOS x86-64: gear-v1.1.1-x86_64-apple-darwin.tar.xz
You can try to run the node:
❯ ./gear --version
gear 1.1.1-33ee05d5aab
Terminal:
curl -O https://get.gear.rs/gear-v1.1.1-x86_64-pc-windows-msvc.zip
or
Windows x86-64: gear-v1.1.1-x86_64-pc-windows-msvc.zip
Unzip the downloaded package then you can try to run the node:
❯ gear.exe --version
gear 1.1.1-33ee05d5aab
Open the second terminal window and run tests using cargo
as it was described in the previous section.
Simple example
Let's add an end-to-end test to our first-gear-app
introduced in the Getting Started section.
Add the tests
directory next to the src
directory and create the end2end.rs
file in it.
└── first-gear-app
├── Cargo.toml
├── src
│ └── lib.rs
└── tests
└── end2end.rs
end2end.rs
:
use gclient::{EventProcessor, GearApi, Result};
const WASM_PATH: &str = "./target/wasm32-unknown-unknown/release/first_gear_app.opt.wasm";
#[tokio::test]
#[ignore]
async fn test_example() -> Result<()> {
// Create API instance
let api = GearApi::dev().await?;
// Subscribe to events
let mut listener = api.subscribe().await?;
// Check that blocks are still running
assert!(listener.blocks_running().await?);
// Calculate gas amount needed for initialization
let gas_info = api
.calculate_upload_gas(
None,
gclient::code_from_os(WASM_PATH)?,
vec![],
0,
true,
None,
)
.await?;
// Upload and init the program
let (message_id, program_id, _hash) = api
.upload_program_bytes_by_path(
WASM_PATH,
gclient::now_micros().to_le_bytes(),
vec![],
gas_info.min_limit,
0,
)
.await?;
assert!(listener.message_processed(message_id).await?.succeed());
let payload = b"PING".to_vec();
// Calculate gas amount needed for handling the message
let gas_info = api
.calculate_handle_gas(None, program_id, payload.clone(), 0, true, None)
.await?;
// Send the PING message
let (message_id, _hash) = api
.send_message_bytes(program_id, payload, gas_info.min_limit, 0)
.await?;
assert!(listener.message_processed(message_id).await?.succeed());
Ok(())
}
Run the following command and wait for all tests to be green:
cargo test --release -- --include-ignored
It's recommended to mark with the #[ignore]
attribute tests with gclient
to separate their slow execution from the rest. To execute ignored tests with Cargo, add the --include-ignored
flag after a double dash (--
) as shown above.
Consider what has been done in the test function above.
First, the API is instantiated to enable interaction with the node through the invocation of corresponding extrinsics. Subsequently, an event listener is created, as obtaining feedback from the node is achievable solely through event subscription. The API instance is used for invoking RPC calls (e.g., calculating the required gas amount for processing) and dispatching extrinsics (e.g., uploading the program and transmitting a message). The event listener facilitates the retrieval of operation results.
More details about gclient
Please refer to the gclient
docs for more information about its capabilities and use cases.