Skip to content

Commit 2b7c397

Browse files
authored
Merge pull request #312 from carlaKC/tests-virtualclock
Speed up tests using virtual time
2 parents cefd0c4 + 028b235 commit 2b7c397

2 files changed

Lines changed: 45 additions & 33 deletions

File tree

simln-lib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@ ntest = "0.9.0"
4343
mockall = "0.13.1"
4444
futures = "0.3.31"
4545
tempfile = "3"
46-
tokio = { version = "1.31.0", features = ["macros", "rt-multi-thread"] }
46+
tokio = { version = "1.31.0", features = ["macros", "rt-multi-thread", "test-util"] }

simln-lib/src/lib.rs

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,7 +1610,7 @@ async fn track_payment_result(
16101610

16111611
#[cfg(test)]
16121612
mod tests {
1613-
use crate::clock::SimulationClock;
1613+
use crate::clock::{Clock, SimulationClock};
16141614
use crate::test_utils::{MockLightningNode, TestNodesResult};
16151615
use crate::{
16161616
get_payment_delay, test_utils, test_utils::LightningTestNodeBuilder, LightningError,
@@ -2005,6 +2005,21 @@ mod tests {
20052005
});
20062006
}
20072007

2008+
/// Fixed pubkeys for payment ordering tests. Payment events that are scheduled for the same
2009+
/// instant are tie-broken on their source pubkey, so node keys must be stable across runs
2010+
/// for the order of payments to be deterministic.
2011+
fn fixed_test_pubkeys() -> Vec<PublicKey> {
2012+
[
2013+
"02f6dc1fcf3431f461ff5e6d870f286e134b064fddd3795a98d5903c55e76cfa8c",
2014+
"0363a5321c2778e2f13f4d7602a84e866824551b4bd31fdfc66e044a274863d647",
2015+
"037b0c8a943a6bc3ebb5b56ed1c377a1d3e6b68e9231ad9bf7afd45ba37374f7a3",
2016+
"026389dd21b3611bf4bb78f8939d5912f3175107ff9c14b6881bb4bef0e7c6e905",
2017+
]
2018+
.iter()
2019+
.map(|pk| PublicKey::from_str(pk).unwrap())
2020+
.collect()
2021+
}
2022+
20082023
#[allow(clippy::type_complexity)]
20092024
/// Helper to create and configure mock nodes for testing
20102025
async fn setup_test_nodes_for_testing_deterministic_events(
@@ -2053,10 +2068,12 @@ mod tests {
20532068
(network, payments_list)
20542069
}
20552070

2056-
#[tokio::test]
2071+
// Run on a paused runtime so that the payment interval sleeps auto-advance rather than
2072+
// consuming real time; elapsed time is measured against the simulation's virtual clock.
2073+
#[tokio::test(start_paused = true)]
20572074
async fn test_deterministic_payments_events_defined_activities() {
20582075
let (network, payments_list) =
2059-
setup_test_nodes_for_testing_deterministic_events(None).await;
2076+
setup_test_nodes_for_testing_deterministic_events(Some(fixed_test_pubkeys())).await;
20602077

20612078
// Define two activities
20622079
// Activity 1: From node_1 to node_2
@@ -2081,29 +2098,34 @@ mod tests {
20812098

20822099
let (shutdown_trigger, shutdown_listener) = triggered::trigger();
20832100

2101+
let clock = Arc::new(SimulationClock::new(SystemTime::now()));
2102+
20842103
// Create simulation without a timeout.
20852104
let simulation = Simulation::new(
20862105
SimulationCfg::new(None, 100, 2.0, None, None),
20872106
network.get_client_hashmap(),
20882107
TaskTracker::new(),
2089-
Arc::new(SimulationClock::new(SystemTime::now())),
2108+
clock.clone(),
20902109
shutdown_trigger,
20912110
shutdown_listener,
20922111
);
20932112

20942113
// Run the simulation
2095-
let start = std::time::Instant::now();
2114+
let start = clock.now();
20962115
let _ = simulation.run(&vec![activity_1, activity_2]).await;
2097-
let elapsed = start.elapsed();
2116+
let elapsed = clock.now().duration_since(start).unwrap();
20982117

2118+
// Activity 1 pays at t = 2, 4, 6, 8, 10 and activity 2 at t = 4, 8, 12, 16, 20. At the
2119+
// instants where both activities fire (t = 4, 8), activity 1 dispatches first because
2120+
// simultaneous events are ordered by source pubkey and its source sorts first.
20992121
let expected_payment_list = vec![
2122+
network.nodes[1].pubkey,
21002123
network.nodes[1].pubkey,
21012124
network.nodes[3].pubkey,
21022125
network.nodes[1].pubkey,
21032126
network.nodes[1].pubkey,
21042127
network.nodes[3].pubkey,
21052128
network.nodes[1].pubkey,
2106-
network.nodes[1].pubkey,
21072129
network.nodes[3].pubkey,
21082130
network.nodes[3].pubkey,
21092131
network.nodes[3].pubkey,
@@ -2121,57 +2143,47 @@ mod tests {
21212143

21222144
assert!(
21232145
payments_list.lock().unwrap().as_ref() == expected_payment_list,
2124-
"The expected order of payments is not correct"
2146+
"The expected order of payments is not correct: {:?} vs {:?}",
2147+
payments_list.lock().unwrap(),
2148+
expected_payment_list,
21252149
);
21262150
}
21272151

2128-
#[tokio::test]
2152+
// Run on a paused runtime so that the payment interval sleeps auto-advance rather than
2153+
// consuming real time; elapsed time is measured against the simulation's virtual clock.
2154+
#[tokio::test(start_paused = true)]
21292155
async fn test_deterministic_payments_events_random() {
2130-
let pk1 = PublicKey::from_str(
2131-
"02f6dc1fcf3431f461ff5e6d870f286e134b064fddd3795a98d5903c55e76cfa8c",
2132-
)
2133-
.unwrap();
2134-
let pk2 = PublicKey::from_str(
2135-
"0363a5321c2778e2f13f4d7602a84e866824551b4bd31fdfc66e044a274863d647",
2136-
)
2137-
.unwrap();
2138-
let pk3 = PublicKey::from_str(
2139-
"037b0c8a943a6bc3ebb5b56ed1c377a1d3e6b68e9231ad9bf7afd45ba37374f7a3",
2140-
)
2141-
.unwrap();
2142-
let pk4 = PublicKey::from_str(
2143-
"026389dd21b3611bf4bb78f8939d5912f3175107ff9c14b6881bb4bef0e7c6e905",
2144-
)
2145-
.unwrap();
2156+
let pks = fixed_test_pubkeys();
2157+
let (pk1, pk2, pk3, pk4) = (pks[0], pks[1], pks[2], pks[3]);
21462158

21472159
let (network, payments_list) =
2148-
setup_test_nodes_for_testing_deterministic_events(Some(vec![pk1, pk2, pk3, pk4])).await;
2160+
setup_test_nodes_for_testing_deterministic_events(Some(pks)).await;
21492161

21502162
let (shutdown_trigger, shutdown_listener) = triggered::trigger();
21512163

2164+
let clock = Arc::new(SimulationClock::new(SystemTime::now()));
2165+
21522166
// Create simulation with a defined seed.
21532167
let simulation = Simulation::new(
21542168
SimulationCfg::new(Some(25), 100, 2.0, None, Some(42)),
21552169
network.get_client_hashmap(),
21562170
TaskTracker::new(),
2157-
Arc::new(SimulationClock::new(SystemTime::now())),
2171+
clock.clone(),
21582172
shutdown_trigger,
21592173
shutdown_listener,
21602174
);
21612175

21622176
// Run the simulation
2163-
let start = std::time::Instant::now();
2177+
let start = clock.now();
21642178
let _ = simulation.run(&[]).await;
2165-
let elapsed = start.elapsed();
2179+
let elapsed = clock.now().duration_since(start).unwrap();
21662180

21672181
assert!(
21682182
elapsed >= Duration::from_secs(25),
21692183
"Simulation should have run at least for 25s, took {:?}",
21702184
elapsed
21712185
);
2172-
let expected_payment_list = vec![
2173-
pk1, pk2, pk1, pk1, pk1, pk3, pk3, pk3, pk4, pk3, pk2, pk1, pk4,
2174-
];
2186+
let expected_payment_list = vec![pk1, pk1, pk2, pk2, pk4, pk2, pk2, pk2, pk3, pk3];
21752187

21762188
assert!(
21772189
payments_list.lock().unwrap().as_ref() == expected_payment_list,

0 commit comments

Comments
 (0)