feat: harden community production foundation through story 1.5
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
use axum::http::{HeaderMap, HeaderValue};
|
||||
use crank_observability::RequestId;
|
||||
use uuid::Version;
|
||||
|
||||
#[test]
|
||||
fn preserves_valid_opaque_request_id() {
|
||||
let request_id = RequestId::resolve(Some("req_test-123/abc"));
|
||||
|
||||
assert_eq!(request_id.as_str(), "req_test-123/abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replaces_missing_and_invalid_values_with_uuid_v7() {
|
||||
for candidate in [
|
||||
None,
|
||||
Some(""),
|
||||
Some("bad value"),
|
||||
Some(" leading"),
|
||||
Some("trailing "),
|
||||
Some("bad,value"),
|
||||
Some("bad;value"),
|
||||
Some("я"),
|
||||
] {
|
||||
let request_id = RequestId::resolve(candidate);
|
||||
let parsed = uuid::Uuid::parse_str(request_id.as_str()).expect("generated UUID");
|
||||
|
||||
assert_eq!(parsed.get_version(), Some(Version::SortRand));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_values_over_the_shared_limit() {
|
||||
let oversized = "x".repeat(RequestId::MAX_LEN + 1);
|
||||
let request_id = RequestId::resolve(Some(&oversized));
|
||||
|
||||
assert_ne!(request_id.as_str(), oversized);
|
||||
assert_eq!(
|
||||
uuid::Uuid::parse_str(request_id.as_str())
|
||||
.expect("generated UUID")
|
||||
.get_version(),
|
||||
Some(Version::SortRand)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_exactly_one_header_value_and_rejects_ambiguous_values() {
|
||||
let mut single = HeaderMap::new();
|
||||
single.insert(
|
||||
"x-request-id",
|
||||
HeaderValue::from_static("opaque-request-id"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
RequestId::resolve_from_headers(&single).as_str(),
|
||||
"opaque-request-id"
|
||||
);
|
||||
|
||||
let mut ambiguous = HeaderMap::new();
|
||||
ambiguous.append("x-request-id", HeaderValue::from_static("first-request-id"));
|
||||
ambiguous.append(
|
||||
"x-request-id",
|
||||
HeaderValue::from_static("second-request-id"),
|
||||
);
|
||||
|
||||
let generated = RequestId::resolve_from_headers(&ambiguous);
|
||||
assert_ne!(generated.as_str(), "first-request-id");
|
||||
assert_ne!(generated.as_str(), "second-request-id");
|
||||
assert_eq!(
|
||||
uuid::Uuid::parse_str(generated.as_str())
|
||||
.expect("generated UUID")
|
||||
.get_version(),
|
||||
Some(Version::SortRand)
|
||||
);
|
||||
}
|
||||
@@ -132,11 +132,11 @@ fn correlation_fields_are_distinct_and_only_present_when_recorded() {
|
||||
tracing::info!(
|
||||
name: "admin.request.completed",
|
||||
request_id = "req-123",
|
||||
trace_id = "trace-456"
|
||||
trace_id = "0af7651916cd43dd8448eb211c80319c"
|
||||
);
|
||||
});
|
||||
assert_eq!(present[0]["request_id"], "req-123");
|
||||
assert_eq!(present[0]["trace_id"], "trace-456");
|
||||
assert_eq!(present[0]["trace_id"], "0af7651916cd43dd8448eb211c80319c");
|
||||
assert!(present[0]["fields"].get("request_id").is_none());
|
||||
assert!(present[0]["fields"].get("trace_id").is_none());
|
||||
|
||||
@@ -148,7 +148,7 @@ fn correlation_fields_are_distinct_and_only_present_when_recorded() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn correlation_fields_preserve_scalar_display_values_before_field_limits() {
|
||||
fn correlation_fields_accept_valid_strings_and_reject_non_string_values() {
|
||||
let limits = RedactionLimits {
|
||||
max_object_fields: 1,
|
||||
..RedactionLimits::default()
|
||||
@@ -164,7 +164,7 @@ fn correlation_fields_preserve_scalar_display_values_before_field_limits() {
|
||||
});
|
||||
|
||||
assert_eq!(events[0]["request_id"], "123");
|
||||
assert_eq!(events[0]["trace_id"], "true");
|
||||
assert!(events[0].get("trace_id").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -321,7 +321,7 @@ fn subscriber_rejects_limits_that_cannot_hold_an_event() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimum_event_budget_handles_maximum_identity_labels() {
|
||||
fn event_budget_rejects_maximum_identity_labels_when_correlation_cannot_fit() {
|
||||
let writer = SharedWriter::default();
|
||||
let config = ObservabilityConfig::new(
|
||||
ServiceIdentity::try_new("s".repeat(64), "v".repeat(64), "e".repeat(64))
|
||||
@@ -332,20 +332,7 @@ fn minimum_event_budget_handles_maximum_identity_labels() {
|
||||
..RedactionLimits::default()
|
||||
},
|
||||
);
|
||||
let subscriber =
|
||||
build_subscriber(config, writer.clone()).expect("minimum valid budget must be usable");
|
||||
|
||||
tracing::subscriber::with_default(subscriber, || {
|
||||
tracing::info!(
|
||||
name: "event-name-that-is-intentionally-longer-than-the-fallback-limit",
|
||||
description = %"x".repeat(4096),
|
||||
);
|
||||
});
|
||||
|
||||
let output = writer.output();
|
||||
assert!(output.len() <= 512);
|
||||
assert_eq!(output.lines().count(), 1);
|
||||
serde_json::from_str::<Value>(output.trim_end()).expect("bounded line must remain valid JSON");
|
||||
assert!(build_subscriber(config, writer).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -97,6 +97,8 @@ fn schema_is_closed_and_uses_fixed_duration_buckets() {
|
||||
"agent_id",
|
||||
"operation_id",
|
||||
"request_id",
|
||||
"trace_id",
|
||||
"correlation_id",
|
||||
"url",
|
||||
"error_message",
|
||||
"text",
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crank_observability::{current_request_correlation, with_request_correlation};
|
||||
|
||||
#[tokio::test]
|
||||
async fn concurrent_request_correlation_is_task_local() {
|
||||
let barrier = Arc::new(tokio::sync::Barrier::new(2));
|
||||
let first = observe(
|
||||
"request-first",
|
||||
"0af7651916cd43dd8448eb211c80319c",
|
||||
Arc::clone(&barrier),
|
||||
);
|
||||
let second = observe(
|
||||
"request-second",
|
||||
"1af7651916cd43dd8448eb211c80319c",
|
||||
barrier,
|
||||
);
|
||||
let (first, second) = tokio::join!(first, second);
|
||||
|
||||
assert_eq!(
|
||||
first,
|
||||
(
|
||||
Some("request-first".to_owned()),
|
||||
Some("0af7651916cd43dd8448eb211c80319c".to_owned()),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
second,
|
||||
(
|
||||
Some("request-second".to_owned()),
|
||||
Some("1af7651916cd43dd8448eb211c80319c".to_owned()),
|
||||
)
|
||||
);
|
||||
assert_eq!(current_request_correlation(), (None, None));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_correlation_strings_never_enter_task_local_state() {
|
||||
let observed = with_request_correlation(
|
||||
"bad request id".to_owned(),
|
||||
"CANARY-NOT-A-TRACE-ID".to_owned(),
|
||||
async { current_request_correlation() },
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(observed, (None, None));
|
||||
}
|
||||
|
||||
async fn observe(
|
||||
request_id: &str,
|
||||
trace_id: &str,
|
||||
barrier: Arc<tokio::sync::Barrier>,
|
||||
) -> (Option<String>, Option<String>) {
|
||||
with_request_correlation(request_id.to_owned(), trace_id.to_owned(), async move {
|
||||
barrier.wait().await;
|
||||
tokio::task::yield_now().await;
|
||||
current_request_correlation()
|
||||
})
|
||||
.await
|
||||
}
|
||||
Reference in New Issue
Block a user