Skip to content

Commit 124178e

Browse files
committed
Log Rust test progress in CI
Enable CI to show Rust integration test logs by running both Rust test jobs with nocapture and setting RUST_LOG for the SDK, rebalancer, LDK node, and test harness targets. Mark the integration tests with the existing test-log attribute and add progress breadcrumbs around shared setup, polling waits, test execution, and cleanup. This should make future stalls show the phase and test location that stopped making progress.
1 parent df2bb05 commit 124178e

3 files changed

Lines changed: 102 additions & 5 deletions

File tree

.github/workflows/tests.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ concurrency:
1111
group: ${{ github.workflow }}-${{ github.ref }}
1212
cancel-in-progress: true
1313

14+
env:
15+
RUST_BACKTRACE: 1
16+
RUST_LOG: orange_sdk=debug,graduated_rebalancer=debug,ldk_node=info,integration_tests=info,test_utils=info
17+
1418
jobs:
1519
rust_tests:
1620
name: Rust Checks
@@ -40,7 +44,7 @@ jobs:
4044
run: cargo check -p orange-cli
4145

4246
- name: Run tests
43-
run: cargo test --features _test-utils -- --test-threads=2
47+
run: cargo test --features _test-utils -- --test-threads=2 --nocapture
4448

4549
cashu_tests:
4650
name: Cashu Tests
@@ -59,4 +63,4 @@ jobs:
5963
- uses: Swatinem/rust-cache@v2.7.8
6064

6165
- name: Run cashu tests
62-
run: cargo test --features _cashu-tests -- --test-threads=2
66+
run: cargo test --features _cashu-tests -- --test-threads=2 --nocapture

orange-sdk/tests/integration_tests.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::time::Duration;
1616
mod test_utils;
1717

