use bucketwarden_server::{
s3_service_specific_error_catalog, BucketWarden, RuntimeConfig, S3ServiceSpecificError,
};
use serde_json::Value;
use std::collections::BTreeSet;
const S3ERR_RUNTIME_EVIDENCE_JSON: &str =
include_str!("../../../.ssot/evidence/s3-service-specific-errors-runtime-foundation-t0.json");
fn expected_feature_ids() -> Vec<String> {
let payload: Value =
serde_json::from_str(S3ERR_RUNTIME_EVIDENCE_JSON).expect("valid ssot evidence JSON");
payload["feature_ids"]
.as_array()
.expect("runtime evidence has feature_ids array")
.iter()
.map(|value| {
value
.as_str()
.expect("feature id must be a string")
.to_owned()
})
.collect()
}
#[test]
fn service_specific_s3_error_catalog_emits_all_tracked_leaf_codes() {
let catalog = s3_service_specific_error_catalog();
let expected_features = expected_feature_ids();
assert_eq!(catalog.len(), expected_features.len());
assert_eq!(
catalog
.iter()
.map(|error| error.feature_id)
.map(str::to_owned)
.collect::<Vec<_>>(),
expected_features
);
assert_eq!(
catalog
.iter()
.map(|error| error.feature_id)
.collect::<BTreeSet<_>>()
.len(),
expected_features.len()
);
let mut runtime = BucketWarden::new(RuntimeConfig::development()).expect("runtime");
for error in catalog {
let response = runtime
.s3_service_specific_error_response(error.feature_id)
.expect("service-specific error response");
assert_eq!(response.status, error.status, "{}", error.feature_id);
assert_eq!(
response.headers.get("x-bucketwarden-error-family"),
Some(&error.family.to_string()),
"{}",
error.feature_id
);
assert_error_body(&response.body, error);
if error.status >= 400 {
assert!(response.headers.contains_key("x-amz-request-id"));
assert!(response.headers.contains_key("x-amz-id-2"));
assert_eq!(
response.headers.get("x-bucketwarden-error-retryable"),
Some(&(error.status == 500 || error.status == 503).to_string()),
"{}",
error.feature_id
);
}
}
assert!(runtime
.s3_service_specific_error_response("feat:bucketwarden.s3err.unknown")
.is_none());
}
fn assert_error_body(body: &[u8], error: &S3ServiceSpecificError) {
let body = String::from_utf8(body.to_vec()).expect("xml body");
assert!(
body.contains(&format!("<Code>{}</Code>", error.code)),
"{} body: {body}",
error.feature_id
);
assert!(
body.contains("<Message>"),
"{} body: {body}",
error.feature_id
);
if error.status >= 400 {
assert!(
body.contains("<RequestId>bwreq"),
"{} body: {body}",
error.feature_id
);
assert!(
body.contains("<HostId>"),
"{} body: {body}",
error.feature_id
);
}
}