Skip to content

Commit

Permalink
refactor: tidy up test network code & docs
Browse files Browse the repository at this point in the history
Signed-off-by: 0x009922 <[email protected]>
  • Loading branch information
0x009922 committed Sep 20, 2024
1 parent 48e10dc commit 5d57d45
Show file tree
Hide file tree
Showing 11 changed files with 428 additions and 367 deletions.
42 changes: 27 additions & 15 deletions crates/iroha/tests/integration/extra_functional/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::time::Duration;

use eyre::Context;
use futures_util::{stream::FuturesUnordered, StreamExt};
use iroha::data_model::{
domain::{Domain, DomainId},
isi::Register,
};
use iroha_test_network::NetworkBuilder;
use tokio::task::spawn_blocking;
use iroha_test_network::{NetworkBuilder, PeerLifecycleEvent};
use tokio::{task::spawn_blocking, time::timeout};

#[tokio::test]
async fn all_peers_submit_genesis() -> eyre::Result<()> {
Expand All @@ -24,19 +26,29 @@ async fn multiple_genesis_4_peers_2_genesis() -> eyre::Result<()> {

async fn multiple_genesis_peers(n_peers: usize, n_genesis_peers: usize) -> eyre::Result<()> {
let network = NetworkBuilder::new().with_peers(n_peers).build();
network
.peers()
.enumerate()
.map(|(i, peer)| {
peer.start(
network.config(),
(i < n_genesis_peers).then_some(network.genesis()),
)
})
.collect::<FuturesUnordered<_>>()
.collect::<Vec<_>>()
.await;
network.ensure_synchronised_blocks_height(1).await?;
timeout(
Duration::from_secs(5),
network
.peers()
.enumerate()
.map(|(i, peer)| {
let cfg = network.config();
let genesis = (i < n_genesis_peers).then_some(network.genesis());
async move {
tokio::join!(
peer.spawn(cfg, genesis),
peer.once(|e| matches!(
e,
PeerLifecycleEvent::LogBlockCommitted { height: 1 }
))
);
}
})
.collect::<FuturesUnordered<_>>()
.collect::<Vec<_>>(),
)
.await
.expect("should start");

let client = network.client();
let domain_id: DomainId = "foo".parse().expect("Valid");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::{num::NonZero, time::Duration};

use eyre::Result;
use futures_util::StreamExt;
use iroha::{
client::{self},
data_model::prelude::*,
Expand All @@ -10,7 +7,7 @@ use iroha_data_model::parameter::BlockParameter;
use iroha_test_network::*;
use iroha_test_samples::gen_account_in;
use nonzero_ext::nonzero;
use tokio::{task::spawn_blocking, time::sleep};
use tokio::task::spawn_blocking;

#[tokio::test]
async fn multiple_blocks_created() -> Result<()> {
Expand All @@ -19,13 +16,27 @@ async fn multiple_blocks_created() -> Result<()> {
// Given
let network = NetworkBuilder::new()
.with_peers(4)
.push_isi(SetParameter(Parameter::Block(
.append_instruction(SetParameter(Parameter::Block(
BlockParameter::MaxTransactions(nonzero!(1u64)),
)))
.start()
.await?;
let client_one = network.peers().take(1).next().unwrap().client_for_alice();
let client_two = network.peers().last().unwrap().client_for_alice();
let peer_one = network.peer();
let client_one = peer_one.alice_client();
let last_peer = network.peers().last().unwrap();
assert_ne!(peer_one.id(), last_peer.id());

let mut events = last_peer.events();
tokio::spawn(async move {
while let Ok(e) = events.recv().await {
match e {
PeerLifecycleEvent::LogBlockCommitted { height } => {
println!("Last peer block committed: {height}")
}
_ => {}
}
}
});

let create_domain = Register::domain(Domain::new("domain".parse()?));
let (account_id, _account_keypair) = gen_account_in("domain");
Expand Down Expand Up @@ -63,7 +74,7 @@ async fn multiple_blocks_created() -> Result<()> {
AssetId::new(definition.clone(), account.clone()),
))
.expect("submit cannot fail");
println!("{i}/{N_BLOCKS}");
println!("Submitted {}/{N_BLOCKS} txs", i + 1);
}
})
.await?;
Expand All @@ -72,6 +83,7 @@ async fn multiple_blocks_created() -> Result<()> {
.await?;

// Then
let client_two = last_peer.alice_client();
let asset = spawn_blocking(move || {
client_two
.query(client::asset::all())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async fn genesis_block_is_committed_with_some_offline_peers() -> Result<()> {
// only 2 out of 4
.take(2)
.enumerate()
.map(|(i, peer)| peer.start(cfg.clone(), (i == 0).then_some(genesis)))
.map(|(i, peer)| peer.spawn(cfg.clone(), (i == 0).then_some(genesis)))
.collect::<FuturesUnordered<_>>()
.collect::<Vec<_>>()
.await;
Expand Down Expand Up @@ -80,7 +80,7 @@ async fn register_offline_peer() -> Result<()> {

async fn check_status(network: &Network, expected_peers: u64) {
for peer in network.peers() {
let client = peer.client_for_alice();
let client = peer.alice_client();
let status = spawn_blocking(move || client.get_status())
.await
.expect("no panic")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> {

let network = NetworkBuilder::new().with_peers(4).start().await?;

let random_client = network.random_peer().client_for_alice();
let random_client = network.random_peer().alice_client();
let asset_definition_clone = asset_definition_id.clone();
spawn_blocking(move || {
random_client
Expand All @@ -34,7 +34,7 @@ async fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> {
// Wait for observing peer to get the block
sleep(network.pipeline_time()).await;

let random_client = network.random_peer().client_for_alice();
let random_client = network.random_peer().alice_client();
let assets = spawn_blocking(move || {
random_client
.query(client::asset::all())
Expand All @@ -55,13 +55,13 @@ async fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> {

// restart one
let peer = network.random_peer();
peer.start(network.config().clone(), Some(network.genesis()))
peer.spawn(network.config().clone(), Some(network.genesis()))
.await;
network.ensure_synchronised_blocks_height(1).await?;

iroha_logger::info!("peer restart");

let client = peer.client_for_alice();
let client = peer.alice_client();
let assets = spawn_blocking(move || {
client
.query(client::asset::all())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ fn unstable_network_stable_after_add_and_after_remove_peer() -> Result<()> {
// and a new peer is registered
let peer = network.add_peer();
let peer_id = peer.id();
let peer_client = peer.client_for_alice();
rt.block_on(async { peer.start(network.config(), None).await });
let peer_client = peer.alice_client();
rt.block_on(async { peer.spawn(network.config(), None).await });
client.submit_blocking(Register::peer(Peer::new(peer_id.clone())))?;
// Then the new peer should already have the mint result.
network.poll_sync(|| {
Expand Down
16 changes: 8 additions & 8 deletions crates/iroha/tests/integration/permissions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{thread, time::Duration};
use std::time::Duration;

use eyre::Result;
use futures_util::{future::join_all, stream::FuturesUnordered};
use iroha::{
client::{self, Client},
crypto::KeyPair,
Expand All @@ -14,10 +13,9 @@ use iroha_executor_data_model::permission::{
asset::{CanSetKeyValueInUserAsset, CanTransferUserAsset},
domain::CanSetKeyValueInDomain,
};
use iroha_genesis::GenesisBlock;
use iroha_test_network::*;
use iroha_test_samples::{gen_account_in, ALICE_ID, BOB_ID};
use tokio::{join, task::JoinSet, time::timeout};
use tokio::{join, time::timeout};

// FIXME
#[tokio::test]
Expand All @@ -28,18 +26,20 @@ async fn genesis_transactions_are_validated_by_executor() {
let asset_definition_id = "xor#wonderland".parse().expect("Valid");
let invalid_instruction =
Register::asset_definition(AssetDefinition::numeric(asset_definition_id));
let network = NetworkBuilder::new().push_isi(invalid_instruction).build();
let network = NetworkBuilder::new()
.append_instruction(invalid_instruction)
.build();
let peer = network.peer();

timeout(Duration::from_secs(3), async {
join!(
// Peer should start...
peer.start(network.config(), Some(network.genesis())),
peer.once(|event| matches!(event, PeerExecutionEvent::ServerStarted)),
peer.spawn(network.config(), Some(network.genesis())),
peer.once(|event| matches!(event, PeerLifecycleEvent::ServerStarted)),
// ...but it should shortly exit with an error
peer.once(|event| match event {
// TODO: handle "Invalid genesis" more granular
PeerExecutionEvent::Terminated { status } => !status.success(),
PeerLifecycleEvent::Terminated { status } => !status.success(),
_ => false,
})
)
Expand Down
15 changes: 6 additions & 9 deletions crates/iroha/tests/integration/transfer_domain.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use eyre::Result;
use iroha::{
client,
client::Client,
crypto::KeyPair,
data_model::{prelude::*, transaction::error::TransactionRejectionReason},
};
Expand All @@ -12,11 +11,9 @@ use iroha_executor_data_model::permission::{
domain::{CanRegisterAssetDefinitionInDomain, CanUnregisterDomain},
trigger::CanUnregisterUserTrigger,
};
use iroha_genesis::GenesisBlock;
use iroha_primitives::json::JsonString;
use iroha_test_network::*;
use iroha_test_samples::{gen_account_in, ALICE_ID, BOB_ID, SAMPLE_GENESIS_ACCOUNT_ID};
use tokio::runtime::Runtime;

#[test]
fn domain_owner_domain_permissions() -> Result<()> {
Expand Down Expand Up @@ -367,16 +364,16 @@ fn not_allowed_to_transfer_other_user_domain() -> Result<()> {
let genesis_account = SAMPLE_GENESIS_ACCOUNT_ID.clone();

let (network, _rt) = NetworkBuilder::new()
.push_isi(Register::domain(Domain::new(users_domain.clone())))
.push_isi(Register::account(Account::new(user1.clone())))
.push_isi(Register::account(Account::new(user2.clone())))
.push_isi(Register::domain(Domain::new(foo_domain.clone())))
.push_isi(Transfer::domain(
.append_instruction(Register::domain(Domain::new(users_domain.clone())))
.append_instruction(Register::account(Account::new(user1.clone())))
.append_instruction(Register::account(Account::new(user2.clone())))
.append_instruction(Register::domain(Domain::new(foo_domain.clone())))
.append_instruction(Transfer::domain(
genesis_account.clone(),
foo_domain.clone(),
user1.clone(),
))
.push_isi(Transfer::domain(
.append_instruction(Transfer::domain(
genesis_account.clone(),
users_domain.clone(),
user1.clone(),
Expand Down
2 changes: 2 additions & 0 deletions crates/iroha_config_base/src/toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ impl<'a> From<&'a mut Table> for Writer<'a> {
}
}

/// Extension trait to implement writing with [`Writer`] directly into [`Table`] in a chained manner.
pub trait WriteExt: Sized {
/// See [`Writer::write`].
fn write<P: WritePath, T: Serialize>(self, path: P, value: T) -> Self;
}

Expand Down
98 changes: 98 additions & 0 deletions crates/iroha_test_network/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//! Sample configuration builders
use std::path::Path;

use iroha_config::base::toml::WriteExt;
use iroha_data_model::{
asset::AssetDefinitionId,
isi::{Grant, Instruction},
peer::PeerId,
ChainId,
};
use iroha_executor_data_model::permission::{
asset::{CanBurnAssetWithDefinition, CanMintAssetWithDefinition},
domain::CanUnregisterDomain,
executor::CanUpgradeExecutor,
peer::CanUnregisterAnyPeer,
role::CanUnregisterAnyRole,
};
use iroha_genesis::{GenesisBlock, RawGenesisTransaction};
use iroha_primitives::unique_vec::UniqueVec;
use iroha_test_samples::{ALICE_ID, SAMPLE_GENESIS_ACCOUNT_KEYPAIR};
use toml::Table;

pub fn chain_id() -> ChainId {
ChainId::from("00000000-0000-0000-0000-000000000000")
}

pub fn base_iroha_config() -> Table {
Table::new()
.write("chain", chain_id())
.write(
["genesis", "public_key"],
SAMPLE_GENESIS_ACCOUNT_KEYPAIR.public_key(),
)
// There is no need in persistence in tests.
.write(["snapshot", "mode"], "disabled")
.write(["kura", "store_dir"], "./storage")
.write(["network", "block_gossip_size"], 1)
.write(["logger", "level"], "DEBUG")
}

pub fn genesis<T: Instruction>(
extra_isi: impl IntoIterator<Item = T>,
topology: UniqueVec<PeerId>,
) -> GenesisBlock {
// TODO: Fix this somehow. Probably we need to make `kagami` a library (#3253).
let mut genesis = RawGenesisTransaction::from_path(
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../defaults/genesis.json"),
)
.expect("Failed to deserialize genesis block from file");

let rose_definition_id = "rose#wonderland".parse::<AssetDefinitionId>().unwrap();

let grant_mint_rose_permission = Grant::account_permission(
CanMintAssetWithDefinition {
asset_definition: rose_definition_id.clone(),
},
ALICE_ID.clone(),
);
let grant_burn_rose_permission = Grant::account_permission(
CanBurnAssetWithDefinition {
asset_definition: rose_definition_id,
},
ALICE_ID.clone(),
);
let grant_unregister_any_peer_permission =
Grant::account_permission(CanUnregisterAnyPeer, ALICE_ID.clone());
let grant_unregister_any_role_permission =
Grant::account_permission(CanUnregisterAnyRole, ALICE_ID.clone());
let grant_unregister_wonderland_domain = Grant::account_permission(
CanUnregisterDomain {
domain: "wonderland".parse().unwrap(),
},
ALICE_ID.clone(),
);
let grant_upgrade_executor_permission =
Grant::account_permission(CanUpgradeExecutor, ALICE_ID.clone());
for isi in [
grant_mint_rose_permission,
grant_burn_rose_permission,
grant_unregister_any_peer_permission,
grant_unregister_any_role_permission,
grant_unregister_wonderland_domain,
grant_upgrade_executor_permission,
] {
genesis.append_instruction(isi);
}

for isi in extra_isi.into_iter() {
genesis.append_instruction(isi);
}

let genesis_key_pair = SAMPLE_GENESIS_ACCOUNT_KEYPAIR.clone();
genesis
.with_topology(topology.into())
.build_and_sign(&genesis_key_pair)
.expect("genesis should load fine")
}
Loading

0 comments on commit 5d57d45

Please sign in to comment.