Skip to content

Commit 7fa8d0f

Browse files
committed
Extract shared setup helpers in Python binding tests
Duplicated node setup, funding, channel opening, and teardown logic made integration tests harder to read and maintain. Hard-coded ports also risked collisions when tests run in parallel. Introduce reusable helpers for two-node setup, funding, channel ready waiting, and cleanup. Bind ephemeral ports to avoid conflicts, and refactor test_channel_full_cycle to use them without changing test behavior.
1 parent 8dd06bf commit 7fa8d0f

1 file changed

Lines changed: 68 additions & 51 deletions

File tree

bindings/python/src/ldk_node/test_ldk_node.py

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import re
77
import requests
8+
import socket
89

910
from ldk_node import *
1011

@@ -118,8 +119,68 @@ def expect_event(node, expected_event_type):
118119
assert isinstance(event, expected_event_type)
119120
print("EVENT:", event)
120121
node.event_handled()
121-
return event
122-
122+
return event
123+
124+
def find_two_free_ports():
125+
with socket.socket() as s1, socket.socket() as s2:
126+
s1.bind(("127.0.0.1", 0))
127+
s2.bind(("127.0.0.1",0))
128+
port_1 = s1.getsockname()[1]
129+
port_2 = s2.getsockname()[1]
130+
return port_1, port_2
131+
132+
def setup_two_nodes(esplora_endpoint):
133+
port_1, port_2 = find_two_free_ports()
134+
tmp_dir_1 = tempfile.TemporaryDirectory("_ldk_node_1")
135+
listening_addresses_1 = [f"127.0.0.1:{port_1}"]
136+
node_1 = setup_node(tmp_dir_1.name, esplora_endpoint, listening_addresses_1)
137+
node_1.start()
138+
node_id_1 = node_1.node_id()
139+
140+
tmp_dir_2 = tempfile.TemporaryDirectory("_ldk_node_2")
141+
listening_addresses_2 = [f"127.0.0.1:{port_2}"]
142+
node_2 = setup_node(tmp_dir_2.name, esplora_endpoint, listening_addresses_2)
143+
node_2.start()
144+
node_id_2 = node_2.node_id()
145+
146+
return node_1, node_2, tmp_dir_1, tmp_dir_2, node_id_1, node_id_2, listening_addresses_2
147+
148+
def fund_nodes(node_1, node_2, esplora_endpoint, amount_sats=100000):
149+
address_1 = node_1.onchain_payment().new_address()
150+
txid_1 = send_to_address(address_1, amount_sats)
151+
address_2 = node_2.onchain_payment().new_address()
152+
txid_2 = send_to_address(address_2, amount_sats)
153+
154+
wait_for_tx(esplora_endpoint, txid_1)
155+
wait_for_tx(esplora_endpoint, txid_2)
156+
mine_and_wait(esplora_endpoint, 6)
157+
158+
node_1.sync_wallets()
159+
node_2.sync_wallets()
160+
161+
def open_channel_and_wait_ready(node_1, node_2, node_id_2, listening_address_2, esplora_endpoint, channel_amount_sats=50000):
162+
node_1.open_channel(node_id_2, listening_address_2, channel_amount_sats, None, None)
163+
164+
channel_pending_event_1 = expect_event(node_1, Event.CHANNEL_PENDING)
165+
expect_event(node_2, Event.CHANNEL_PENDING)
166+
167+
funding_txid = channel_pending_event_1.funding_txo.txid
168+
wait_for_tx(esplora_endpoint, funding_txid)
169+
mine_and_wait(esplora_endpoint, 6)
170+
171+
node_1.sync_wallets()
172+
node_2.sync_wallets()
173+
174+
channel_ready_event_1 = expect_event(node_1, Event.CHANNEL_READY)
175+
channel_ready_event_2 = expect_event(node_2, Event.CHANNEL_READY)
176+
return channel_ready_event_1, channel_ready_event_2, funding_txid
177+
178+
def stop_and_cleanup(node_1, node_2, tmp_dir_1, tmp_dir_2):
179+
node_1.stop()
180+
node_2.stop()
181+
time.sleep(1)
182+
tmp_dir_1.cleanup()
183+
tmp_dir_2.cleanup()
123184

