Skip to content

Commit a412ecd

Browse files
committed
Log Rust test progress in CI
Enable CI to show Rust integration test logs by running 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 a412ecd

3 files changed

Lines changed: 100 additions & 4 deletions

File tree

.github/workflows/tests.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ jobs:
1616
name: Rust Checks
1717
runs-on: self-hosted
1818
timeout-minutes: 120
19+
env:
20+
RUST_BACKTRACE: 1
21+
RUST_LOG: orange_sdk=debug,graduated_rebalancer=debug,ldk_node=info,integration_tests=info,test_utils=info
1922
steps:
2023
- uses: actions/checkout@v4
2124
- uses: dtolnay/rust-toolchain@stable
@@ -40,7 +43,7 @@ jobs:
4043
run: cargo check -p orange-cli
4144

4245
- name: Run tests
43-
run: cargo test --features _test-utils -- --test-threads=2
46+
run: cargo test --features _test-utils -- --test-threads=2 --nocapture
4447

4548
cashu_tests:
4649
name: Cashu Tests

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)