use crank_core::{CorrelationContext, RequestId, TraceContext, TraceId}; use uuid::Version; const VALID_TRACEPARENT: &str = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"; #[test] fn generated_identities_are_distinct_and_canonical() { let context = CorrelationContext::generate(); assert_eq!( uuid::Uuid::parse_str(context.request_id().as_str()) .unwrap() .get_version(), Some(Version::SortRand) ); assert_eq!(context.trace_id().as_str().len(), 32); assert!( context .trace_id() .as_str() .bytes() .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase()) ); assert_ne!( context.request_id().as_str().replace('-', ""), context.trace_id().as_str() ); } #[test] fn request_id_preserves_one_valid_opaque_value_and_replaces_invalid_values() { assert_eq!( RequestId::resolve(Some("gateway-request-42")).as_str(), "gateway-request-42" ); for invalid in ["", "bad value", "bad,value", "bad;value"] { let replacement = RequestId::resolve(Some(invalid)); assert_ne!(replacement.as_str(), invalid); assert_eq!( uuid::Uuid::parse_str(replacement.as_str()) .unwrap() .get_version(), Some(Version::SortRand) ); } assert!(RequestId::is_valid(&"a".repeat(RequestId::MAX_LEN))); assert!(!RequestId::is_valid(&"a".repeat(RequestId::MAX_LEN + 1))); } #[test] fn traceparent_parser_is_strict_and_never_accepts_zero_ids() { let context = TraceContext::parse(VALID_TRACEPARENT).unwrap(); assert_eq!( context.trace_id().as_str(), "0af7651916cd43dd8448eb211c80319c" ); assert_eq!(context.traceparent(), VALID_TRACEPARENT); for invalid in [ "00-00000000000000000000000000000000-b7ad6b7169203331-01", "00-0af7651916cd43dd8448eb211c80319c-0000000000000000-01", "00-0AF7651916CD43DD8448EB211C80319C-b7ad6b7169203331-01", "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-0z", "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-02", "ff-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01", "canary-invalid-traceparent", ] { assert!(TraceContext::parse(invalid).is_err(), "accepted {invalid}"); } assert!(TraceId::parse("00000000000000000000000000000000").is_err()); } #[test] fn durable_parent_envelope_roundtrips_without_conflating_ids() { let context = CorrelationContext::new( RequestId::resolve(Some("request-opaque-1")), TraceContext::parse(VALID_TRACEPARENT).unwrap(), ); let encoded = serde_json::to_vec(&context).unwrap(); let decoded: CorrelationContext = serde_json::from_slice(&encoded).unwrap(); assert_eq!(decoded, context); assert_eq!(decoded.request_id().as_str(), "request-opaque-1"); assert_eq!( decoded.trace_id().as_str(), "0af7651916cd43dd8448eb211c80319c" ); } #[test] fn durable_parent_envelope_rejects_invalid_or_inconsistent_identities() { for candidate in [ serde_json::json!({ "request_id": "bad request", "trace_context": { "trace_id": "0af7651916cd43dd8448eb211c80319c", "traceparent": VALID_TRACEPARENT, } }), serde_json::json!({ "request_id": "request-1", "trace_context": { "trace_id": "00000000000000000000000000000000", "traceparent": VALID_TRACEPARENT, } }), serde_json::json!({ "request_id": "request-1", "trace_context": { "trace_id": "1af7651916cd43dd8448eb211c80319c", "traceparent": VALID_TRACEPARENT, } }), ] { assert!(serde_json::from_value::(candidate).is_err()); } } #[test] fn caller_state_and_baggage_budgets_are_closed_and_bounded() { assert!(TraceContext::tracestate_within_budget("vendor=value")); assert!(!TraceContext::tracestate_within_budget(&"x".repeat(513))); assert!(!TraceContext::tracestate_within_budget( &std::iter::repeat_n("a=b", 33).collect::>().join(",") )); assert!(TraceContext::baggage_within_budget("key=value")); assert!(!TraceContext::baggage_within_budget(&"x".repeat(8_193))); assert!(!TraceContext::baggage_within_budget( &std::iter::repeat_n("a=b", 65).collect::>().join(",") )); }