debugbundle 1.0.0-alpha.1

Safe, bounded runtime error reporting for Rust, Axum and Actix Web
Documentation
use debugbundle::protocol::{acknowledgement, retry_after};
use serde_json::json;
use std::time::{Duration, SystemTime};

#[test]
fn partial_acknowledgements_reconcile_each_index_once() {
    let result=acknowledgement(&json!({"accepted":1,"rejected":2,"errors":[{"index":1,"reason":"rate_limited"},{"index":2,"reason":"invalid_event"}]}),3).unwrap();
    assert_eq!(result.accepted, vec![0]);
    assert_eq!(result.retry, vec![1]);
    assert_eq!(result.terminal, vec![2]);
    for reason in ["monthly_quota_exceeded", "analytics_quota_exceeded"] {
        assert_eq!(
            acknowledgement(
                &json!({"accepted":0,"rejected":1,"errors":[{"index":0,"reason":reason}]}),
                1
            )
            .unwrap()
            .retry,
            vec![0]
        );
    }
}

#[test]
fn json_mathematical_integers_share_the_receiving_contract() {
    let body = serde_json::from_str(
        r#"{"accepted":1.0,"rejected":1e0,"errors":[{"index":1.0,"reason":"rate_limited"}]}"#,
    )
    .unwrap();
    let ack = acknowledgement(&body, 2).unwrap();
    assert_eq!(ack.accepted, vec![0]);
    assert_eq!(ack.retry, vec![1]);
    for accepted in ["0.5", "-1.0", "1e10000"] {
        let body: serde_json::Value = serde_json::from_str(&format!(
            r#"{{"accepted":{accepted},"rejected":0,"errors":[]}}"#
        ))
        .unwrap();
        assert!(acknowledgement(&body, 1).is_none());
    }
}

#[test]
fn malformed_acknowledgements_cannot_release_ownership() {
    for value in [
        json!({}),
        json!({"accepted":1,"rejected":0}),
        json!({"accepted":1,"rejected":1,"errors":[]}),
        json!({"accepted":-1,"rejected":2,"errors":[]}),
        json!({"accepted":18446744073709551615u64,"rejected":1,"errors":[]}),
        json!({"accepted":0,"rejected":1,"errors":[{"index":1,"reason":"rate_limited"}]}),
        json!({"accepted":0,"rejected":1,"errors":[{"index":0,"reason":" "}]}),
        json!({"accepted":0,"rejected":2,"errors":[{"index":0,"reason":"x"},{"index":0,"reason":"x"}]}),
    ] {
        assert!(acknowledgement(&value, 1).is_none(), "{value}");
    }
}

#[test]
fn retry_hints_are_capped_before_deadline_arithmetic() {
    let now = SystemTime::UNIX_EPOCH + Duration::from_secs(1000000);
    assert_eq!(
        retry_after("1844674407370955161500000000000", now),
        Some(Duration::from_secs(300))
    );
    assert_eq!(retry_after("7", now), Some(Duration::from_secs(7)));
    assert_eq!(
        retry_after(
            &httpdate::fmt_http_date(now + Duration::from_secs(301)),
            now
        ),
        Some(Duration::from_secs(300))
    );
    assert_eq!(
        retry_after(&httpdate::fmt_http_date(now - Duration::from_secs(1)), now),
        Some(Duration::ZERO)
    );
    for value in ["-1", "NaN", "infinity", "", "3.5"] {
        assert!(retry_after(value, now).is_none());
    }
}