Skip to content

Commit

Permalink
Add PartialFailure test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
jurvis committed Aug 21, 2022
1 parent c389dce commit e8e05fd
Showing 1 changed file with 104 additions and 3 deletions.
107 changes: 104 additions & 3 deletions lightning-invoice/src/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ mod tests {
use std::time::{SystemTime, Duration};
use time_utils::tests::SinceEpoch;
use DEFAULT_EXPIRY_TIME;
use lightning::util::errors::APIError::{ChannelUnavailable, MonitorUpdateFailed};
use lightning::util::errors::APIError::{APIMisuseError, ChannelUnavailable, FeeRateTooHigh, MonitorUpdateFailed, RouteError};

fn invoice(payment_preimage: PaymentPreimage) -> Invoice {
let payment_hash = Sha256::hash(&payment_preimage.0);
Expand Down Expand Up @@ -958,8 +958,8 @@ mod tests {
let final_value_msat = invoice.amount_milli_satoshis().unwrap();

let payer = TestPayer::new()
.fails_with_partial_failure(retry.clone(), OnAttempt(1))
.fails_with_partial_failure(retry, OnAttempt(2))
.fails_with_partial_failure(retry.clone(), OnAttempt(1), None)
.fails_with_partial_failure(retry, OnAttempt(2), None)
.expect_send(Amount::ForInvoice(final_value_msat))
.expect_send(Amount::OnRetry(final_value_msat / 2))
.expect_send(Amount::OnRetry(final_value_msat / 2));
Expand Down Expand Up @@ -1641,6 +1641,107 @@ mod tests {
invoice_payer.pay_invoice(&payment_invoice_2).unwrap();
}

// This following partial failure tests are variants of `inflight_map_data_trivial_test` above,
// except with partial failure errors.
#[test]
fn test_partial_failure_inflight_map() {
let event_handled = core::cell::RefCell::new(false);
let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };

let payment_preimage = PaymentPreimage([1; 32]);
let invoice_to_pay = invoice(payment_preimage);
let payment_hash = Some(PaymentHash(invoice_to_pay.payment_hash().clone().into_inner()));
let final_value_msat = invoice_to_pay.amount_milli_satoshis().unwrap();

let retry = TestRouter::retry_for_invoice(&invoice_to_pay);
let payer = TestPayer::new()
.fails_with_partial_failure(retry.clone(), OnAttempt(1),
Some(vec![
Err(ChannelUnavailable { err: "abc".to_string() }),
Err(MonitorUpdateFailed)
]))
.expect_send(Amount::ForInvoice(final_value_msat));

let final_value_msat = invoice_to_pay.amount_milli_satoshis().unwrap();
let route = TestRouter::route_for_value(final_value_msat);
let router = TestRouter {};
let scorer = RefCell::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));

invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
let inflight_map = invoice_payer.create_inflight_map();

// Only the second path, that failed with `MonitorUpdateFailed` should be added to our
// inflight map.
assert_eq!(inflight_map.len(), 1);
}

#[test]
fn test_partial_failure_inflight_map_2() {
let event_handled = core::cell::RefCell::new(false);
let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };

let payment_preimage = PaymentPreimage([1; 32]);
let invoice_to_pay = invoice(payment_preimage);
let payment_hash = Some(PaymentHash(invoice_to_pay.payment_hash().clone().into_inner()));
let final_value_msat = invoice_to_pay.amount_milli_satoshis().unwrap();

let retry = TestRouter::retry_for_invoice(&invoice_to_pay);
let payer = TestPayer::new()
.fails_with_partial_failure(retry.clone(), OnAttempt(1),
Some(vec![
Err(ChannelUnavailable { err: "abc".to_string() }),
Err(RouteError { err: "abc" })
]))
.expect_send(Amount::ForInvoice(final_value_msat));

let final_value_msat = invoice_to_pay.amount_milli_satoshis().unwrap();
let route = TestRouter::route_for_value(final_value_msat);
let router = TestRouter {};
let scorer = RefCell::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));

invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
let inflight_map = invoice_payer.create_inflight_map();
assert_eq!(inflight_map.len(), 0);
}

#[test]
fn test_partial_failure_inflight_map_3() {
let event_handled = core::cell::RefCell::new(false);
let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };

let payment_preimage = PaymentPreimage([1; 32]);
let invoice_to_pay = invoice(payment_preimage);
let payment_hash = Some(PaymentHash(invoice_to_pay.payment_hash().clone().into_inner()));
let final_value_msat = invoice_to_pay.amount_milli_satoshis().unwrap();

let retry = TestRouter::retry_for_invoice(&invoice_to_pay);
let payer = TestPayer::new()
.fails_with_partial_failure(retry.clone(), OnAttempt(1),
Some(vec![
Err(FeeRateTooHigh { err: "abc".to_string(), feerate: 0 }),
Err(APIMisuseError { err: "abc".to_string() })
]))
.expect_send(Amount::ForInvoice(final_value_msat));

let final_value_msat = invoice_to_pay.amount_milli_satoshis().unwrap();
let route = TestRouter::route_for_value(final_value_msat);
let router = TestRouter {};
let scorer = RefCell::new(TestScorer::new());
let logger = TestLogger::new();
let invoice_payer =
InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));

invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
let inflight_map = invoice_payer.create_inflight_map();
assert_eq!(inflight_map.len(), 0);
}

struct TestRouter;

impl TestRouter {
Expand Down

0 comments on commit e8e05fd

Please sign in to comment.