Skip to content

Commit db96a89

Browse files
committed
Adding shutdown test cases for multiple activities
1 parent 5936a15 commit db96a89

File tree

1 file changed

+165
-1
lines changed

1 file changed

+165
-1
lines changed

simln-lib/src/lib.rs

+165-1
Original file line numberDiff line numberDiff line change
@@ -1866,7 +1866,7 @@ mod tests {
18661866
}
18671867

18681868
#[tokio::test]
1869-
async fn test_manual_shutdown() {
1869+
async fn test_shutdown_manual() {
18701870
// Set up test nodes
18711871
let ((node_1, node_2), clients) = setup_test_nodes();
18721872

@@ -2009,4 +2009,168 @@ mod tests {
20092009
total_payments
20102010
);
20112011
}
2012+
2013+
#[tokio::test]
2014+
async fn test_shutdown_multiple_activities() {
2015+
let ((node_1, node_2), clients) = setup_test_nodes();
2016+
2017+
// Define activity 1: From node 0 to node 1 with a count limit of 3 payments
2018+
let activity_1 = crate::ActivityDefinition {
2019+
source: node_1.clone(),
2020+
destination: node_2.clone(),
2021+
start_secs: None, // Start immediately
2022+
count: Some(3), // Limited to 3 payments
2023+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2024+
amount_msat: crate::ValueOrRange::Value(2000), // 2000 msats
2025+
};
2026+
2027+
// Define activity 2: From node 2 to node 1 with no count limit
2028+
let activity_2 = crate::ActivityDefinition {
2029+
source: node_2.clone(),
2030+
destination: node_1.clone(),
2031+
start_secs: None, // Start immediately
2032+
count: None, // No limit (will run forever)
2033+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2034+
amount_msat: crate::ValueOrRange::Value(3000), // 3000 msats
2035+
};
2036+
2037+
// Create simulation with a timeout of 6 seconds
2038+
// This gives enough time for first activity to complete (3 payments at 1 second each)
2039+
// and for the second activity to continue making payments after that
2040+
let timeout_secs = 6;
2041+
let simulation = Simulation::new(
2042+
SimulationCfg::new(
2043+
Some(timeout_secs), // Run for 6 seconds
2044+
1000, // Expected payment size
2045+
0.1, // Activity multiplier
2046+
None, // No result writing
2047+
Some(42), // Seed for determinism
2048+
),
2049+
clients,
2050+
vec![activity_1, activity_2], // Use both activities
2051+
TaskTracker::new(),
2052+
);
2053+
2054+
// Run the simulation for the full timeout duration
2055+
let start = std::time::Instant::now();
2056+
let result = simulation.run().await;
2057+
let elapsed = start.elapsed();
2058+
2059+
// Verify the simulation ran correctly
2060+
assert!(result.is_ok(), "Simulation should end without error");
2061+
2062+
// Verify it ran for approximately the timeout duration
2063+
let margin = Duration::from_secs(1);
2064+
assert!(
2065+
elapsed >= Duration::from_secs(6) && elapsed <= Duration::from_secs(6) + margin,
2066+
"Simulation should have run for approximately {} seconds, but took {:?}",
2067+
timeout_secs,
2068+
elapsed
2069+
);
2070+
2071+
// We expect at least 8 payments in total:
2072+
// - 3 from activity 1 (which completes its count)
2073+
// - At least 5 from activity 2 (1 per second for 6 seconds)
2074+
// The exact number may vary slightly due to timing, but should be at least 8
2075+
let total_payments = simulation.get_total_payments().await;
2076+
assert!(
2077+
total_payments >= 8,
2078+
"Expected at least 8 payments to be attempted, got {}",
2079+
total_payments
2080+
);
2081+
}
2082+
2083+
#[tokio::test]
2084+
async fn test_shutdown_multiple_activities_with_error() {
2085+
// Set up test nodes with node_1 that will produce a permanent error
2086+
let ((node_1, node_2), mut clients) = setup_test_nodes();
2087+
2088+
// Create mock for node_1 that will return a permanent error on send_payment
2089+
let mut mock_node_1 = MockLightningNode::new();
2090+
let node_1_clone = node_1.clone();
2091+
2092+
// Set up basic expectations for node_1
2093+
mock_node_1.expect_get_info().return_const(node_1.clone());
2094+
mock_node_1
2095+
.expect_get_network()
2096+
.returning(|| Ok(Network::Regtest));
2097+
mock_node_1
2098+
.expect_list_channels()
2099+
.returning(|| Ok(vec![100_000]));
2100+
mock_node_1
2101+
.expect_get_node_info()
2102+
.returning(move |_| Ok(node_1_clone.clone()));
2103+
mock_node_1.expect_track_payment().returning(|_, _| {
2104+
Ok(crate::PaymentResult {
2105+
htlc_count: 1,
2106+
payment_outcome: crate::PaymentOutcome::Success,
2107+
})
2108+
});
2109+
2110+
// Set up node_1 to return a permanent error on send_payment
2111+
mock_node_1.expect_send_payment().returning(|_, _| {
2112+
Err(LightningError::PermanentError(
2113+
"Simulated permanent error".to_string(),
2114+
))
2115+
});
2116+
2117+
// Replace node_1 with our new mock
2118+
clients.insert(node_1.pubkey, Arc::new(Mutex::new(mock_node_1)));
2119+
2120+
// Define two activities
2121+
// Activity 1: From node_1 to node_2 - This will encounter the permanent error
2122+
let activity_1 = crate::ActivityDefinition {
2123+
source: node_1.clone(),
2124+
destination: node_2.clone(),
2125+
start_secs: None,
2126+
count: None, // No limit
2127+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2128+
amount_msat: crate::ValueOrRange::Value(2000), // 2000 msats
2129+
};
2130+
2131+
// Activity 2: From node_2 to node_1 - This would normally succeed
2132+
let activity_2 = crate::ActivityDefinition {
2133+
source: node_2.clone(),
2134+
destination: node_1.clone(),
2135+
start_secs: Some(2), // Start 2 seconds after the first activity
2136+
count: Some(10), // 10 payments if no error
2137+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2138+
amount_msat: crate::ValueOrRange::Value(3000), // 3000 msats
2139+
};
2140+
2141+
// Create simulation with a long timeout that we don't expect to be reached
2142+
let simulation = Simulation::new(
2143+
SimulationCfg::new(
2144+
Some(30), // 30 second timeout (shouldn't matter)
2145+
1000, // Expected payment size
2146+
0.1, // Activity multiplier
2147+
None, // No result writing
2148+
Some(42), // Seed for determinism
2149+
),
2150+
clients,
2151+
vec![activity_1, activity_2], // Use both activities
2152+
TaskTracker::new(),
2153+
);
2154+
2155+
// Run the simulation (should be interrupted by the error)
2156+
let start = std::time::Instant::now();
2157+
let _ = simulation.run().await;
2158+
let elapsed = start.elapsed();
2159+
2160+
// Check that simulation ran for a short time (less than 3 seconds)
2161+
assert!(
2162+
elapsed < Duration::from_secs(3),
2163+
"Simulation should have shut down quickly after encountering the error, took {:?}",
2164+
elapsed
2165+
);
2166+
2167+
// We expect no successful payments to be recorded since the first activity errors immediately
2168+
// and it should shut down the entire simulation
2169+
let total_payments = simulation.get_total_payments().await;
2170+
assert_eq!(
2171+
total_payments, 0,
2172+
"Expected no payments to be recorded, got {}",
2173+
total_payments
2174+
);
2175+
}
20122176
}

0 commit comments

Comments
 (0)