Files

134 lines
4.5 KiB
Rust

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);
assert!(context.is_sampled());
assert!(!TraceContext::generate().is_sampled());
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::<CorrelationContext>(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::<Vec<_>>().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::<Vec<_>>().join(",")
));
}