Skip to content

Commit e1e9867

Browse files
committed
Add shared interop test scenarios
- Add scenario modules: channel, payment, disconnect, splice - Add wait_for_external_node_block_height helper to ensure external nodes have synced before asserting channel state - Add expect_event! macro with 60-second timeout to prevent hangs - Add retry_until_ok helper for operations with gossip delay - Add setup_interop_test to fund and connect LDK + external node - Use electrum chain source for LDK nodes
1 parent 43006e2 commit e1e9867

9 files changed

Lines changed: 1281 additions & 12 deletions

File tree

tests/common/mod.rs

Lines changed: 154 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,17 @@ use serde_json::{json, Value};
5757

5858
macro_rules! expect_event {
5959
($node:expr, $event_type:ident) => {{
60-
match $node.next_event_async().await {
60+
let event =
61+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
62+
.await
63+
.unwrap_or_else(|_| {
64+
panic!(
65+
"{} timed out waiting for {} event after 60s",
66+
$node.node_id(),
67+
std::stringify!($event_type)
68+
)
69+
});
70+
match event {
6171
ref e @ Event::$event_type { .. } => {
6272
println!("{} got event {:?}", $node.node_id(), e);
6373
$node.event_handled().unwrap();
@@ -73,7 +83,16 @@ pub(crate) use expect_event;
7383

7484
macro_rules! expect_channel_pending_event {
7585
($node:expr, $counterparty_node_id:expr) => {{
76-
match $node.next_event_async().await {
86+
let event =
87+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
88+
.await
89+
.unwrap_or_else(|_| {
90+
panic!(
91+
"{} timed out waiting for ChannelPending event after 60s",
92+
$node.node_id()
93+
)
94+
});
95+
match event {
7796
ref e @ Event::ChannelPending { funding_txo, counterparty_node_id, .. } => {
7897
println!("{} got event {:?}", $node.node_id(), e);
7998
assert_eq!(counterparty_node_id, $counterparty_node_id);
@@ -91,7 +110,13 @@ pub(crate) use expect_channel_pending_event;
91110

92111
macro_rules! expect_channel_ready_event {
93112
($node:expr, $counterparty_node_id:expr) => {{
94-
match $node.next_event_async().await {
113+
let event =
114+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
115+
.await
116+
.unwrap_or_else(|_| {
117+
panic!("{} timed out waiting for ChannelReady event after 60s", $node.node_id())
118+
});
119+
match event {
95120
ref e @ Event::ChannelReady { user_channel_id, counterparty_node_id, .. } => {
96121
println!("{} got event {:?}", $node.node_id(), e);
97122
assert_eq!(counterparty_node_id, Some($counterparty_node_id));
@@ -111,7 +136,16 @@ macro_rules! expect_channel_ready_events {
111136
($node:expr, $counterparty_node_id_a:expr, $counterparty_node_id_b:expr) => {{
112137
let mut ids = Vec::new();
113138
for _ in 0..2 {
114-
match $node.next_event_async().await {
139+
let event =
140+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
141+
.await
142+
.unwrap_or_else(|_| {
143+
panic!(
144+
"{} timed out waiting for ChannelReady event after 60s",
145+
$node.node_id()
146+
)
147+
});
148+
match event {
115149
ref e @ Event::ChannelReady { counterparty_node_id, .. } => {
116150
println!("{} got event {:?}", $node.node_id(), e);
117151
ids.push(counterparty_node_id);
@@ -137,7 +171,16 @@ pub(crate) use expect_channel_ready_events;
137171

138172
macro_rules! expect_splice_pending_event {
139173
($node:expr, $counterparty_node_id:expr) => {{
140-
match $node.next_event_async().await {
174+
let event =
175+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
176+
.await
177+
.unwrap_or_else(|_| {
178+
panic!(
179+
"{} timed out waiting for SplicePending event after 60s",
180+
$node.node_id()
181+
)
182+
});
183+
match event {
141184
ref e @ Event::SplicePending { new_funding_txo, counterparty_node_id, .. } => {
142185
println!("{} got event {:?}", $node.node_id(), e);
143186
assert_eq!(counterparty_node_id, $counterparty_node_id);
@@ -155,7 +198,16 @@ pub(crate) use expect_splice_pending_event;
155198

156199
macro_rules! expect_payment_received_event {
157200
($node:expr, $amount_msat:expr) => {{
158-
match $node.next_event_async().await {
201+
let event =
202+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
203+
.await
204+
.unwrap_or_else(|_| {
205+
panic!(
206+
"{} timed out waiting for PaymentReceived event after 60s",
207+
$node.node_id()
208+
)
209+
});
210+
match event {
159211
ref e @ Event::PaymentReceived { payment_id, amount_msat, .. } => {
160212
println!("{} got event {:?}", $node.node_id(), e);
161213
assert_eq!(amount_msat, $amount_msat);
@@ -177,7 +229,16 @@ pub(crate) use expect_payment_received_event;
177229

178230
macro_rules! expect_payment_claimable_event {
179231
($node:expr, $payment_id:expr, $payment_hash:expr, $claimable_amount_msat:expr) => {{
180-
match $node.next_event_async().await {
232+
let event =
233+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
234+
.await
235+
.unwrap_or_else(|_| {
236+
panic!(
237+
"{} timed out waiting for PaymentClaimable event after 60s",
238+
std::stringify!($node)
239+
)
240+
});
241+
match event {
181242
ref e @ Event::PaymentClaimable {
182243
payment_id,
183244
payment_hash,
@@ -202,7 +263,16 @@ pub(crate) use expect_payment_claimable_event;
202263

203264
macro_rules! expect_payment_successful_event {
204265
($node:expr, $payment_id:expr, $fee_paid_msat:expr) => {{
205-
match $node.next_event_async().await {
266+
let event =
267+
tokio::time::timeout(std::time::Duration::from_secs(60), $node.next_event_async())
268+
.await
269+
.unwrap_or_else(|_| {
270+
panic!(
271+
"{} timed out waiting for PaymentSuccessful event after 60s",
272+
$node.node_id()
273+
)
274+
});
275+
match event {
206276
ref e @ Event::PaymentSuccessful { payment_id, fee_paid_msat, .. } => {
207277
println!("{} got event {:?}", $node.node_id(), e);
208278
if let Some(fee_msat) = $fee_paid_msat {
@@ -390,6 +460,9 @@ macro_rules! setup_builder {
390460

391461
pub(crate) use setup_builder;
392462

463+
#[cfg(any(cln_test, lnd_test, eclair_test))]
464+
pub(crate) mod scenarios;
465+
393466
pub(crate) fn setup_two_nodes(
394467
chain_source: &TestChainSource, allow_0conf: bool, anchor_channels: bool,
395468
anchors_trusted_no_reserve: bool,
@@ -1699,3 +1772,76 @@ impl TestSyncStoreInner {
16991772
self.do_list(primary_namespace, secondary_namespace)
17001773
}
17011774
}
1775+
1776+
/// Generates individual `#[tokio::test]` functions for every combination of
1777+
/// (Phase, disconnect Side, CloseType, close Side, PayType).
1778+
///
1779+
/// Usage (inside each `integration_tests_*.rs`):
1780+
/// ```ignore
1781+
/// interop_combo_tests!(test_lnd, setup_clients, setup_ldk_node);
1782+
/// ```
1783+
#[macro_export]
1784+
macro_rules! interop_combo_tests {
1785+
($prefix:ident, $setup_clients:ident, $setup_ldk_node:ident) => {
1786+
$crate::interop_combo_tests!(
1787+
@phase $prefix, $setup_clients, $setup_ldk_node,
1788+
[payment, Phase::Payment], [idle, Phase::Idle]
1789+
);
1790+
};
1791+
1792+
(@phase $prefix:ident, $sc:ident, $sn:ident, $([$pn:ident, $pv:expr]),+) => {
1793+
$(
1794+
$crate::interop_combo_tests!(
1795+
@disc $prefix, $sc, $sn, $pn, $pv,
1796+
[ldk, Side::Ldk], [ext, Side::External]
1797+
);
1798+
)+
1799+
};
1800+
1801+
(@disc $prefix:ident, $sc:ident, $sn:ident, $pn:ident, $pv:expr, $([$dn:ident, $dv:expr]),+) => {
1802+
$(
1803+
$crate::interop_combo_tests!(
1804+
@close $prefix, $sc, $sn, $pn, $pv, $dn, $dv,
1805+
[coop, CloseType::Cooperative], [force, CloseType::Force]
1806+
);
1807+
)+
1808+
};
1809+
1810+
(@close $prefix:ident, $sc:ident, $sn:ident, $pn:ident, $pv:expr, $dn:ident, $dv:expr,
1811+
$([$cn:ident, $cv:expr]),+) => {
1812+
$(
1813+
$crate::interop_combo_tests!(
1814+
@ci $prefix, $sc, $sn, $pn, $pv, $dn, $dv, $cn, $cv,
1815+
[ldk, Side::Ldk], [ext, Side::External]
1816+
);
1817+
)+
1818+
};
1819+
1820+
(@ci $prefix:ident, $sc:ident, $sn:ident, $pn:ident, $pv:expr, $dn:ident, $dv:expr,
1821+
$cn:ident, $cv:expr, $([$cin:ident, $civ:expr]),+) => {
1822+
$(
1823+
$crate::interop_combo_tests!(
1824+
@pay $prefix, $sc, $sn, $pn, $pv, $dn, $dv, $cn, $cv, $cin, $civ,
1825+
[bolt11, PayType::Bolt11], [keysend, PayType::Keysend]
1826+
);
1827+
)+
1828+
};
1829+
1830+
(@pay $prefix:ident, $sc:ident, $sn:ident, $pn:ident, $pv:expr, $dn:ident, $dv:expr,
1831+
$cn:ident, $cv:expr, $cin:ident, $civ:expr, $([$payn:ident, $payv:expr]),+) => {
1832+
$(
1833+
paste::paste! {
1834+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
1835+
async fn [<$prefix _combo_ $pn _ $dn _ $cn _ $cin _ $payn>]() {
1836+
let (bitcoind, electrs, peer) = $sc().await;
1837+
let node = $sn();
1838+
run_interop_property_test(
1839+
&node, &peer, &bitcoind, &electrs,
1840+
$pv, $dv, $cv, $civ, $payv,
1841+
).await;
1842+
node.stop().unwrap();
1843+
}
1844+
}
1845+
)+
1846+
};
1847+
}

0 commit comments

Comments
 (0)