Skip to content

Commit 662c789

Browse files
committed
Add shared interop test scenarios
- Add scenario modules: channel, payment, disconnect, splice - Add expect_event! macro with 60s timeout and retry_until_ok helper - Add setup_interop_test to fund/connect LDK + external node with block sync via ExternalNode::wait_for_block_sync()
1 parent 6a516d6 commit 662c789

File tree

6 files changed

+1098
-9
lines changed

6 files changed

+1098
-9
lines changed

tests/common/mod.rs

Lines changed: 152 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,24 @@ use rand::distr::Alphanumeric;
5555
use rand::{rng, Rng};
5656
use serde_json::{json, Value};
5757

58+
/// Shared timeout (in seconds) for waiting on LDK events and external node operations.
59+
pub(crate) const INTEROP_TIMEOUT_SECS: u64 = 60;
60+
5861
macro_rules! expect_event {
5962
($node:expr, $event_type:ident) => {{
60-
match $node.next_event_async().await {
63+
let event = tokio::time::timeout(
64+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
65+
$node.next_event_async(),
66+
)
67+
.await
68+
.unwrap_or_else(|_| {
69+
panic!(
70+
"{} timed out waiting for {} event after 60s",
71+
$node.node_id(),
72+
std::stringify!($event_type)
73+
)
74+
});
75+
match event {
6176
ref e @ Event::$event_type { .. } => {
6277
println!("{} got event {:?}", $node.node_id(), e);
6378
$node.event_handled().unwrap();
@@ -73,7 +88,15 @@ pub(crate) use expect_event;
7388

7489
macro_rules! expect_channel_pending_event {
7590
($node:expr, $counterparty_node_id:expr) => {{
76-
match $node.next_event_async().await {
91+
let event = tokio::time::timeout(
92+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
93+
$node.next_event_async(),
94+
)
95+
.await
96+
.unwrap_or_else(|_| {
97+
panic!("{} timed out waiting for ChannelPending event after 60s", $node.node_id())
98+
});
99+
match event {
77100
ref e @ Event::ChannelPending { funding_txo, counterparty_node_id, .. } => {
78101
println!("{} got event {:?}", $node.node_id(), e);
79102
assert_eq!(counterparty_node_id, $counterparty_node_id);
@@ -91,7 +114,15 @@ pub(crate) use expect_channel_pending_event;
91114

92115
macro_rules! expect_channel_ready_event {
93116
($node:expr, $counterparty_node_id:expr) => {{
94-
match $node.next_event_async().await {
117+
let event = tokio::time::timeout(
118+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
119+
$node.next_event_async(),
120+
)
121+
.await
122+
.unwrap_or_else(|_| {
123+
panic!("{} timed out waiting for ChannelReady event after 60s", $node.node_id())
124+
});
125+
match event {
95126
ref e @ Event::ChannelReady { user_channel_id, counterparty_node_id, .. } => {
96127
println!("{} got event {:?}", $node.node_id(), e);
97128
assert_eq!(counterparty_node_id, Some($counterparty_node_id));
@@ -111,7 +142,15 @@ macro_rules! expect_channel_ready_events {
111142
($node:expr, $counterparty_node_id_a:expr, $counterparty_node_id_b:expr) => {{
112143
let mut ids = Vec::new();
113144
for _ in 0..2 {
114-
match $node.next_event_async().await {
145+
let event = tokio::time::timeout(
146+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
147+
$node.next_event_async(),
148+
)
149+
.await
150+
.unwrap_or_else(|_| {
151+
panic!("{} timed out waiting for ChannelReady event after 60s", $node.node_id())
152+
});
153+
match event {
115154
ref e @ Event::ChannelReady { counterparty_node_id, .. } => {
116155
println!("{} got event {:?}", $node.node_id(), e);
117156
ids.push(counterparty_node_id);
@@ -137,7 +176,15 @@ pub(crate) use expect_channel_ready_events;
137176

138177
macro_rules! expect_splice_pending_event {
139178
($node:expr, $counterparty_node_id:expr) => {{
140-
match $node.next_event_async().await {
179+
let event = tokio::time::timeout(
180+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
181+
$node.next_event_async(),
182+
)
183+
.await
184+
.unwrap_or_else(|_| {
185+
panic!("{} timed out waiting for SplicePending event after 60s", $node.node_id())
186+
});
187+
match event {
141188
ref e @ Event::SplicePending { new_funding_txo, counterparty_node_id, .. } => {
142189
println!("{} got event {:?}", $node.node_id(), e);
143190
assert_eq!(counterparty_node_id, $counterparty_node_id);
@@ -155,7 +202,15 @@ pub(crate) use expect_splice_pending_event;
155202

156203
macro_rules! expect_payment_received_event {
157204
($node:expr, $amount_msat:expr) => {{
158-
match $node.next_event_async().await {
205+
let event = tokio::time::timeout(
206+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
207+
$node.next_event_async(),
208+
)
209+
.await
210+
.unwrap_or_else(|_| {
211+
panic!("{} timed out waiting for PaymentReceived event after 60s", $node.node_id())
212+
});
213+
match event {
159214
ref e @ Event::PaymentReceived { payment_id, amount_msat, .. } => {
160215
println!("{} got event {:?}", $node.node_id(), e);
161216
assert_eq!(amount_msat, $amount_msat);
@@ -167,7 +222,7 @@ macro_rules! expect_payment_received_event {
167222
payment_id
168223
},
169224
ref e => {
170-
panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e);
225+
panic!("{} got unexpected event!: {:?}", std::stringify!($node), e);
171226
},
172227
}
173228
}};
@@ -177,7 +232,18 @@ pub(crate) use expect_payment_received_event;
177232

178233
macro_rules! expect_payment_claimable_event {
179234
($node:expr, $payment_id:expr, $payment_hash:expr, $claimable_amount_msat:expr) => {{
180-
match $node.next_event_async().await {
235+
let event = tokio::time::timeout(
236+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
237+
$node.next_event_async(),
238+
)
239+
.await
240+
.unwrap_or_else(|_| {
241+
panic!(
242+
"{} timed out waiting for PaymentClaimable event after 60s",
243+
std::stringify!($node)
244+
)
245+
});
246+
match event {
181247
ref e @ Event::PaymentClaimable {
182248
payment_id,
183249
payment_hash,
@@ -202,7 +268,15 @@ pub(crate) use expect_payment_claimable_event;
202268

203269
macro_rules! expect_payment_successful_event {
204270
($node:expr, $payment_id:expr, $fee_paid_msat:expr) => {{
205-
match $node.next_event_async().await {
271+
let event = tokio::time::timeout(
272+
std::time::Duration::from_secs(crate::common::INTEROP_TIMEOUT_SECS),
273+
$node.next_event_async(),
274+
)
275+
.await
276+
.unwrap_or_else(|_| {
277+
panic!("{} timed out waiting for PaymentSuccessful event after 60s", $node.node_id())
278+
});
279+
match event {
206280
ref e @ Event::PaymentSuccessful { payment_id, fee_paid_msat, .. } => {
207281
println!("{} got event {:?}", $node.node_id(), e);
208282
if let Some(fee_msat) = $fee_paid_msat {
@@ -390,6 +464,9 @@ macro_rules! setup_builder {
390464

391465
pub(crate) use setup_builder;
392466

467+
#[cfg(any(cln_test, lnd_test, eclair_test))]
468+
pub(crate) mod scenarios;
469+
393470
pub(crate) fn setup_two_nodes(
394471
chain_source: &TestChainSource, allow_0conf: bool, anchor_channels: bool,
395472
anchors_trusted_no_reserve: bool,
@@ -1699,3 +1776,69 @@ impl TestSyncStoreInner {
16991776
self.do_list(primary_namespace, secondary_namespace)
17001777
}
17011778
}
1779+
1780+
/// Generates individual `#[tokio::test]` functions for every combination of
1781+
/// (Phase, disconnect Side, CloseType, close Side).
1782+
///
1783+
/// PayType is fixed to Bolt11 — keysend vs bolt11 doesn't affect close
1784+
/// behavior and is already covered by dedicated named tests.
1785+
///
1786+
/// Usage (inside each `integration_tests_*.rs`):
1787+
/// ```ignore
1788+
/// interop_combo_tests!(test_lnd, setup_clients, setup_ldk_node);
1789+
/// ```
1790+
#[macro_export]
1791+
macro_rules! interop_combo_tests {
1792+
($prefix:ident, $setup_clients:ident, $setup_ldk_node:ident) => {
1793+
$crate::interop_combo_tests!(
1794+
@phase $prefix, $setup_clients, $setup_ldk_node,
1795+
[payment, Phase::Payment], [idle, Phase::Idle]
1796+
);
1797+
};
1798+
1799+
(@phase $prefix:ident, $sc:ident, $sn:ident, $([$pn:ident, $pv:expr]),+) => {
1800+
$(
1801+
$crate::interop_combo_tests!(
1802+
@disc $prefix, $sc, $sn, $pn, $pv,
1803+
[ldk, Side::Ldk], [ext, Side::External]
1804+
);
1805+
)+
1806+
};
1807+
1808+
(@disc $prefix:ident, $sc:ident, $sn:ident, $pn:ident, $pv:expr, $([$dn:ident, $dv:expr]),+) => {
1809+
$(
1810+
$crate::interop_combo_tests!(
1811+
@close $prefix, $sc, $sn, $pn, $pv, $dn, $dv,
1812+
[coop, CloseType::Cooperative], [force, CloseType::Force]
1813+
);
1814+
)+
1815+
};
1816+
1817+
(@close $prefix:ident, $sc:ident, $sn:ident, $pn:ident, $pv:expr, $dn:ident, $dv:expr,
1818+
$([$cn:ident, $cv:expr]),+) => {
1819+
$(
1820+
$crate::interop_combo_tests!(
1821+
@ci $prefix, $sc, $sn, $pn, $pv, $dn, $dv, $cn, $cv,
1822+
[ldk, Side::Ldk], [ext, Side::External]
1823+
);
1824+
)+
1825+
};
1826+
1827+
(@ci $prefix:ident, $sc:ident, $sn:ident, $pn:ident, $pv:expr, $dn:ident, $dv:expr,
1828+
$cn:ident, $cv:expr, $([$cin:ident, $civ:expr]),+) => {
1829+
$(
1830+
paste::paste! {
1831+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
1832+
async fn [<$prefix _combo_ $pn _ $dn _ $cn _ $cin>]() {
1833+
let (bitcoind, electrs, peer) = $sc().await;
1834+
let node = $sn();
1835+
run_interop_property_test(
1836+
&node, &peer, &bitcoind, &electrs,
1837+
$pv, $dv, $cv, $civ, PayType::Bolt11,
1838+
).await;
1839+
node.stop().unwrap();
1840+
}
1841+
}
1842+
)+
1843+
};
1844+
}

0 commit comments

Comments
 (0)