@@ -1866,7 +1866,7 @@ mod tests {
1866
1866
}
1867
1867
1868
1868
#[ tokio:: test]
1869
- async fn test_manual_shutdown ( ) {
1869
+ async fn test_shutdown_manual ( ) {
1870
1870
// Set up test nodes
1871
1871
let ( ( node_1, node_2) , clients) = setup_test_nodes ( ) ;
1872
1872
@@ -2009,4 +2009,168 @@ mod tests {
2009
2009
total_payments
2010
2010
) ;
2011
2011
}
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
+ }
2012
2176
}
0 commit comments