Skip to content

Commit fe180dd

Browse files
committed
Refactor integration tests into shared scenario-based entry points
- Extract setup_clients() and setup_ldk_node() per implementation - Replace inline test logic with shared scenario function calls - Generate 16 combo tests per implementation via interop_combo_tests! macro
1 parent 662c789 commit fe180dd

File tree

4 files changed

+695
-281
lines changed

4 files changed

+695
-281
lines changed

tests/common/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8-
#![cfg(any(test, cln_test, lnd_test, vss_test))]
8+
#![cfg(any(test, cln_test, lnd_test, eclair_test, vss_test))]
99
#![allow(dead_code)]
1010

1111
pub(crate) mod external_node;

tests/integration_tests_cln.rs

Lines changed: 208 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -9,119 +9,234 @@
99

1010
mod common;
1111

12-
use std::default::Default;
1312
use std::str::FromStr;
1413

15-
use clightningrpc::lightningrpc::LightningRPC;
16-
use clightningrpc::responses::NetworkAddress;
14+
use common::cln::TestClnNode;
15+
use common::external_node::ExternalNode;
16+
use common::scenarios::channel::{
17+
open_channel_to_external, run_inbound_channel_test, test_cooperative_close_after_fee_change,
18+
test_cooperative_close_by_ldk, test_force_close_after_fee_change, test_force_close_by_external,
19+
test_force_close_by_ldk,
20+
};
21+
use common::scenarios::disconnect::test_disconnect_reconnect_idle;
22+
use common::scenarios::payment::{
23+
run_interop_property_test, test_bidirectional_payments, test_concurrent_payments,
24+
test_pay_expired_invoice, test_receive_bolt11_payment,
25+
};
26+
use common::scenarios::splice::{test_splice_from_external, test_splice_then_payment};
27+
use common::scenarios::{setup_interop_test, CloseType, PayType, Phase, Side};
1728
use electrsd::corepc_client::client_sync::Auth;
1829
use electrsd::corepc_node::Client as BitcoindClient;
1930
use electrum_client::Client as ElectrumClient;
20-
use ldk_node::bitcoin::secp256k1::PublicKey;
21-
use ldk_node::bitcoin::Amount;
22-
use ldk_node::lightning::ln::msgs::SocketAddress;
2331
use ldk_node::{Builder, Event};
24-
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description};
25-
use rand::distr::Alphanumeric;
26-
use rand::{rng, Rng};
2732

