use crate::ExecutionResult;
use super::common::{MathContext, MathError, MathWithFlaky, MathWithFlakyInputs};
#[tokio::test]
async fn retry_succeeds_after_transient_failures() {
let saga = MathWithFlaky::new(MathWithFlakyInputs {
add: ("a".into(), 1, 1), flaky: "x".into(),
halt: (),
});
let mut ctx = MathContext::default();
ctx.fail_count = 2;
let exec = saga.build(ctx);
match exec.start().await {
ExecutionResult::Completed(e) => {
assert_eq!(e.context().r.get("a").copied(), Some(2));
assert_eq!(e.context().r.get("x").copied(), Some(1));
}
other => panic!(
"Expected Completed, got {:?}",
std::mem::discriminant(&other)
),
}
}
#[tokio::test]
async fn exceeding_retries_triggers_compensation() {
let saga = MathWithFlaky::new(MathWithFlakyInputs {
add: ("a".into(), 1, 1), flaky: "x".into(),
halt: (),
});
let mut ctx = MathContext::default();
ctx.fail_count = 5;
let exec = saga.build(ctx);
match exec.start().await {
ExecutionResult::Failed(e, err) => {
assert_eq!(err, MathError::Transient);
assert!(!e.context().r.contains_key("a"));
}
other => panic!("Expected Failed, got {:?}", std::mem::discriminant(&other)),
}
}
#[test]
fn retry_policy_configuration() {
use crate::RetryPolicy;
let no_retry = RetryPolicy::NoRetry;
assert!(!no_retry.should_retry(0));
assert!(!no_retry.should_retry(1));
assert_eq!(no_retry.backoff_ms(), 0);
let retry_3 = RetryPolicy::retries(3);
assert!(retry_3.should_retry(0));
assert!(retry_3.should_retry(1));
assert!(retry_3.should_retry(2));
assert!(!retry_3.should_retry(3));
assert!(!retry_3.should_retry(4));
let retry_with_backoff = RetryPolicy::retries_with_backoff(3, 100);
assert!(retry_with_backoff.should_retry(0));
assert_eq!(retry_with_backoff.backoff_ms(), 100);
}