Skip to content

Commit

Permalink
Merge pull request #5098 from m1sterc001guy/all_peers_online
Browse files Browse the repository at this point in the history
test: FederationTestBuilder for building federations in rust tests
  • Loading branch information
dpc committed Apr 28, 2024
2 parents a5e7326 + 8cd8def commit 0d95d32
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 94 deletions.
134 changes: 101 additions & 33 deletions fedimint-testing/src/federation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use fedimint_core::db::mem_impl::MemDatabase;
use fedimint_core::db::Database;
use fedimint_core::invite_code::InviteCode;
use fedimint_core::module::ApiAuth;
use fedimint_core::task::TaskGroup;
use fedimint_core::task::{block_in_place, TaskGroup};
use fedimint_core::PeerId;
use fedimint_logging::LOG_TEST;
use fedimint_rocksdb::RocksDb;
Expand Down Expand Up @@ -116,7 +116,7 @@ impl FederationTest {
self.configs[&PeerId::from(0)].get_invite_code()
}

/// Return first id for gateways
/// Return the federation id
pub fn id(&self) -> FederationId {
self.configs[&PeerId::from(0)]
.consensus
Expand All @@ -125,51 +125,119 @@ impl FederationTest {
.global
.calculate_federation_id()
}
}

/// Builder struct for creating a `FederationTest`.
#[derive(Clone, Debug)]
pub struct FederationTestBuilder {
num_peers: u16,
num_offline: u16,
base_port: u16,
primary_client: ModuleInstanceId,
version_hash: String,
params: ServerModuleConfigGenParamsRegistry,
server_init: ServerModuleInitRegistry,
client_init: ClientModuleInitRegistry,
reliability: Option<StreamReliability>,
}

