#![cfg(test)]
#![allow(dead_code)]
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct OtlpClassifierErrorFixture {
message: String,
status_code: u16,
retry_after: Option<Duration>,
retryable: bool,
}
impl OtlpClassifierErrorFixture {
fn retryable(status_code: u16, retry_after: Option<Duration>) -> Self {
Self {
message: format!("Retryable OTLP error: {}", status_code),
status_code,
retry_after,
retryable: true,
}
}
fn non_retryable(message: String) -> Self {
Self {
message,
status_code: 0, retry_after: None,
retryable: false,
}
}
fn is_retryable(&self) -> bool {
self.retryable
}
}
#[derive(Debug, Clone)]
pub struct ResponseFixture {
status: u16,
headers: Vec<(String, String)>,
}
impl ResponseFixture {
fn new(status: u16) -> Self {
Self {
status,
headers: vec![],
}
}
fn with_retry_after(mut self, seconds: u64) -> Self {
self.headers
.push(("Retry-After".to_string(), seconds.to_string()));
self
}
fn status(&self) -> u16 {
self.status
}
fn headers(&self) -> &Vec<(String, String)> {
&self.headers
}
}
fn classify_otlp_response_status(
response: &ResponseFixture,
) -> Result<(), OtlpClassifierErrorFixture> {
match response.status() {
200..=299 => Ok(()),
429 => {
let retry_after = response
.headers()
.iter()
.find(|(name, _)| name.eq_ignore_ascii_case("retry-after"))
.and_then(|(_, value)| value.parse::<u64>().ok())
.map(std::time::Duration::from_secs);
Err(OtlpClassifierErrorFixture::retryable(
response.status(),
retry_after,
))
}
502..=504 => {
Err(OtlpClassifierErrorFixture::retryable(
response.status(),
None,
))
}
400..=499 => {
Err(OtlpClassifierErrorFixture::non_retryable(format!(
"OTLP client error: {} - batch dropped",
response.status()
)))
}
500..=599 => {
Err(OtlpClassifierErrorFixture::non_retryable(format!(
"OTLP server error: {} - batch dropped",
response.status()
)))
}
_ => Err(OtlpClassifierErrorFixture::non_retryable(format!(
"Unexpected OTLP response status: {}",
response.status()
))),
}
}
#[test]
fn audit_otlp_retry_classifier_unexpected_4xx_codes() {
println!("🔍 AUDIT: OTLP retry classifier for unexpected 4xx status codes");
println!("📋 OTLP retry classifier specification:");
println!(" • 4xx codes (except 429) are TERMINAL - MUST NOT retry");
println!(" • 429 Rate Limited is RETRYABLE with optional Retry-After");
println!(" • NOT: retry 4xx client errors (violates HTTP semantics)");
println!(" • NOT: assume retry will succeed for client errors");
let unexpected_4xx_scenarios = vec![
(400, "Bad Request"),
(401, "Unauthorized"),
(403, "Forbidden"),
(404, "Not Found"),
(405, "Method Not Allowed"),
(408, "Request Timeout"),
(409, "Conflict"),
(410, "Gone"),
(413, "Payload Too Large"),
(414, "URI Too Long"),
(415, "Unsupported Media Type"),
(422, "Unprocessable Entity"),
(451, "Unavailable For Legal Reasons"), (499, "Client Closed Request"), ];
println!("📊 Testing unexpected 4xx status codes:");
let mut terminal_count = 0;
let mut retryable_count = 0;
for (status_code, description) in unexpected_4xx_scenarios {
println!(" Testing: HTTP {} - {}", status_code, description);
let response = ResponseFixture::new(status_code);
let result = classify_otlp_response_status(&response);
match result {
Ok(()) => {
println!(" ❌ UNEXPECTED: Treated as success");
panic!(
"4xx status {} should never be treated as success",
status_code
);
}
Err(otlp_error) => {
if otlp_error.is_retryable() {
println!(" ❌ SPEC VIOLATION: Classified as retryable");
retryable_count += 1;
} else {
println!(" ✅ SPEC COMPLIANT: Classified as terminal");
terminal_count += 1;
}
}
}
}
println!("📊 4xx status code classification results:");
println!(" Terminal (correct): {}", terminal_count);
println!(" Retryable (incorrect): {}", retryable_count);
assert_eq!(
retryable_count, 0,
"All 4xx codes (except 429) must be terminal per OTLP spec"
);
assert!(
terminal_count > 0,
"Should have tested at least one 4xx code"
);
println!("✅ OTLP UNEXPECTED 4XX AUDIT COMPLETE");
println!("🏆 FINDING: Current retry classifier is SPEC-COMPLIANT");
}
#[test]
fn audit_otlp_retry_classifier_429_special_case() {
println!("🔍 AUDIT: OTLP retry classifier 429 Rate Limited special case");
println!("📋 HTTP 429 Rate Limited requirements:");
println!(" • 429 is RETRYABLE (exception to 4xx terminal rule)");
println!(" • Retry-After header should be parsed if present");
println!(" • No Retry-After header is still retryable");
let response_no_header = ResponseFixture::new(429);
let result_no_header = classify_otlp_response_status(&response_no_header);
match result_no_header {
Ok(()) => {
println!("❌ UNEXPECTED: 429 treated as success");
panic!("429 Rate Limited should be retryable error, not success");
}
Err(otlp_error) => {
if otlp_error.is_retryable() {
println!("✅ CORRECT: 429 without Retry-After is retryable");
} else {
println!("❌ SPEC VIOLATION: 429 should be retryable");
panic!("429 Rate Limited must be retryable per OTLP spec");
}
}
}
let response_with_header = ResponseFixture::new(429).with_retry_after(60);
let result_with_header = classify_otlp_response_status(&response_with_header);
match result_with_header {
Ok(()) => {
println!("❌ UNEXPECTED: 429 with Retry-After treated as success");
panic!("429 Rate Limited should be retryable error, not success");
}
Err(otlp_error) => {
if otlp_error.is_retryable() {
println!("✅ CORRECT: 429 with Retry-After is retryable");
} else {
println!("❌ SPEC VIOLATION: 429 with Retry-After should be retryable");
panic!("429 Rate Limited with Retry-After must be retryable");
}
}
}
println!("✅ HTTP 429 SPECIAL CASE AUDIT COMPLETE");
println!("🏆 FINDING: 429 correctly treated as retryable exception");
}
#[test]
fn audit_otlp_retry_classifier_5xx_server_errors() {
println!("🔍 AUDIT: OTLP retry classifier 5xx server error handling");
println!("📋 OTLP 5xx server error classification:");
println!(" • 502 Bad Gateway: RETRYABLE (temporary proxy issue)");
println!(" • 503 Service Unavailable: RETRYABLE (temporary overload)");
println!(" • 504 Gateway Timeout: RETRYABLE (temporary timeout)");
println!(" • Other 5xx: NON-RETRYABLE (prevent cascade amplification)");
let server_error_scenarios = vec![
(500, "Internal Server Error", false), (501, "Not Implemented", false), (502, "Bad Gateway", true), (503, "Service Unavailable", true), (504, "Gateway Timeout", true), (505, "HTTP Version Not Supported", false), (507, "Insufficient Storage", false), (508, "Loop Detected", false), (511, "Network Authentication Required", false), (599, "Network Connect Timeout Error", false), ];
println!("📊 Testing 5xx server error classification:");
let mut correctly_classified = 0;
let mut incorrectly_classified = 0;
for (status_code, description, should_be_retryable) in server_error_scenarios {
println!(" Testing: HTTP {} - {}", status_code, description);
let response = ResponseFixture::new(status_code);
let result = classify_otlp_response_status(&response);
match result {
Ok(()) => {
println!(" ❌ UNEXPECTED: 5xx treated as success");
incorrectly_classified += 1;
}
Err(otlp_error) => {
let is_retryable = otlp_error.is_retryable();
if is_retryable == should_be_retryable {
println!(
" ✅ CORRECT: Classified as {}",
if is_retryable {
"retryable"
} else {
"terminal"
}
);
correctly_classified += 1;
} else {
println!(
" ❌ INCORRECT: Expected {}, got {}",
if should_be_retryable {
"retryable"
} else {
"terminal"
},
if is_retryable {
"retryable"
} else {
"terminal"
}
);
incorrectly_classified += 1;
}
}
}
}
println!("📊 5xx server error classification results:");
println!(" Correctly classified: {}", correctly_classified);
println!(" Incorrectly classified: {}", incorrectly_classified);
assert_eq!(
incorrectly_classified, 0,
"All 5xx codes should be classified per OTLP best practices"
);
println!("✅ 5XX SERVER ERROR AUDIT COMPLETE");
println!("🏆 FINDING: Conservative 5xx handling prevents cascade amplification");
}
#[test]
fn audit_otlp_retry_classifier_edge_case_status_codes() {
println!("🔍 AUDIT: OTLP retry classifier edge case status code handling");
println!("📋 Edge case status code requirements:");
println!(" • 1xx Informational: TERMINAL (unexpected for OTLP)");
println!(" • 3xx Redirection: TERMINAL (OTLP doesn't support redirects)");
println!(" • Invalid codes: TERMINAL (protocol violation)");
let edge_case_scenarios = vec![
(100, "Continue"),
(101, "Switching Protocols"),
(102, "Processing"),
(300, "Multiple Choices"),
(301, "Moved Permanently"),
(302, "Found"),
(304, "Not Modified"),
(307, "Temporary Redirect"),
(308, "Permanent Redirect"),
(0, "Invalid Status"), (999, "Custom Status"), ];
println!("📊 Testing edge case status codes:");
let mut terminal_count = 0;
let mut non_terminal_count = 0;
for (status_code, description) in edge_case_scenarios {
println!(" Testing: HTTP {} - {}", status_code, description);
let response = ResponseFixture::new(status_code);
let result = classify_otlp_response_status(&response);
match result {
Ok(()) => {
println!(" ❌ UNEXPECTED: Edge case treated as success");
non_terminal_count += 1;
}
Err(otlp_error) => {
if otlp_error.is_retryable() {
println!(" ❌ RISKY: Edge case classified as retryable");
non_terminal_count += 1;
} else {
println!(" ✅ SAFE: Edge case classified as terminal");
terminal_count += 1;
}
}
}
}
println!("📊 Edge case handling results:");
println!(" Terminal (safe): {}", terminal_count);
println!(" Non-terminal (risky): {}", non_terminal_count);
assert_eq!(
non_terminal_count, 0,
"All edge case status codes should be terminal for fail-safe behavior"
);
println!("✅ EDGE CASE STATUS CODE AUDIT COMPLETE");
println!("🏆 FINDING: Fail-safe handling of unexpected status codes");
}