28-
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
29-
async fn test_cln() {
30-
// Setup bitcoind / electrs clients
31-
let bitcoind_client = BitcoindClient::new_with_auth(
33+
async fn setup_clients() -> (BitcoindClient, ElectrumClient, TestClnNode) {
34+
let bitcoind = BitcoindClient::new_with_auth(
3235
"http://127.0.0.1:18443",
3336
Auth::UserPass("user".to_string(), "pass".to_string()),
3437
)
3538
.unwrap();
36-
let electrs_client = ElectrumClient::new("tcp://127.0.0.1:50001").unwrap();
39+
let electrs = ElectrumClient::new("tcp://127.0.0.1:50001").unwrap();
3740

38-
// Give electrs a kick.
39-
common::generate_blocks_and_wait(&bitcoind_client, &electrs_client, 1).await;
41+
let cln = TestClnNode::from_env();
42+
(bitcoind, electrs, cln)
43+
}
4044

41-
// Setup LDK Node
45+
fn setup_ldk_node() -> ldk_node::Node {
4246
let config = common::random_config(true);
4347
let mut builder = Builder::from_config(config.node_config);
44-
builder.set_chain_source_esplora("http://127.0.0.1:3002".to_string(), None);
45-
48+
builder.set_chain_source_electrum("tcp://127.0.0.1:50001".to_string(), None);
4649
let node = builder.build(config.node_entropy).unwrap();
4750
node.start().unwrap();
51+
node
52+
}
53+
54+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
55+
async fn test_cln_basic_channel_cycle() {
56+
let (bitcoind, electrs, cln) = setup_clients().await;
57+
let node = setup_ldk_node();
58+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
59+
60+
let (user_channel_id, _ext_channel_id) =
61+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
62+
.await;
63+
64+
// LDK -> CLN payment
65+
let invoice = cln.create_invoice(10_000_000, "cln-test-send").await.unwrap();
66+
let parsed = lightning_invoice::Bolt11Invoice::from_str(&invoice).unwrap();
67+
node.bolt11_payment().send(&parsed, None).unwrap();
68+
common::expect_event!(node, PaymentSuccessful);
69+
70+
// CLN -> LDK payment
71+
test_receive_bolt11_payment(&node, &cln, 10_000_000).await;
72+
73+
test_cooperative_close_by_ldk(&node, &cln, &bitcoind, &electrs, &user_channel_id).await;
74+
node.stop().unwrap();
75+
}
76+
77+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
78+
async fn test_cln_disconnect_reconnect() {
79+
let (bitcoind, electrs, cln) = setup_clients().await;
80+
let node = setup_ldk_node();
81+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
82+
let (_user_ch, _ext_ch) =
83+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
84+
.await;
85+
86+
test_disconnect_reconnect_idle(&node, &cln, &bitcoind, &electrs, &Side::Ldk).await;
87+
test_disconnect_reconnect_idle(&node, &cln, &bitcoind, &electrs, &Side::External).await;
88+
89+
node.stop().unwrap();
90+
}
91+
92+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
93+
async fn test_cln_force_close_by_ldk() {
94+
let (bitcoind, electrs, cln) = setup_clients().await;
95+
let node = setup_ldk_node();
96+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
97+
let (user_ch, _ext_ch) =
98+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
99+
.await;
100+
101+
test_force_close_by_ldk(&node, &cln, &bitcoind, &electrs, &user_ch).await;
102+
node.stop().unwrap();
103+
}
104+
105+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
106+
async fn test_cln_force_close_by_external() {
107+
let (bitcoind, electrs, cln) = setup_clients().await;
108+
let node = setup_ldk_node();
109+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
110+
let (_user_ch, ext_ch) =
111+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
112+
.await;
113+
114+
test_force_close_by_external(&node, &cln, &bitcoind, &electrs, &ext_ch).await;
115+
node.stop().unwrap();
116+
}
117+
118+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
119+
async fn test_cln_splice() {
120+
let (bitcoind, electrs, cln) = setup_clients().await;
121+
let node = setup_ldk_node();
122+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
123+
let (_user_ch, ext_ch) =
124+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
125+
.await;
126+
127+
test_splice_from_external(&node, &cln, &bitcoind, &electrs, &ext_ch).await;
128+
129+
node.stop().unwrap();
130+
}
131+
132+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
133+
async fn test_cln_splice_then_payment() {
134+
let (bitcoind, electrs, cln) = setup_clients().await;
135+
let node = setup_ldk_node();
136+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
137+
let (_user_ch, ext_ch) =
138+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
139+
.await;
140+
141+
test_splice_then_payment(&node, &cln, &bitcoind, &electrs, &ext_ch).await;
142+
143+
node.stop().unwrap();
144+
}
48145

49-
// Premine some funds and distribute
50-
let address = node.onchain_payment().new_address().unwrap();
51-
let premine_amount = Amount::from_sat(5_000_000);
52-
common::premine_and_distribute_funds(
53-
&bitcoind_client,
54-
&electrs_client,
55-
vec![address],
56-
premine_amount,
146+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
147+
async fn test_cln_inbound_channel() {
148+
let (bitcoind, electrs, cln) = setup_clients().await;
149+
let node = setup_ldk_node();
150+
run_inbound_channel_test(
151+
&node,
152+
&cln,
153+
&bitcoind,
154+
&electrs,
155+
CloseType::Cooperative,
156+
Side::External,
57157
)
58158
.await;
159+
node.stop().unwrap();
160+
}
161+
162+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
163+
async fn test_cln_receive_payments() {
164+
let (bitcoind, electrs, cln) = setup_clients().await;
165+
let node = setup_ldk_node();
166+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
167+
let (_user_ch, _ext_ch) =
168+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
169+
.await;
170+
171+
test_receive_bolt11_payment(&node, &cln, 5_000_000).await;
172+
// TODO: CLN v24.08+ includes a `payment_secret` in outbound keysend payments.
173+
// LDK treats any inbound HTLC that carries a `payment_secret` as a BOLT 11 payment and
174+
// attempts to verify it against a stored invoice; since no invoice exists for a spontaneous
175+
// payment, it fails with WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS.
176+
// This is an LDK-side issue: when a valid `keysend_preimage` TLV is present,
177+
// `payment_secret` verification should be skipped.
178+
// Tracked upstream: CLN keysend interop issue (CLN includes payment_secret in keysend HTLCs)
179+
// test_receive_keysend_payment(&node, &cln, 5_000_000).await;
180+
181+
node.stop().unwrap();
182+
}
183+
184+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
185+
async fn test_cln_bidirectional_payments() {
186+
let (bitcoind, electrs, cln) = setup_clients().await;
187+
let node = setup_ldk_node();
188+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
189+
let (_user_ch, ext_ch) =
190+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
191+
.await;
192+
193+
test_bidirectional_payments(&node, &cln, &ext_ch, 5_000_000).await;
59194

60-
// Setup CLN
61-
let sock = "/tmp/lightning-rpc";
62-
let cln_client = LightningRPC::new(&sock);
63-
let cln_info = {
64-
loop {
65-
let info = cln_client.getinfo().unwrap();
66-
// Wait for CLN to sync block height before channel open.
67-
// Prevents crash due to unset blockheight (see LDK Node issue #527).
68-
if info.blockheight > 0 {
69-
break info;
70-
}
71-
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
72-
}
73-
};
74-
let cln_node_id = PublicKey::from_str(&cln_info.id).unwrap();
75-
let cln_address: SocketAddress = match cln_info.binding.first().unwrap() {
76-
NetworkAddress::Ipv4 { address, port } => {
77-
std::net::SocketAddrV4::new(*address, *port).into()
78-
},
79-
NetworkAddress::Ipv6 { address, port } => {
80-
std::net::SocketAddrV6::new(*address, *port, 0, 0).into()
81-
},
82-
_ => {
83-
panic!()
84-
},
85-
};
86-
87-
node.sync_wallets().unwrap();
88-
89-
// Open the channel
90-
let funding_amount_sat = 1_000_000;
91-
92-
node.open_channel(cln_node_id, cln_address, funding_amount_sat, Some(500_000_000), None)
93-
.unwrap();
94-
95-
let funding_txo = common::expect_channel_pending_event!(node, cln_node_id);
96-
common::wait_for_tx(&electrs_client, funding_txo.txid).await;
97-
common::generate_blocks_and_wait(&bitcoind_client, &electrs_client, 6).await;
98-
node.sync_wallets().unwrap();
99-
let user_channel_id = common::expect_channel_ready_event!(node, cln_node_id);
100-
101-
// Send a payment to CLN
102-
let mut rng = rng();
103-
let rand_label: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
104-
let cln_invoice =
105-
cln_client.invoice(Some(10_000_000), &rand_label, &rand_label, None, None, None).unwrap();
106-
let parsed_invoice = Bolt11Invoice::from_str(&cln_invoice.bolt11).unwrap();
107-
108-
node.bolt11_payment().send(&parsed_invoice, None).unwrap();
109-
common::expect_event!(node, PaymentSuccessful);
110-
let cln_listed_invoices =
111-
cln_client.listinvoices(Some(&rand_label), None, None, None).unwrap().invoices;
112-
assert_eq!(cln_listed_invoices.len(), 1);
113-
assert_eq!(cln_listed_invoices.first().unwrap().status, "paid");
114-
115-
// Send a payment to LDK
116-
let rand_label: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
117-
let invoice_description =
118-
Bolt11InvoiceDescription::Direct(Description::new(rand_label).unwrap());
119-
let ldk_invoice =
120-
node.bolt11_payment().receive(10_000_000, &invoice_description, 3600).unwrap();
121-
cln_client.pay(&ldk_invoice.to_string(), Default::default()).unwrap();
122-
common::expect_event!(node, PaymentReceived);
123-
124-
node.close_channel(&user_channel_id, cln_node_id).unwrap();
125-
common::expect_event!(node, ChannelClosed);
126195
node.stop().unwrap();
127196
}
197+
198+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
199+
async fn test_cln_pay_expired_invoice() {
200+
let (bitcoind, electrs, cln) = setup_clients().await;
201+
let node = setup_ldk_node();
202+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
203+
let (_user_ch, _ext_ch) =
204+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
205+
.await;
206+
207+
test_pay_expired_invoice(&node, &cln).await;
208+
209+
node.stop().unwrap();
210+
}
211+
212+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
213+
async fn test_cln_concurrent_payments() {
214+
let (bitcoind, electrs, cln) = setup_clients().await;
215+
let node = setup_ldk_node();
216+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
217+
let (_user_ch, _ext_ch) =
218+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
219+
.await;
220+
221+
test_concurrent_payments(&node, &cln, 5, 1_000_000).await;
222+
223+
node.stop().unwrap();
224+
}
225+
226+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
227+
async fn test_cln_cooperative_close_after_fee_change() {
228+
let (bitcoind, electrs, cln) = setup_clients().await;
229+
let node = setup_ldk_node();
230+
test_cooperative_close_after_fee_change(&node, &cln, &bitcoind, &electrs).await;
231+
node.stop().unwrap();
232+
}
233+
234+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
235+
async fn test_cln_force_close_after_fee_change() {
236+
let (bitcoind, electrs, cln) = setup_clients().await;
237+
let node = setup_ldk_node();
238+
test_force_close_after_fee_change(&node, &cln, &bitcoind, &electrs).await;
239+
node.stop().unwrap();
240+
}
241+
242+
interop_combo_tests!(test_cln, setup_clients, setup_ldk_node);

0 commit comments

Comments
 (0)