1818
#[tokio::test(flavor = "multi_thread")]
19+
#[test_log::test]
1920
async fn test_node_start() {
2021
test_utils::run_test(|params| async move {
2122
let bal = params.wallet.get_balance().await.unwrap();
@@ -84,6 +85,7 @@ async fn test_receive_to_trusted() {
8485
}
8586

8687
#[tokio::test(flavor = "multi_thread")]
88+
#[test_log::test]
8789
async fn test_pay_from_trusted() {
8890
test_utils::run_test(|params| async move {
8991
let wallet = Arc::clone(&params.wallet);
@@ -168,6 +170,7 @@ async fn test_pay_from_trusted() {
168170
}
169171

170172
#[tokio::test(flavor = "multi_thread")]
173+
#[test_log::test]
171174
async fn test_sweep_to_ln() {
172175
test_utils::run_test(|params| async move {
173176
let wallet = Arc::clone(&params.wallet);
@@ -327,6 +330,7 @@ async fn test_sweep_to_ln() {
327330
}
328331

329332
#[tokio::test(flavor = "multi_thread")]
333+
#[test_log::test]
330334
async fn test_receive_to_ln() {
331335
test_utils::run_test(|params| async move {
332336
let wallet = Arc::clone(&params.wallet);
@@ -694,6 +698,7 @@ async fn run_test_pay_lightning_from_self_custody(amountless: bool) {
694698
}
695699

696700
#[tokio::test(flavor = "multi_thread")]
701+
#[test_log::test]
697702
async fn test_pay_lightning_from_self_custody() {
698703
run_test_pay_lightning_from_self_custody(false).await;
699704
run_test_pay_lightning_from_self_custody(true).await;
@@ -788,12 +793,14 @@ async fn run_test_pay_bolt12_from_self_custody(amountless: bool) {
788793
}
789794

790795
#[tokio::test(flavor = "multi_thread")]
796+
#[test_log::test]
791797
async fn test_pay_bolt12_from_self_custody() {
792798
run_test_pay_bolt12_from_self_custody(false).await;
793799
run_test_pay_bolt12_from_self_custody(true).await;
794800
}
795801

796802
#[tokio::test(flavor = "multi_thread")]
803+
#[test_log::test]
797804
async fn test_pay_onchain_from_self_custody() {
798805
test_utils::run_test(|params| async move {
799806
let wallet = Arc::clone(&params.wallet);
@@ -1009,6 +1016,7 @@ async fn test_pay_onchain_from_channel() {
10091016
}
10101017

10111018
#[tokio::test(flavor = "multi_thread")]
1019+
#[test_log::test]
10121020
async fn test_force_close_handling() {
10131021
test_utils::run_test(|params| async move {
10141022
let wallet = Arc::clone(&params.wallet);
@@ -1058,6 +1066,7 @@ async fn test_force_close_handling() {
10581066
}
10591067

10601068
#[tokio::test(flavor = "multi_thread")]
1069+
#[test_log::test]
10611070
async fn test_close_all_channels() {
10621071
test_utils::run_test(|params| async move {
10631072
let wallet = Arc::clone(&params.wallet);
@@ -1099,6 +1108,7 @@ async fn test_close_all_channels() {
10991108
}
11001109

11011110
#[tokio::test(flavor = "multi_thread")]
1111+
#[test_log::test]
11021112
async fn test_threshold_boundary_trusted_balance_limit() {
11031113
test_utils::run_test(|params| async move {
11041114
let wallet = Arc::clone(&params.wallet);
@@ -1182,6 +1192,7 @@ async fn test_threshold_boundary_trusted_balance_limit() {
11821192
}
11831193

11841194
#[tokio::test(flavor = "multi_thread")]
1195+
#[test_log::test]
11851196
async fn test_threshold_boundary_rebalance_min() {
11861197
test_utils::run_test(|params| async move {
11871198
let wallet = Arc::clone(&params.wallet);
@@ -1260,6 +1271,7 @@ async fn test_threshold_boundary_rebalance_min() {
12601271
}
12611272

12621273
#[tokio::test(flavor = "multi_thread")]
1274+
#[test_log::test]
12631275
async fn test_threshold_boundary_onchain_receive_threshold() {
12641276
test_utils::run_test(|params| async move {
12651277
let wallet = Arc::clone(&params.wallet);
@@ -1329,6 +1341,7 @@ async fn test_threshold_boundary_onchain_receive_threshold() {
13291341
}
13301342

13311343
#[tokio::test(flavor = "multi_thread")]
1344+
#[test_log::test]
13321345
async fn test_threshold_combinations_and_edge_cases() {
13331346
test_utils::run_test(|params| async move {
13341347
let wallet = Arc::clone(&params.wallet);
@@ -1393,6 +1406,7 @@ async fn test_threshold_combinations_and_edge_cases() {
13931406
}
13941407

13951408
#[tokio::test(flavor = "multi_thread")]
1409+
#[test_log::test]
13961410
async fn test_invalid_payment_instructions() {
13971411
test_utils::run_test(|params| async move {
13981412
let wallet = Arc::clone(&params.wallet);
@@ -1459,6 +1473,7 @@ async fn test_invalid_payment_instructions() {
14591473
}
14601474

14611475
#[tokio::test(flavor = "multi_thread")]
1476+
#[test_log::test]
14621477
async fn test_payment_with_expired_invoice() {
14631478
test_utils::run_test(|params| async move {
14641479
let wallet = Arc::clone(&params.wallet);
@@ -1492,6 +1507,7 @@ async fn test_payment_with_expired_invoice() {
14921507
}
14931508

14941509
#[tokio::test(flavor = "multi_thread")]
1510+
#[test_log::test]
14951511
async fn test_payment_network_mismatch() {
14961512
test_utils::run_test(|params| async move {
14971513
let wallet = Arc::clone(&params.wallet);
@@ -1554,6 +1570,7 @@ async fn test_payment_network_mismatch() {
15541570
}
15551571

15561572
#[tokio::test(flavor = "multi_thread")]
1573+
#[test_log::test]
15571574
async fn test_concurrent_payments() {
15581575
test_utils::run_test(|params| async move {
15591576
let wallet = Arc::clone(&params.wallet);
@@ -1750,6 +1767,7 @@ async fn test_concurrent_payments() {
17501767
}
17511768

17521769
#[tokio::test(flavor = "multi_thread")]
1770+
#[test_log::test]
17531771
async fn test_concurrent_receive_operations() {
17541772
test_utils::run_test(|params| async move {
17551773
let wallet = Arc::clone(&params.wallet);
@@ -1809,6 +1827,7 @@ async fn test_concurrent_receive_operations() {
18091827
}
18101828

18111829
#[tokio::test(flavor = "multi_thread")]
1830+
#[test_log::test]
18121831
async fn test_balance_consistency_under_load() {
18131832
test_utils::run_test(|params| async move {
18141833
let wallet = Arc::clone(&params.wallet);
@@ -1864,6 +1883,7 @@ async fn test_balance_consistency_under_load() {
18641883
}
18651884

18661885
#[tokio::test(flavor = "multi_thread")]
1886+
#[test_log::test]
18671887
async fn test_invalid_tunables_relationships() {
18681888
test_utils::run_test(|params| async move {
18691889
let wallet = Arc::clone(&params.wallet);
@@ -1956,6 +1976,7 @@ async fn test_invalid_tunables_relationships() {
19561976
}
19571977

19581978
#[tokio::test(flavor = "multi_thread")]
1979+
#[test_log::test]
19591980
async fn test_extreme_amount_handling() {
19601981
test_utils::run_test(|params| async move {
19611982
let wallet = Arc::clone(&params.wallet);
@@ -2027,6 +2048,7 @@ async fn test_extreme_amount_handling() {
20272048
}
20282049

20292050
#[tokio::test(flavor = "multi_thread")]
2051+
#[test_log::test]
20302052
async fn test_wallet_configuration_validation() {
20312053
test_utils::run_test(|params| async move {
20322054
let wallet = Arc::clone(&params.wallet);
@@ -2093,6 +2115,7 @@ async fn test_wallet_configuration_validation() {
20932115
}
20942116

20952117
#[tokio::test(flavor = "multi_thread")]
2118+
#[test_log::test]
20962119
async fn test_edge_case_payment_instruction_parsing() {
20972120
test_utils::run_test(|params| async move {
20982121
let wallet = Arc::clone(&params.wallet);
@@ -2149,6 +2172,7 @@ async fn test_edge_case_payment_instruction_parsing() {
21492172
}
21502173

21512174
#[tokio::test(flavor = "multi_thread")]
2175+
#[test_log::test]
21522176
async fn test_lsp_connectivity_fallback() {
21532177
test_utils::run_test(|params| async move {
21542178
let wallet = Arc::clone(&params.wallet);

orange-sdk/tests/test_utils.rs

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@ where
4545
};
4646
let start = tokio::time::Instant::now();
4747
let mut delay = Duration::from_millis(50);
48+
log::info!("waiting for condition: {condition_name}");
4849
loop {
4950
if condition().await {
51+
log::info!("condition met: {condition_name} after {:?}", start.elapsed());
5052
return;
5153
}
5254
if start.elapsed() >= timeout {
55+
log::warn!("condition timed out: {condition_name} after {:?}", start.elapsed());
5356
panic!("Timeout waiting for condition: {condition_name}");
5457
}
5558
tokio::time::sleep(delay).await;
@@ -312,14 +315,63 @@ pub(crate) async fn stop_ldk_node(name: &'static str, node: Arc<Node>) {
312315
/// Runs a test with automatically managed TestParams lifecycle.
313316
/// The test closure receives TestParams and must return it when done.
314317
/// Cleanup happens automatically after the test completes.
315-
pub async fn run_test<F, Fut>(test: F)
318+
#[track_caller]
319+
pub fn run_test<F, Fut>(test: F) -> impl Future<Output = ()>
316320
where
317321
F: FnOnce(TestParams) -> Fut + Send + 'static,
318322
Fut: Future<Output = ()> + Send + 'static,
319323
{
324+
let caller = std::panic::Location::caller();
325+
let test_name = format!("{}:{}", caller.file(), caller.line());
326+
327+
async move { run_test_with_name(test_name, test).await }
328+
}
329+
330+
async fn run_test_with_name<F, Fut>(test_name: String, test: F)
331+
where
332+
F: FnOnce(TestParams) -> Fut + Send + 'static,
333+
Fut: Future<Output = ()> + Send + 'static,
334+
{
335+
let lifecycle_timeout = if std::env::var("CI").is_ok() {
336+
Duration::from_secs(20 * 60)
337+
} else {
338+
Duration::from_secs(10 * 60)
339+
};
340+
341+
log::info!("spawning test lifecycle for {test_name}");
342+
343+
let (sender, receiver) = tokio::sync::oneshot::channel();
344+
let lifecycle_name = test_name.clone();
345+
std::thread::spawn(move || {
346+
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
347+
let runtime = tokio::runtime::Builder::new_multi_thread()
348+
.enable_all()
349+
.build()
350+
.expect("failed to create test runtime");
351+
runtime.block_on(run_test_inner(lifecycle_name, test));
352+
}));
353+
let _ = sender.send(result);
354+
});
355+
356+
match tokio::time::timeout(lifecycle_timeout, receiver).await {
357+
Ok(Ok(Ok(()))) => {},
358+
Ok(Ok(Err(panic))) => std::panic::resume_unwind(panic),
359+
Ok(Err(_)) => panic!("test lifecycle thread exited without a result"),
360+
Err(_) => panic!("test lifecycle timed out after {lifecycle_timeout:?} for {test_name}"),
361+
}
362+
}
363+
364+
async fn run_test_inner<F, Fut>(test_name: String, test: F)
365+
where
366+
F: FnOnce(TestParams) -> Fut + Send + 'static,
367+
Fut: Future<Output = ()> + Send + 'static,
368+
{
369+
log::info!("test lifecycle started for {test_name}");
370+
log::info!("building test nodes for {test_name}");
320371
let params = build_test_nodes().await;
321372

322-
println!("=== test start ===");
373+
log::info!("test body starting for {test_name}");
374+
println!("=== test start: {test_name} ===");
323375

324376
let test_timeout = if std::env::var("CI").is_ok() {
325377
Duration::from_secs(15 * 60)
@@ -334,6 +386,7 @@ where
334386
let test_result = tokio::select! {
335387
res = &mut test_task => Ok(res),
336388
_ = tokio::time::sleep(test_timeout) => {
389+
log::warn!("test body timed out for {test_name} after {test_timeout:?}");
337390
test_task.abort();
338391
let _ = tokio::time::timeout(Duration::from_secs(5), &mut test_task).await;
339392
Err(())
@@ -342,9 +395,12 @@ where
342395

343396
// Always clean up
344397
let timeout = Duration::from_secs(45);
398+
log::info!("test cleanup starting for {test_name}");
345399
if tokio::time::timeout(timeout, params.stop()).await.is_err() {
400+
log::warn!("test cleanup timed out for {test_name} after {timeout:?}");
346401
eprintln!("Warning: params stop timed out after {timeout:?}");
347402
}
403+
log::info!("test cleanup finished for {test_name}");
348404

349405
match test_result {
350406
Ok(Ok(())) => {},
@@ -356,11 +412,14 @@ where
356412

357413
async fn build_test_nodes() -> TestParams {
358414
let test_id = Uuid::now_v7();
415+
log::info!("creating bitcoind and electrsd for {test_id}");
359416
let (bitcoind, electrsd) = create_bitcoind(test_id).await;
360417

418+
log::info!("creating LSP and third-party nodes for {test_id}");
361419
let lsp = create_lsp(test_id, &bitcoind);
362420
let third_party = create_third_party(test_id, &bitcoind);
363421
let start_bal = third_party.list_balances().total_onchain_balance_sats;
422+
log::info!("funding LSP and third-party nodes for {test_id}");
364423
fund_two_nodes(&lsp, &third_party, &bitcoind, &electrsd).await;
365424

366425
// wait for node to sync (needs blocking wait as we are not in async context here)
@@ -374,6 +433,7 @@ async fn build_test_nodes() -> TestParams {
374433
let lsp_listen = lsp.listening_addresses().unwrap().first().unwrap().clone();
375434

376435
// open a channel from payer to LSP
436+
log::info!("opening third-party channel to LSP for {test_id}");
377437
third_party.open_channel(lsp.node_id(), lsp_listen.clone(), 10_000_000, None, None).unwrap();
378438
wait_for_tx_broadcast(&bitcoind).await;
379439
generate_blocks(&bitcoind, &electrsd, 6).await;
@@ -395,6 +455,7 @@ async fn build_test_nodes() -> TestParams {
395455

396456
#[cfg(not(feature = "_cashu-tests"))]
397457
let wallet = {
458+
log::info!("creating dummy trusted wallet for {test_id}");
398459
let dummy_wallet_config = DummyTrustedWalletExtraConfig {
399460
uuid: test_id,
400461
lsp: Arc::clone(&lsp),
@@ -427,6 +488,7 @@ async fn build_test_nodes() -> TestParams {
427488
#[cfg(feature = "_cashu-tests")]
428489
{
429490
let tmp = temp_dir().join(format!("orange-test-{test_id}/cashu-ldk-node"));
491+
log::info!("creating Cashu trusted wallet fixtures for {test_id}");
430492
let cookie = bitcoind.params.get_cookie_values().unwrap().unwrap();
431493
let bitcoind_port = bitcoind.params.rpc_socket.port();
432494
let cdk_port = {
@@ -569,11 +631,15 @@ async fn build_test_nodes() -> TestParams {
569631
};
570632
let wallet = Arc::new(Wallet::new(wallet_config).await.unwrap());
571633

634+
log::info!("finished building test nodes for {test_id}");
572635
return TestParams { wallet, lsp, third_party, bitcoind, electrsd, _mint: mint };
573636
};
574637

575638
#[cfg(not(feature = "_cashu-tests"))]
576-
TestParams { wallet, lsp, third_party, bitcoind, electrsd }
639+
{
640+
log::info!("finished building test nodes for {test_id}");
641+
TestParams { wallet, lsp, third_party, bitcoind, electrsd }
642+
}
577643
}
578644

579645
pub async fn open_channel_from_lsp(wallet: &orange_sdk::Wallet, payer: Arc<Node>) -> Amount {
@@ -626,12 +692,15 @@ async fn wait_for_tx_broadcast(bitcoind: &Bitcoind) {
626692
};
627693
let start = tokio::time::Instant::now();
628694
let mut delay = Duration::from_millis(50);
695+
log::info!("waiting for tx broadcast");
629696
loop {
630697
let num_txs = bitcoind.client.get_mempool_info().unwrap().size;
631698
if num_txs > 0 {
699+
log::info!("tx broadcast observed after {:?}", start.elapsed());
632700
break;
633701
}
634702
if start.elapsed() >= timeout {
703+
log::warn!("tx broadcast timed out after {:?}", start.elapsed());
635704
panic!("Timeout waiting for tx broadcast");
636705
}
637706
tokio::time::sleep(delay).await;

0 commit comments

Comments
 (0)