use asx::__fuzz::ErrorCode;
use asx::__mapping::{backend, map, partner_ebms, partner_mdn};
use asx::ErrorKind;
#[track_caller]
fn assert_row(stage: &str, codes: &[ErrorCode], kind: ErrorKind, retryable: bool) {
for code in codes {
let err = map(stage, *code).unwrap_or_else(|| panic!("unknown stage {stage:?}"));
assert_eq!(err.kind(), kind, "{stage} / {code:?}: {err}");
assert_eq!(
err.is_retryable(),
retryable,
"{stage} / {code:?}: is_retryable"
);
}
}
#[test]
fn unknown_stage_is_none() {
assert!(map("no-such-stage", ErrorCode::InvalidInput).is_none());
}
#[test]
fn build_and_send_validate_is_config() {
assert_row(
"config",
&[
ErrorCode::InvalidInput,
ErrorCode::PolicyViolation,
ErrorCode::InteropViolation,
ErrorCode::PayloadTooLarge,
ErrorCode::NotFound,
ErrorCode::CertificateExpired,
ErrorCode::CertificateRevoked,
],
ErrorKind::Config,
false,
);
}
#[test]
fn embedder_backend_failure_is_backend() {
let err = backend();
assert_eq!(err.kind(), ErrorKind::Backend);
assert!(err.is_retryable());
}
#[test]
fn capacity_exhausted_is_transport() {
for stage in ["config", "http_not_written", "http_after_write", "inbound"] {
assert_row(
stage,
&[ErrorCode::CapacityExhausted],
ErrorKind::Transport,
true,
);
}
}
#[test]
fn http_not_written_is_transport() {
assert_row(
"http_not_written",
&[ErrorCode::TransportFailure],
ErrorKind::Transport,
true,
);
}
#[test]
fn address_pin_refusal_is_not_retryable() {
for code in [ErrorCode::PolicyViolation, ErrorCode::InvalidInput] {
let err = map("http_not_written", code).expect("stage");
assert!(!err.is_retryable(), "{code:?}: {err}");
}
}
#[test]
fn address_pin_refusal_kind() {
let err = map("http_not_written", ErrorCode::PolicyViolation).expect("stage");
assert_eq!(err.kind(), ErrorKind::Transport, "{err}");
}
#[test]
fn http_after_write_is_indeterminate() {
assert_row(
"http_after_write",
&[ErrorCode::Timeout, ErrorCode::TransportFailure],
ErrorKind::Indeterminate,
true,
);
}
#[test]
fn partner_ebms_error() {
let err = partner_ebms("EBMS:0202");
assert_eq!(err.kind(), ErrorKind::PartnerError);
assert_eq!(err.ebms_code(), Some("EBMS:0202"));
assert!(err.is_retryable());
for code in ["EBMS:0004", "EBMS:0101", "EBMS:0102", "EBMS:0303"] {
let err = partner_ebms(code);
assert_eq!(err.kind(), ErrorKind::PartnerError);
assert_eq!(err.ebms_code(), Some(code));
assert!(!err.is_retryable(), "{code}");
}
}
#[test]
fn partner_negative_mdn() {
let retry = "processed/error: unexpected-processing-error";
let err = partner_mdn(retry);
assert_eq!(err.kind(), ErrorKind::PartnerError);
assert_eq!(err.mdn_disposition(), Some(retry));
assert!(err.is_retryable());
for disposition in [
"processed/error: decryption-failed",
"processed/error: authentication-failed",
"failed/failure: unsupported format",
] {
let err = partner_mdn(disposition);
assert_eq!(err.kind(), ErrorKind::PartnerError);
assert_eq!(err.mdn_disposition(), Some(disposition));
assert!(!err.is_retryable(), "{disposition}");
}
}
const VERIFY_CODES: &[ErrorCode] = &[
ErrorCode::SecurityVerificationFailed,
ErrorCode::ParseFailed,
ErrorCode::InteropViolation,
ErrorCode::DecryptionFailed,
];
#[test]
fn response_verification_failure_is_indeterminate() {
assert_row(
"response_verify",
VERIFY_CODES,
ErrorKind::Indeterminate,
true,
);
}
#[test]
fn async_mdn_mismatch_is_rejected() {
assert_row(
"async_mdn_match",
&[ErrorCode::ParseFailed, ErrorCode::InvalidInput],
ErrorKind::Rejected,
false,
);
}
#[test]
fn async_mdn_verification_failure_is_indeterminate() {
assert_row(
"response_verify",
VERIFY_CODES,
ErrorKind::Indeterminate,
true,
);
}
#[test]
fn smp_untrusted_is_rejected() {
assert_row(
"smp_lookup",
&[
ErrorCode::SecurityVerificationFailed,
ErrorCode::InteropViolation,
],
ErrorKind::Rejected,
false,
);
}
#[test]
fn smp_network_failure_is_transport() {
assert_row(
"smp_lookup",
&[ErrorCode::TransportFailure, ErrorCode::Timeout],
ErrorKind::Transport,
true,
);
}
#[test]
fn smp_not_registered_is_config() {
assert_row(
"smp_lookup",
&[ErrorCode::NotFound],
ErrorKind::Config,
false,
);
}
#[test]
fn key_material_parse_failure_is_config() {
assert_row(
"config",
&[ErrorCode::ParseFailed, ErrorCode::InvalidInput],
ErrorKind::Config,
false,
);
#[cfg(any(feature = "as2", feature = "as4"))]
{
let err = asx::Certificate::from_pem(b"not a certificate").expect_err("garbage");
assert_eq!(err.kind(), ErrorKind::Config);
assert!(!err.is_retryable());
let err = asx::KeyPair::from_pem(b"not a chain", b"not a key").expect_err("garbage");
assert_eq!(err.kind(), ErrorKind::Config);
assert!(!err.is_retryable());
}
}
#[test]
fn inbound_refusal_is_rejected() {
assert_row(
"inbound",
&[
ErrorCode::SecurityVerificationFailed,
ErrorCode::DecryptionFailed,
ErrorCode::ParseFailed,
],
ErrorKind::Rejected,
false,
);
}