Skip to content

Commit

Permalink
Added e2e test to run 1000 dry_run (#1091)
Browse files Browse the repository at this point in the history
Reworked unit tests to execute the code directly without cmd.
  • Loading branch information
xgreenx authored Mar 30, 2023
1 parent 12bafa6 commit 6aad3df
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 151 deletions.
2 changes: 1 addition & 1 deletion bin/e2e-test-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ secret = "37fa81c84ccd547c30c176b118d5cb892bdb113e8e80141f266519422ef9eefd"
```

```shell
FUEL_CORE_E2E_CONFIG="/Users/your_user_name/fuel/e2e.toml" cargo run -p fuel-core-e2e-client
FUEL_CORE_E2E_CONFIG="/Users/your_user_name/fuel/e2e.toml" cargo run -p fuel-core-e2e-client -- --nocapture
```
93 changes: 92 additions & 1 deletion bin/e2e-test-client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,98 @@
use std::time::Duration;
use crate::{
config::SuiteConfig,
test_context::TestContext,
};
use libtest_mimic::{
Arguments,
Failed,
Trial,
};
use std::{
env,
fs,
future::Future,
time::Duration,
};

pub const CONFIG_FILE_KEY: &str = "FUEL_CORE_E2E_CONFIG";
pub const SYNC_TIMEOUT: Duration = Duration::from_secs(10);

pub mod config;
pub mod test_context;
pub mod tests;

pub fn main_body(config: SuiteConfig, mut args: Arguments) {
fn with_cloned(
config: &SuiteConfig,
f: impl FnOnce(SuiteConfig) -> anyhow::Result<(), Failed>,
) -> impl FnOnce() -> anyhow::Result<(), Failed> {
let config = config.clone();
move || f(config)
}

// If we run tests in parallel they may fail because try to use the same state like UTXOs.
args.test_threads = Some(1);

let tests = vec![
Trial::test(
"can transfer from alice to bob",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::transfers::basic_transfer(&ctx))
}),
),
Trial::test(
"can transfer from alice to bob and back",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::transfers::transfer_back(&ctx))
}),
),
Trial::test(
"can execute script and get receipts",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::script::receipts(&ctx))
}),
),
Trial::test(
"can dry run transfer script and get receipts",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::script::dry_run(&ctx))?;
Ok(())
}),
),
Trial::test(
"can deploy a large contract",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::contracts::deploy_large_contract(&ctx))
}),
),
];

libtest_mimic::run(&args, tests).exit();
}

pub fn load_config_env() -> SuiteConfig {
// load from env var
env::var_os(CONFIG_FILE_KEY)
.map(|path| load_config(path.to_string_lossy().to_string()))
.unwrap_or_default()
}

pub fn load_config(path: String) -> SuiteConfig {
let file = fs::read(path).unwrap();
toml::from_slice(&file).unwrap()
}

fn async_execute<F: Future<Output = anyhow::Result<(), Failed>>>(
func: F,
) -> Result<(), Failed> {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(func)
}
86 changes: 3 additions & 83 deletions bin/e2e-test-client/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,88 +1,8 @@
//! The `e2e-test-client` binary is used to run end-to-end tests for the Fuel client.
pub use fuel_core_e2e_client::*;
use fuel_core_e2e_client::{
config::SuiteConfig,
test_context::TestContext,
};
use libtest_mimic::{
Arguments,
Failed,
Trial,
};
use std::{
env,
fs,
future::Future,
};
use libtest_mimic::Arguments;

pub mod tests;

fn main() {
fn with_cloned(
config: &SuiteConfig,
f: impl FnOnce(SuiteConfig) -> anyhow::Result<(), Failed>,
) -> impl FnOnce() -> anyhow::Result<(), Failed> {
let config = config.clone();
move || f(config)
}

let mut args = Arguments::from_args();
// If we run tests in parallel they may fail because try to use the same state like UTXOs.
args.test_threads = Some(1);
let config = load_config();

let tests = vec![
Trial::test(
"can transfer from alice to bob",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::transfers::basic_transfer(&ctx))
}),
),
Trial::test(
"can execute script and get receipts",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::script::receipts(&ctx))
}),
),
Trial::test(
"can transfer from alice to bob and back",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::transfers::transfer_back(&ctx))
}),
),
Trial::test(
"can deploy a large contract",
with_cloned(&config, |config| {
let ctx = TestContext::new(config);
async_execute(tests::contracts::deploy_large_contract(&ctx))
}),
),
];

libtest_mimic::run(&args, tests).exit();
}

fn load_config() -> SuiteConfig {
// load from env var
env::var_os(CONFIG_FILE_KEY)
.map(|path| {
let path = path.to_string_lossy().to_string();
let file = fs::read(path).unwrap();
toml::from_slice(&file).unwrap()
})
.unwrap_or_default()
}

fn async_execute<F: Future<Output = anyhow::Result<(), Failed>>>(
func: F,
) -> Result<(), Failed> {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(func)
pub fn main() {
main_body(load_config_env(), Arguments::from_args())
}
29 changes: 20 additions & 9 deletions bin/e2e-test-client/src/test_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use fuel_core_types::{
Finalizable,
Input,
Output,
Transaction,
TransactionBuilder,
TxId,
UniqueIdentifier,
Expand Down Expand Up @@ -70,6 +71,7 @@ impl TestContext {
}
}

#[derive(Debug, Clone)]
pub struct Wallet {
pub secret: SecretKey,
pub address: Address,
Expand Down Expand Up @@ -130,13 +132,13 @@ impl Wallet {
Ok(false)
}

/// Transfers coins from this wallet to another
pub async fn transfer(
/// Creates the transfer transaction.
pub async fn transfer_tx(
&self,
destination: Address,
transfer_amount: u64,
asset_id: Option<AssetId>,
) -> anyhow::Result<TransferResult> {
) -> anyhow::Result<Transaction> {
let asset_id = asset_id.unwrap_or_default();
let asset_id_string = asset_id.to_string();
let asset_id_str = asset_id_string.as_str();
Expand Down Expand Up @@ -179,19 +181,28 @@ impl Wallet {
asset_id,
});

let tx = tx.finalize();
Ok(tx.finalize_as_transaction())
}

let status = self
.client
.submit_and_await_commit(&tx.clone().into())
/// Transfers coins from this wallet to another
pub async fn transfer(
&self,
destination: Address,
transfer_amount: u64,
asset_id: Option<AssetId>,
) -> anyhow::Result<TransferResult> {
let tx = self
.transfer_tx(destination, transfer_amount, asset_id)
.await?;
let tx_id = tx.id();
let status = self.client.submit_and_await_commit(&tx).await?;

// we know the transferred coin should be output 0 from above
let transferred_utxo = UtxoId::new(tx.id(), 0);
let transferred_utxo = UtxoId::new(tx_id, 0);

// get status and return the utxo id of transferred coin
Ok(TransferResult {
tx_id: tx.id(),
tx_id,
transferred_utxo,
success: matches!(status, TransactionStatus::Success { .. }),
status,
Expand Down
2 changes: 1 addition & 1 deletion bin/e2e-test-client/src/tests/contracts.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fuel_core_e2e_client::test_context::TestContext;
use crate::test_context::TestContext;
use libtest_mimic::Failed;
use std::time::Duration;
use tokio::time::timeout;
Expand Down
47 changes: 45 additions & 2 deletions bin/e2e-test-client/src/tests/script.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use fuel_core_e2e_client::test_context::{
use crate::test_context::{
TestContext,
BASE_AMOUNT,
};
use libtest_mimic::Failed;

// Alice makes transfer to Bob of `4 * BASE_AMOUNT` native tokens.
// Executes transfer script and gets the receipts.
pub async fn receipts(ctx: &TestContext) -> Result<(), Failed> {
// alice makes transfer to bob
let result = tokio::time::timeout(
Expand Down Expand Up @@ -37,3 +37,46 @@ pub async fn receipts(ctx: &TestContext) -> Result<(), Failed> {

Ok(())
}

// Dry run the transaction.
pub async fn dry_run(ctx: &TestContext) -> Result<(), Failed> {
let transaction = tokio::time::timeout(
ctx.config.sync_timeout(),
ctx.alice.transfer_tx(ctx.bob.address, 0, None),
)
.await??;

println!("\nStarting dry runs");
let mut queries = vec![];
for i in 0..1000 {
let tx = transaction.clone();
let alice = ctx.alice.clone();
queries.push(async move {
let before = tokio::time::Instant::now();
let query = alice.client.dry_run(&tx).await;
println!(
"Received the response for the query number {i} for {}ms",
before.elapsed().as_millis()
);
(query, i)
});
}

// All queries should be resolved for 30 seconds.
let queries = tokio::time::timeout(
std::time::Duration::from_secs(30),
futures::future::join_all(queries),
)
.await?;
for query in queries {
let (query, query_number) = query;
let receipts = query?;
if receipts.is_empty() {
return Err(
format!("Receipts are empty for query_number {query_number}").into(),
)
}
}

Ok(())
}
2 changes: 1 addition & 1 deletion bin/e2e-test-client/src/tests/transfers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fuel_core_e2e_client::test_context::{
use crate::test_context::{
TestContext,
BASE_AMOUNT,
};
Expand Down
Loading

0 comments on commit 6aad3df

Please sign in to comment.