Skip to content

Commit dda35c1

Browse files
authored
Merge pull request #236 from jirigrill/unit-tests-validate_activity-validate_node_network
simln-lib/test: unit tests for validate_activity and validate_node_network
2 parents e5482da + 9a7aa53 commit dda35c1

File tree

4 files changed

+357
-61
lines changed

4 files changed

+357
-61
lines changed

Cargo.lock

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

simln-lib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ hex = "0.4.3"
3030
csv = "1.2.2"
3131
serde_millis = "0.1.1"
3232
rand_distr = "0.4.3"
33-
mockall = "0.12.1"
3433
rand_chacha = "0.3.1"
3534
reqwest = { version = "0.12", features = ["json", "multipart"] }
3635
tokio-util = { version = "0.7.13", features = ["rt"] }
3736

3837
[dev-dependencies]
3938
ntest = "0.9.0"
39+
mockall = "0.13.1"

simln-lib/src/lib.rs

Lines changed: 174 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ pub mod lnd;
3333
mod random_activity;
3434
pub mod serializers;
3535
pub mod sim_node;
36-
#[cfg(test)]
3736
mod test_utils;
3837

3938
#[derive(Serialize, Debug, Clone)]
@@ -1418,18 +1417,17 @@ async fn track_payment_result(
14181417
#[cfg(test)]
14191418
mod tests {
14201419
use crate::{
1421-
get_payment_delay, test_utils, LightningError, LightningNode, MutRng, NodeInfo,
1422-
PaymentGenerationError, PaymentGenerator, Simulation,
1420+
get_payment_delay, test_utils, test_utils::LightningTestNodeBuilder, LightningError,
1421+
LightningNode, MutRng, PaymentGenerationError, PaymentGenerator,
14231422
};
1424-
use async_trait::async_trait;
14251423
use bitcoin::secp256k1::PublicKey;
1424+
use bitcoin::Network;
14261425
use mockall::mock;
14271426
use std::collections::HashMap;
14281427
use std::fmt;
14291428
use std::sync::Arc;
14301429
use std::time::Duration;
14311430
use tokio::sync::Mutex;
1432-
use tokio_util::task::TaskTracker;
14331431

14341432
#[test]
14351433
fn create_seeded_mut_rng() {
@@ -1472,27 +1470,6 @@ mod tests {
14721470
}
14731471
}
14741472

1475-
mock! {
1476-
pub LightningNode {}
1477-
#[async_trait]
1478-
impl crate::LightningNode for LightningNode {
1479-
fn get_info(&self) -> &NodeInfo;
1480-
async fn get_network(&mut self) -> Result<bitcoin::Network, LightningError>;
1481-
async fn send_payment(
1482-
&mut self,
1483-
dest: bitcoin::secp256k1::PublicKey,
1484-
amount_msat: u64,
1485-
) -> Result<lightning::ln::PaymentHash, LightningError>;
1486-
async fn track_payment(
1487-
&mut self,
1488-
hash: &lightning::ln::PaymentHash,
1489-
shutdown: triggered::Listener,
1490-
) -> Result<crate::PaymentResult, LightningError>;
1491-
async fn get_node_info(&mut self, node_id: &PublicKey) -> Result<NodeInfo, LightningError>;
1492-
async fn list_channels(&mut self) -> Result<Vec<u64>, LightningError>;
1493-
}
1494-
}
1495-
14961473
#[test]
14971474
fn test_no_payment_delay() {
14981475
let node = test_utils::create_nodes(1, 100_000)
@@ -1548,33 +1525,178 @@ mod tests {
15481525
);
15491526
}
15501527

1528+
/// Verifies that an empty activity (for random generation) is valid when two nodes with keysend
1529+
/// support are present, expecting an `Ok` result.
1530+
#[tokio::test]
1531+
async fn test_validate_activity_empty_with_sufficient_nodes() {
1532+
let (_, clients) = LightningTestNodeBuilder::new(3).build_full();
1533+
let simulation = test_utils::create_simulation(clients, vec![]);
1534+
let result = simulation.validate_activity().await;
1535+
assert!(result.is_ok());
1536+
}
1537+
1538+
/// Verifies that an empty activity fails validation with only one keysend-enabled node,
1539+
/// expecting a `ValidationError` with "At least two nodes required".
1540+
#[tokio::test]
1541+
async fn test_validate_activity_empty_with_insufficient_nodes() {
1542+
let (_, clients) = LightningTestNodeBuilder::new(1).build_full();
1543+
let simulation = test_utils::create_simulation(clients, vec![]);
1544+
let result = simulation.validate_activity().await;
1545+
1546+
assert!(result.is_err());
1547+
assert!(matches!(result,
1548+
Err(LightningError::ValidationError(msg)) if msg.contains("At least two nodes required")));
1549+
}
1550+
1551+
/// Verifies that an empty activity fails when one of two nodes doesn’t support keysend,
1552+
/// expecting a `ValidationError` with "must support keysend".
1553+
#[tokio::test]
1554+
async fn test_validate_activity_empty_with_non_keysend_node() {
1555+
let (_, clients) = LightningTestNodeBuilder::new(2)
1556+
.with_keysend_nodes(vec![0])
1557+
.build_full();
1558+
let simulation = test_utils::create_simulation(clients, vec![]);
1559+
let result = simulation.validate_activity().await;
1560+
1561+
assert!(result.is_err());
1562+
assert!(matches!(result,
1563+
Err(LightningError::ValidationError(msg)) if msg.contains("must support keysend")));
1564+
}
1565+
1566+
/// Verifies that an activity fails when the source node isn’t in the clients map,
1567+
/// expecting a `ValidationError` with "Source node not found".
1568+
#[tokio::test]
1569+
async fn test_validate_activity_with_missing_source_node() {
1570+
let (nodes, clients) = LightningTestNodeBuilder::new(1).build_full();
1571+
let missing_nodes = test_utils::create_nodes(1, 100_000);
1572+
let missing_node = missing_nodes.first().unwrap().0.clone();
1573+
let dest_node = nodes[0].clone();
1574+
1575+
let activity = test_utils::create_activity(missing_node, dest_node, 1000);
1576+
let simulation = test_utils::create_simulation(clients, vec![activity]);
1577+
let result = simulation.validate_activity().await;
1578+
1579+
assert!(result.is_err());
1580+
assert!(matches!(result,
1581+
Err(LightningError::ValidationError(msg)) if msg.contains("Source node not found")));
1582+
}
1583+
1584+
/// Verifies that an activity fails when the destination lacks keysend support,
1585+
/// expecting a `ValidationError` with "does not support keysend".
1586+
#[tokio::test]
1587+
async fn test_validate_activity_with_non_keysend_destination() {
1588+
let (nodes, clients) = LightningTestNodeBuilder::new(1).build_full();
1589+
let dest_nodes = test_utils::create_nodes(1, 100_000);
1590+
let dest_node = dest_nodes.first().unwrap().0.clone();
1591+
1592+
let activity = test_utils::create_activity(nodes[0].clone(), dest_node, 1000);
1593+
let simulation = test_utils::create_simulation(clients, vec![activity]);
1594+
let result = simulation.validate_activity().await;
1595+
1596+
assert!(result.is_err());
1597+
assert!(matches!(result,
1598+
Err(LightningError::ValidationError(msg)) if msg.contains("does not support keysend")));
1599+
}
1600+
1601+
/// Verifies that an activity with a non-zero amount between two keysend-enabled nodes
1602+
/// passes validation, expecting an `Ok` result.
1603+
#[tokio::test]
1604+
async fn test_validate_activity_valid_payment_flow() {
1605+
let (nodes, clients) = LightningTestNodeBuilder::new(1).build_full();
1606+
let dest_nodes = test_utils::create_nodes(1, 100_000);
1607+
let mut dest_node = dest_nodes.first().unwrap().0.clone();
1608+
dest_node.features.set_keysend_optional();
1609+
1610+
let activity = test_utils::create_activity(nodes[0].clone(), dest_node, 1000);
1611+
let simulation = test_utils::create_simulation(clients, vec![activity]);
1612+
let result = simulation.validate_activity().await;
1613+
1614+
assert!(result.is_ok());
1615+
}
1616+
1617+
/// Verifies that an activity with a zero amount between two keysend-enabled nodes fails,
1618+
/// expecting a `ValidationError` with "zero values".
15511619
#[tokio::test]
15521620
async fn test_validate_zero_amount_no_valid() {
1553-
let nodes = test_utils::create_nodes(2, 100_000);
1554-
let mut node_1 = nodes.first().unwrap().0.clone();
1555-
let mut node_2 = nodes.get(1).unwrap().0.clone();
1556-
node_1.features.set_keysend_optional();
1557-
node_2.features.set_keysend_optional();
1558-
1559-
let mock_node_1 = MockLightningNode::new();
1560-
let mock_node_2 = MockLightningNode::new();
1561-
let mut clients: HashMap<PublicKey, Arc<Mutex<dyn LightningNode>>> = HashMap::new();
1562-
clients.insert(node_1.pubkey, Arc::new(Mutex::new(mock_node_1)));
1563-
clients.insert(node_2.pubkey, Arc::new(Mutex::new(mock_node_2)));
1564-
let activity_definition = crate::ActivityDefinition {
1565-
source: node_1,
1566-
destination: node_2,
1567-
start_secs: None,
1568-
count: None,
1569-
interval_secs: crate::ValueOrRange::Value(0),
1570-
amount_msat: crate::ValueOrRange::Value(0),
1571-
};
1572-
let simulation = Simulation::new(
1573-
crate::SimulationCfg::new(Some(0), 0, 0.0, None, None),
1574-
clients,
1575-
vec![activity_definition],
1576-
TaskTracker::new(),
1577-
);
1578-
assert!(simulation.validate_activity().await.is_err());
1621+
let (nodes, clients) = LightningTestNodeBuilder::new(2).build_full();
1622+
1623+
let activity = test_utils::create_activity(nodes[0].clone(), nodes[1].clone(), 0);
1624+
let simulation = test_utils::create_simulation(clients, vec![activity]);
1625+
let result = simulation.validate_activity().await;
1626+
1627+
assert!(result.is_err());
1628+
assert!(matches!(result,
1629+
Err(LightningError::ValidationError(msg)) if msg.contains("zero values")));
1630+
}
1631+
1632+
/// Verifies that validation fails with no nodes, expecting a `ValidationError` with
1633+
/// "we don't control any nodes".
1634+
#[tokio::test]
1635+
async fn test_validate_node_network_empty_nodes() {
1636+
let empty_nodes: HashMap<PublicKey, Arc<Mutex<dyn LightningNode>>> = HashMap::new();
1637+
1638+
let simulation = test_utils::create_simulation(empty_nodes, vec![]);
1639+
let result = simulation.validate_node_network().await;
1640+
1641+
assert!(result.is_err());
1642+
assert!(matches!(result,
1643+
Err(LightningError::ValidationError(msg)) if msg.contains("we don't control any nodes")));
1644+
}
1645+
1646+
/// Verifies that a node on Bitcoin mainnet fails validation, expecting a `ValidationError`
1647+
/// with "mainnet is not supported".
1648+
#[tokio::test]
1649+
async fn test_validate_node_network_mainnet_not_supported() {
1650+
let clients = LightningTestNodeBuilder::new(1)
1651+
.with_networks(vec![Network::Bitcoin])
1652+
.build_clients_only();
1653+
1654+
let simulation = test_utils::create_simulation(clients, vec![]);
1655+
let result = simulation.validate_node_network().await;
1656+
1657+
assert!(result.is_err());
1658+
assert!(matches!(result,
1659+
Err(LightningError::ValidationError(msg)) if msg.contains("mainnet is not supported")));
1660+
}
1661+
1662+
/// Verifies that nodes on Testnet and Regtest fail validation, expecting a
1663+
/// `ValidationError` with "nodes are not on the same network".
1664+
#[tokio::test]
1665+
async fn test_validate_node_network_mixed_networks() {
1666+
let clients = LightningTestNodeBuilder::new(2)
1667+
.with_networks(vec![Network::Testnet, Network::Regtest])
1668+
.build_clients_only();
1669+
1670+
let simulation = test_utils::create_simulation(clients, vec![]);
1671+
let result = simulation.validate_node_network().await;
1672+
1673+
assert!(result.is_err());
1674+
assert!(matches!(result,
1675+
Err(LightningError::ValidationError(msg)) if msg.contains("nodes are not on the same network")));
1676+
}
1677+
1678+
/// Verifies that three Testnet nodes pass validation, expecting an `Ok` result.
1679+
#[tokio::test]
1680+
async fn test_validate_node_network_multiple_nodes_same_network() {
1681+
let clients = LightningTestNodeBuilder::new(3)
1682+
.with_networks(vec![Network::Testnet, Network::Testnet, Network::Testnet])
1683+
.build_clients_only();
1684+
1685+
let simulation = test_utils::create_simulation(clients, vec![]);
1686+
let result = simulation.validate_node_network().await;
1687+
1688+
assert!(result.is_ok());
1689+
}
1690+
1691+
#[tokio::test]
1692+
async fn test_validate_node_network_single_node_valid_network() {
1693+
let clients = LightningTestNodeBuilder::new(1)
1694+
.with_networks(vec![Network::Testnet])
1695+
.build_clients_only();
1696+
1697+
let simulation = test_utils::create_simulation(clients, vec![]);
1698+
let result = simulation.validate_node_network().await;
1699+
1700+
assert!(result.is_ok());
15791701
}
15801702
}

0 commit comments

Comments
 (0)