Skip to content

Commit cf68cb0

Browse files
committed
Adding shutdown test cases for multiple activities
1 parent adab935 commit cf68cb0

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
@@ -1939,7 +1939,7 @@ mod tests {
19391939
}
19401940

19411941
#[tokio::test]
1942-
async fn test_manual_shutdown() {
1942+
async fn test_shutdown_manual() {
19431943
// Set up test nodes
19441944
let ((node_1, node_2), clients) = setup_test_nodes();
19451945

@@ -2082,4 +2082,168 @@ mod tests {
20822082
total_payments
20832083
);
20842084
}
2085+
2086+
#[tokio::test]
2087+
async fn test_shutdown_multiple_activities() {
2088+
let ((node_1, node_2), clients) = setup_test_nodes();
2089+
2090+
// Define activity 1: From node 0 to node 1 with a count limit of 3 payments
2091+
let activity_1 = crate::ActivityDefinition {
2092+
source: node_1.clone(),
2093+
destination: node_2.clone(),
2094+
start_secs: None, // Start immediately
2095+
count: Some(3), // Limited to 3 payments
2096+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2097+
amount_msat: crate::ValueOrRange::Value(2000), // 2000 msats
2098+
};
2099+
2100+
// Define activity 2: From node 2 to node 1 with no count limit
2101+
let activity_2 = crate::ActivityDefinition {
2102+
source: node_2.clone(),
2103+
destination: node_1.clone(),
2104+
start_secs: None, // Start immediately
2105+
count: None, // No limit (will run forever)
2106+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2107+
amount_msat: crate::ValueOrRange::Value(3000), // 3000 msats
2108+
};
2109+
2110+
// Create simulation with a timeout of 6 seconds
2111+
// This gives enough time for first activity to complete (3 payments at 1 second each)
2112+
// and for the second activity to continue making payments after that
2113+
let timeout_secs = 6;
2114+
let simulation = Simulation::new(
2115+
SimulationCfg::new(
2116+
Some(timeout_secs), // Run for 6 seconds
2117+
1000, // Expected payment size
2118+
0.1, // Activity multiplier
2119+
None, // No result writing
2120+
Some(42), // Seed for determinism
2121+
),
2122+
clients,
2123+
vec![activity_1, activity_2], // Use both activities
2124+
TaskTracker::new(),
2125+
);
2126+
2127+
// Run the simulation for the full timeout duration
2128+
let start = std::time::Instant::now();
2129+
let result = simulation.run().await;
2130+
let elapsed = start.elapsed();
2131+
2132+
// Verify the simulation ran correctly
2133+
assert!(result.is_ok(), "Simulation should end without error");
2134+
2135+
// Verify it ran for approximately the timeout duration
2136+
let margin = Duration::from_secs(1);
2137+
assert!(
2138+
elapsed >= Duration::from_secs(6) && elapsed <= Duration::from_secs(6) + margin,
2139+
"Simulation should have run for approximately {} seconds, but took {:?}",
2140+
timeout_secs,
2141+
elapsed
2142+
);
2143+
2144+
// We expect at least 8 payments in total:
2145+
// - 3 from activity 1 (which completes its count)
2146+
// - At least 5 from activity 2 (1 per second for 6 seconds)
2147+
// The exact number may vary slightly due to timing, but should be at least 8
2148+
let total_payments = simulation.get_total_payments().await;
2149+
assert!(
2150+
total_payments >= 8,
2151+
"Expected at least 8 payments to be attempted, got {}",
2152+
total_payments
2153+
);
2154+
}
2155+
2156+
#[tokio::test]
2157+
async fn test_shutdown_multiple_activities_with_error() {
2158+
// Set up test nodes with node_1 that will produce a permanent error
2159+
let ((node_1, node_2), mut clients) = setup_test_nodes();
2160+
2161+
// Create mock for node_1 that will return a permanent error on send_payment
2162+
let mut mock_node_1 = MockLightningNode::new();
2163+
let node_1_clone = node_1.clone();
2164+
2165+
// Set up basic expectations for node_1
2166+
mock_node_1.expect_get_info().return_const(node_1.clone());
2167+
mock_node_1
2168+
.expect_get_network()
2169+
.returning(|| Ok(Network::Regtest));
2170+
mock_node_1
2171+
.expect_list_channels()
2172+
.returning(|| Ok(vec![100_000]));
2173+
mock_node_1
2174+
.expect_get_node_info()
2175+
.returning(move |_| Ok(node_1_clone.clone()));
2176+
mock_node_1.expect_track_payment().returning(|_, _| {
2177+
Ok(crate::PaymentResult {
2178+
htlc_count: 1,
2179+
payment_outcome: crate::PaymentOutcome::Success,
2180+
})
2181+
});
2182+
2183+
// Set up node_1 to return a permanent error on send_payment
2184+
mock_node_1.expect_send_payment().returning(|_, _| {
2185+
Err(LightningError::PermanentError(
2186+
"Simulated permanent error".to_string(),
2187+
))
2188+
});
2189+
2190+
// Replace node_1 with our new mock
2191+
clients.insert(node_1.pubkey, Arc::new(Mutex::new(mock_node_1)));
2192+
2193+
// Define two activities
2194+
// Activity 1: From node_1 to node_2 - This will encounter the permanent error
2195+
let activity_1 = crate::ActivityDefinition {
2196+
source: node_1.clone(),
2197+
destination: node_2.clone(),
2198+
start_secs: None,
2199+
count: None, // No limit
2200+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2201+
amount_msat: crate::ValueOrRange::Value(2000), // 2000 msats
2202+
};
2203+
2204+
// Activity 2: From node_2 to node_1 - This would normally succeed
2205+
let activity_2 = crate::ActivityDefinition {
2206+
source: node_2.clone(),
2207+
destination: node_1.clone(),
2208+
start_secs: Some(2), // Start 2 seconds after the first activity
2209+
count: Some(10), // 10 payments if no error
2210+
interval_secs: crate::ValueOrRange::Value(1), // 1 second interval
2211+
amount_msat: crate::ValueOrRange::Value(3000), // 3000 msats
2212+
};
2213+
2214+
// Create simulation with a long timeout that we don't expect to be reached
2215+
let simulation = Simulation::new(
2216+
SimulationCfg::new(
2217+
Some(30), // 30 second timeout (shouldn't matter)
2218+
1000, // Expected payment size
2219+
0.1, // Activity multiplier
2220+
None, // No result writing
2221+
Some(42), // Seed for determinism
2222+
),
2223+
clients,
2224+
vec![activity_1, activity_2], // Use both activities
2225+
TaskTracker::new(),
2226+
);
2227+
2228+
// Run the simulation (should be interrupted by the error)
2229+
let start = std::time::Instant::now();
2230+
let _ = simulation.run().await;
2231+
let elapsed = start.elapsed();
2232+
2233+
// Check that simulation ran for a short time (less than 3 seconds)
2234+
assert!(
2235+
elapsed < Duration::from_secs(3),
2236+
"Simulation should have shut down quickly after encountering the error, took {:?}",
2237+
elapsed
2238+
);
2239+
2240+
// We expect no successful payments to be recorded since the first activity errors immediately
2241+
// and it should shut down the entire simulation
2242+
let total_payments = simulation.get_total_payments().await;
2243+
assert_eq!(
2244+
total_payments, 0,
2245+
"Expected no payments to be recorded, got {}",
2246+
total_payments
2247+
);
2248+
}
20852249
}

0 commit comments

Comments
 (0)