124185
def assert_feature_helpers_return_bool(test_case, features):
125186
feature_methods = [
@@ -156,42 +217,17 @@ def setUp(self):
156217
def test_channel_full_cycle(self):
157218
esplora_endpoint = get_esplora_endpoint()
158219

159-
## Setup Node 1
160-
tmp_dir_1 = tempfile.TemporaryDirectory("_ldk_node_1")
161-
print("TMP DIR 1:", tmp_dir_1.name)
162-
163-
listening_addresses_1 = ["127.0.0.1:2323"]
164-
node_1 = setup_node(tmp_dir_1.name, esplora_endpoint, listening_addresses_1)
165-
node_1.start()
166-
node_id_1 = node_1.node_id()
220+
## Setup two nodes
221+
node_1, node_2, tmp_dir_1, tmp_dir_2, node_id_1, node_id_2, listening_addresses_2 = setup_two_nodes(esplora_endpoint)
167222
print("Node ID 1:", node_id_1)
168-
169-
# Setup Node 2
170-
tmp_dir_2 = tempfile.TemporaryDirectory("_ldk_node_2")
171-
print("TMP DIR 2:", tmp_dir_2.name)
172-
173-
listening_addresses_2 = ["127.0.0.1:2324"]
174-
node_2 = setup_node(tmp_dir_2.name, esplora_endpoint, listening_addresses_2)
175-
node_2.start()
176-
node_id_2 = node_2.node_id()
177223
print("Node ID 2:", node_id_2)
178224

179225
# Check node-announcement features exposed through NodeStatus.
180226
for node in [node_1, node_2]:
181227
node_features_exposed(self, node.status().node_features)
182228

183-
address_1 = node_1.onchain_payment().new_address()
184-
txid_1 = send_to_address(address_1, 100000)
185-
address_2 = node_2.onchain_payment().new_address()
186-
txid_2 = send_to_address(address_2, 100000)
229+
fund_nodes(node_1, node_2, esplora_endpoint)
187230

188-
wait_for_tx(esplora_endpoint, txid_1)
189-
wait_for_tx(esplora_endpoint, txid_2)
190-
191-
mine_and_wait(esplora_endpoint, 6)
192-
193-
node_1.sync_wallets()
194-
node_2.sync_wallets()
195231

196232
spendable_balance_1 = node_1.list_balances().spendable_onchain_balance_sats
197233
spendable_balance_2 = node_2.list_balances().spendable_onchain_balance_sats
@@ -210,22 +246,9 @@ def test_channel_full_cycle(self):
210246
print("TOTAL 2:", total_balance_2)
211247
self.assertEqual(total_balance_2, 100000)
212248

213-
node_1.open_channel(node_id_2, listening_addresses_2[0], 50000, None, None)
214-
215-
216-
channel_pending_event_1 = expect_event(node_1, Event.CHANNEL_PENDING)
217-
channel_pending_event_2 = expect_event(node_2, Event.CHANNEL_PENDING)
218-
funding_txid = channel_pending_event_1.funding_txo.txid
219-
wait_for_tx(esplora_endpoint, funding_txid)
220-
mine_and_wait(esplora_endpoint, 6)
221-
222-
node_1.sync_wallets()
223-
node_2.sync_wallets()
224-
225-
channel_ready_event_1 = expect_event(node_1, Event.CHANNEL_READY)
249+
channel_ready_event_1, channel_ready_event_2, funding_txid = open_channel_and_wait_ready(node_1, node_2, node_id_2, listening_addresses_2[0], esplora_endpoint)
226250
print("funding_txo:", funding_txid)
227251

228-
channel_ready_event_2 = expect_event(node_2, Event.CHANNEL_READY)
229252

230253
# Check negotiated init features exposed through ChannelDetails.
231254
for channel in [node_1.list_channels()[0], node_2.list_channels()[0]]:
@@ -259,13 +282,7 @@ def test_channel_full_cycle(self):
259282
self.assertEqual(spendable_balance_after_close_2, 102500)
260283

261284
# Stop nodes
262-
node_1.stop()
263-
node_2.stop()
264-
265-
# Cleanup
266-
time.sleep(1) # Wait a sec so our logs can finish writing
267-
tmp_dir_1.cleanup()
268-
tmp_dir_2.cleanup()
285+
stop_and_cleanup(node_1, node_2, tmp_dir_1, tmp_dir_2)
269286

270287
if __name__ == '__main__':
271288
unittest.main()

0 commit comments

Comments
 (0)