#[allow(clippy::too_many_arguments)]
pub(crate) async fn new(
num_peers: u16,
num_offline: u16,
base_port: u16,
impl FederationTestBuilder {
pub fn new(
params: ServerModuleConfigGenParamsRegistry,
server_init: ServerModuleInitRegistry,
client_init: ClientModuleInitRegistry,
primary_client: ModuleInstanceId,
version_hash: String,
) -> Self {
) -> FederationTestBuilder {
let num_peers = 4;
Self {
num_peers,
num_offline: 1,
base_port: block_in_place(|| fedimint_portalloc::port_alloc(num_peers * 2))
.expect("Failed to allocate a port range"),
primary_client: 0,
version_hash: "fedimint-testing-dummy-version-hash".to_owned(),
params,
server_init,
client_init,
reliability: None,
}
}

pub fn num_peers(mut self, num_peers: u16) -> FederationTestBuilder {
self.num_peers = num_peers;
self
}

pub fn num_offline(mut self, num_offline: u16) -> FederationTestBuilder {
self.num_offline = num_offline;
self
}

pub fn base_port(mut self, base_port: u16) -> FederationTestBuilder {
self.base_port = base_port;
self
}

pub fn primary_client(mut self, primary_client: ModuleInstanceId) -> FederationTestBuilder {
self.primary_client = primary_client;
self
}

pub fn version_hash(mut self, version_hash: String) -> FederationTestBuilder {
self.version_hash = version_hash;
self
}

pub fn add_unreliable_connections(mut self) -> FederationTestBuilder {
self.reliability = Some(StreamReliability::INTEGRATION_TEST);
self
}

pub async fn build(self) -> FederationTest {
let num_offline = self.num_offline;
assert!(
num_peers > 3 * num_offline,
self.num_peers > 3 * self.num_offline,
"too many peers offline ({num_offline}) to reach consensus"
);
let peers = (0..num_peers).map(PeerId::from).collect::<Vec<_>>();
let params =
local_config_gen_params(&peers, base_port, params).expect("Generates local config");
let peers = (0..self.num_peers).map(PeerId::from).collect::<Vec<_>>();
let params = local_config_gen_params(&peers, self.base_port, self.params)
.expect("Generates local config");

let configs = ServerConfig::trusted_dealer_gen(&params, server_init.clone(), version_hash);
let configs =
ServerConfig::trusted_dealer_gen(&params, self.server_init.clone(), self.version_hash);
let network = MockNetwork::new();

let task_group = TaskGroup::new();
for (peer_id, config) in configs.clone() {
if u16::from(peer_id) >= num_peers - num_offline {
if u16::from(peer_id) >= self.num_peers - self.num_offline {
continue;
}
let reliability = StreamReliability::INTEGRATION_TEST;
let connections = network.connector(peer_id, reliability).into_dyn();

let instances = config.consensus.iter_module_instances();
let decoders = server_init.available_decoders(instances).unwrap();
let decoders = self.server_init.available_decoders(instances).unwrap();
let db = Database::new(MemDatabase::new(), decoders);

let (consensus_server, consensus_api) = ConsensusServer::new_with(
config.clone(),
db.clone(),
server_init.clone(),
connections,
DelayCalculator::TEST_DEFAULT,
&task_group,
)
.await
.expect("Failed to init server");
let (consensus_server, consensus_api) = if let Some(reliability) = self.reliability {
let connections = network.connector(peer_id, reliability).into_dyn();
ConsensusServer::new_with(
config.clone(),
db.clone(),
self.server_init.clone(),
connections,
DelayCalculator::TEST_DEFAULT,
&task_group,
)
.await
.expect("Failed to init server")
} else {
ConsensusServer::new(
config.clone(),
db.clone(),
self.server_init.clone(),
&task_group,
)
.await
.expect("Setting up consensus server")
};

let api_handle = FedimintServer::spawn_consensus_api(consensus_api).await;

Expand All @@ -179,11 +247,11 @@ impl FederationTest {
});
}

Self {
FederationTest {
configs,
server_init,
client_init,
primary_client,
server_init: self.server_init,
client_init: self.client_init,
primary_client: self.primary_client,
_task: task_group,
}
}
Expand Down
36 changes: 11 additions & 25 deletions fedimint-testing/src/fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@ use fedimint_core::module::{DynServerModuleInit, IServerModuleInit};
use fedimint_core::runtime::block_in_place;
use fedimint_core::task::{MaybeSend, MaybeSync, TaskGroup};
use fedimint_core::util::SafeUrl;
use fedimint_logging::{TracingSetup, LOG_TEST};
use fedimint_logging::TracingSetup;
use tempfile::TempDir;
use tracing::info;

use crate::btc::mock::FakeBitcoinFactory;
use crate::btc::real::RealBitcoinTest;
use crate::btc::BitcoinTest;
use crate::envs::{
FM_PORT_ESPLORA_ENV, FM_TEST_BITCOIND_RPC_ENV, FM_TEST_DIR_ENV, FM_TEST_USE_REAL_DAEMONS_ENV,
};
use crate::federation::FederationTest;
use crate::federation::{FederationTest, FederationTestBuilder};
use crate::gateway::GatewayTest;
use crate::ln::mock::FakeLightningTest;
use crate::ln::real::{ClnLightningTest, LndLightningTest};
Expand All @@ -37,12 +36,9 @@ pub const TIMEOUT: Duration = Duration::from_secs(10);

/// A tool for easily writing fedimint integration tests
pub struct Fixtures {
num_peers: u16,
num_offline: u16,
clients: Vec<DynClientModuleInit>,
servers: Vec<DynServerModuleInit>,
params: ServerModuleConfigGenParamsRegistry,
primary_client: ModuleInstanceId,
bitcoin_rpc: BitcoinRpcConfig,
bitcoin: Arc<dyn BitcoinTest>,
dyn_bitcoin_rpc: DynBitcoindRpc,
Expand All @@ -58,8 +54,6 @@ impl Fixtures {
// Ensure tracing has been set once
let _ = TracingSetup::default().init();
let real_testing = Fixtures::is_real_test();
let num_peers = 4;
let num_offline = 1;
let task_group = TaskGroup::new();
let (dyn_bitcoin_rpc, bitcoin, config): (
DynBitcoindRpc,
Expand All @@ -82,12 +76,9 @@ impl Fixtures {
};

Self {
num_peers,
num_offline,
clients: vec![],
servers: vec![],
params: Default::default(),
primary_client: 0,
bitcoin_rpc: config,
bitcoin,
dyn_bitcoin_rpc,
Expand Down Expand Up @@ -131,26 +122,21 @@ impl Fixtures {
}

/// Starts a new federation with default number of peers for testing
pub async fn new_fed(&self) -> FederationTest {
self.new_fed_with_peers(self.num_peers, self.num_offline)
.await
pub async fn new_default_fed(&self) -> FederationTest {
let federation_builder = FederationTestBuilder::new(
self.params.clone(),
ServerModuleInitRegistry::from(self.servers.clone()),
ClientModuleInitRegistry::from(self.clients.clone()),
);
federation_builder.build().await
}

/// Starts a new federation with number of peers
pub async fn new_fed_with_peers(&self, num_peers: u16, num_offline: u16) -> FederationTest {
info!(target: LOG_TEST, num_peers, "Setting federation with peers");
FederationTest::new(
num_peers,
num_offline,
block_in_place(|| fedimint_portalloc::port_alloc(num_peers * 2))
.expect("Failed to allocate a port range"),
pub fn new_fed_builder(&self) -> FederationTestBuilder {
FederationTestBuilder::new(
self.params.clone(),
ServerModuleInitRegistry::from(self.servers.clone()),
ClientModuleInitRegistry::from(self.clients.clone()),
self.primary_client,
"fedimint-testing-dummy-version-hash".to_owned(),
)
.await
}

/// Starts a new gateway with a given lightning node
Expand Down
14 changes: 7 additions & 7 deletions gateway/ln-gateway/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ where
let cln2 = fixtures.cln().await;

for (gateway_ln, other_node) in [(lnd1, cln1), (cln2, lnd2)] {
let fed = fixtures.new_fed().await;
let fed = fixtures.new_default_fed().await;
let mut gateway = fixtures
.new_gateway(gateway_ln, 0, Some(DEFAULT_GATEWAY_PASSWORD.to_string()))
.await;
Expand All @@ -127,8 +127,8 @@ where
B: Future<Output = anyhow::Result<()>>,
{
let fixtures = fixtures();
let fed1 = fixtures.new_fed().await;
let fed2 = fixtures.new_fed().await;
let fed1 = fixtures.new_default_fed().await;
let fed2 = fixtures.new_default_fed().await;

let lightning = match lightning_node_type {
LightningNodeType::Lnd => fixtures.lnd().await,
Expand Down Expand Up @@ -882,7 +882,7 @@ async fn test_gateway_client_intercept_htlc_invalid_offer() -> anyhow::Result<()
async fn test_gateway_register_with_federation() -> anyhow::Result<()> {
let fixtures = fixtures();
let node = fixtures.lnd().await;
let fed = fixtures.new_fed().await;
let fed = fixtures.new_default_fed().await;
let user_client = fed.new_client().await;
let mut gateway_test = fixtures
.new_gateway(node, 0, Some(DEFAULT_GATEWAY_PASSWORD.to_string()))
Expand Down Expand Up @@ -1038,7 +1038,7 @@ async fn test_gateway_filters_route_hints_by_inbound() -> anyhow::Result<()> {

tracing::info!("Creating federation with gateway type {gateway_type}. Number of route hints: {num_route_hints}");

let fed = fixtures.new_fed().await;
let fed = fixtures.new_default_fed().await;
let mut gateway = fixtures
.new_gateway(
gateway_ln,
Expand Down Expand Up @@ -1138,7 +1138,7 @@ async fn test_gateway_filters_route_hints_by_inbound() -> anyhow::Result<()> {
async fn test_cannot_connect_same_federation() -> anyhow::Result<()> {
let fixtures = fixtures();

let fed = fixtures.new_fed().await;
let fed = fixtures.new_default_fed().await;
let lnd = fixtures.lnd().await;
let gateway = fixtures
.new_gateway(lnd, 0, Some(DEFAULT_GATEWAY_PASSWORD.to_string()))
Expand Down Expand Up @@ -1176,7 +1176,7 @@ async fn test_cannot_connect_same_federation() -> anyhow::Result<()> {
async fn test_gateway_configuration() -> anyhow::Result<()> {
let fixtures = fixtures();

let fed = fixtures.new_fed().await;
let fed = fixtures.new_default_fed().await;
let lnd = fixtures.lnd().await;
let gateway = fixtures.new_gateway(lnd, 0, None).await;
let initial_rpc_client = gateway.get_rpc().await;
Expand Down
8 changes: 4 additions & 4 deletions modules/fedimint-dummy-tests/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn fixtures() -> Fixtures {

#[tokio::test(flavor = "multi_thread")]
async fn can_print_and_send_money() -> anyhow::Result<()> {
let fed = fixtures().new_fed().await;
let fed = fixtures().new_default_fed().await;
let (client1, client2) = fed.two_clients().await;

let client1_dummy_module = client1.get_first_module::<DummyClientModule>();
Expand All @@ -42,7 +42,7 @@ async fn can_print_and_send_money() -> anyhow::Result<()> {

#[tokio::test(flavor = "multi_thread")]
async fn client_ignores_unknown_module() {
let fed = fixtures().new_fed().await;
let fed = fixtures().new_default_fed().await;
let client = fed.new_client().await;

let mut cfg = client.get_config().clone();
Expand All @@ -66,7 +66,7 @@ async fn client_ignores_unknown_module() {

#[tokio::test(flavor = "multi_thread")]
async fn federation_should_abort_if_balance_sheet_is_negative() -> anyhow::Result<()> {
let fed = fixtures().new_fed().await;
let fed = fixtures().new_default_fed().await;
let client = fed.new_client().await;

let (panic_sender, panic_receiver) = std::sync::mpsc::channel::<()>();
Expand Down Expand Up @@ -115,7 +115,7 @@ async fn federation_should_abort_if_balance_sheet_is_negative() -> anyhow::Resul
/// the federation should reject because it's unbalanced.
#[tokio::test(flavor = "multi_thread")]
async fn unbalanced_transactions_get_rejected() -> anyhow::Result<()> {
let fed = fixtures().new_fed().await;
let fed = fixtures().new_default_fed().await;
let client = fed.new_client().await;

let dummy_module = client.get_first_module::<DummyClientModule>();
Expand Down

0 comments on commit 0d95d32

Please sign in to comment.