#[test]
fn test_extract_w3c_context_none() {
use provide_telemetry::extract_w3c_context;
let ctx = extract_w3c_context(None, None, None);
let _ = ctx;
}
#[test]
fn test_extract_w3c_context_with_header() {
use provide_telemetry::extract_w3c_context;
let header = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01";
let ctx = extract_w3c_context(Some(header), None, None);
if let Some(ref tid) = ctx.trace_id {
assert!(!tid.is_empty());
}
}
#[test]
fn test_counter_creation() {
use provide_telemetry::counter;
let _c = counter("test", None, None);
}
#[test]
fn test_gauge_creation() {
use provide_telemetry::gauge;
let _g = gauge("test", None, None);
}
#[test]
fn test_histogram_creation() {
use provide_telemetry::histogram;
let _h = histogram("test", None, None);
}
#[test]
fn test_get_logger() {
use provide_telemetry::get_logger;
let _ = get_logger(Some("test"));
}
#[test]
fn test_null_logger() {
use provide_telemetry::null_logger;
let _ = null_logger(Some("test"));
}
#[test]
fn test_buffer_logger() {
use provide_telemetry::buffer_logger;
let _ = buffer_logger(Some("test"));
}
#[test]
fn test_compute_error_fingerprint() {
use provide_telemetry::compute_error_fingerprint;
let fp = compute_error_fingerprint("ValueError", None);
assert!(!fp.is_empty());
}
#[test]
fn test_fingerprint_deterministic() {
use provide_telemetry::compute_error_fingerprint;
let fp1 = compute_error_fingerprint("ValueError", None);
let fp2 = compute_error_fingerprint("ValueError", None);
assert_eq!(fp1, fp2);
}
#[test]
fn test_fingerprint_different_errors() {
use provide_telemetry::compute_error_fingerprint;
let fp1 = compute_error_fingerprint("ValueError", None);
let fp2 = compute_error_fingerprint("TypeError", None);
assert_ne!(fp1, fp2);
}
#[test]
fn test_trace_context() {
use provide_telemetry::testing::{acquire_test_state_lock, reset_telemetry_state};
use provide_telemetry::{get_trace_context, set_trace_context};
let _guard = acquire_test_state_lock();
reset_telemetry_state();
let _guard = set_trace_context(Some("trace123".to_string()), Some("span456".to_string()));
let ctx = get_trace_context();
assert_eq!(ctx.get("trace_id"), Some(&Some("trace123".to_string())));
assert_eq!(ctx.get("span_id"), Some(&Some("span456".to_string())));
}
#[test]
fn test_get_tracer() {
use provide_telemetry::get_tracer;
let _ = get_tracer(Some("test"));
}
#[test]
fn fingerprint_with_stack_differs_from_no_stack() {
use provide_telemetry::compute_error_fingerprint;
let without = compute_error_fingerprint("ValueError", None);
let with_stack = compute_error_fingerprint("ValueError", Some("module_a.py\nmodule_b.py"));
assert_ne!(
with_stack, without,
"a non-empty stack must change the fingerprint"
);
}
#[test]
fn fingerprint_different_stacks_produce_different_hashes() {
use provide_telemetry::compute_error_fingerprint;
let fp1 = compute_error_fingerprint("ValueError", Some("module_a.py"));
let fp2 = compute_error_fingerprint("ValueError", Some("module_b.py"));
assert_ne!(
fp1, fp2,
"different stack frames must produce different fingerprints"
);
}
#[test]
fn fingerprint_stack_normalizes_path_separators() {
use provide_telemetry::compute_error_fingerprint;
let unix = compute_error_fingerprint("ValueError", Some("src/app/module.py"));
let windows = compute_error_fingerprint("ValueError", Some("src\\app\\module.py"));
assert_eq!(
unix, windows,
"path separators must be normalised to the same last component"
);
}
#[test]
fn fingerprint_stack_is_deterministic_with_frames() {
use provide_telemetry::compute_error_fingerprint;
let fp1 = compute_error_fingerprint("ValueError", Some(" app.py\n utils.py\n core.py"));
let fp2 = compute_error_fingerprint("ValueError", Some(" app.py\n utils.py\n core.py"));
assert_eq!(
fp1, fp2,
"same stack must always produce the same fingerprint"
);
}
#[test]
fn otel_installed_for_tests_returns_false_without_otel_feature() {
assert!(
!provide_telemetry::otel_installed_for_tests(),
"otel must not be marked as installed when built without the otel feature"
);
}
#[cfg(feature = "governance")]
#[test]
fn classification_policy_default_values() {
let policy = provide_telemetry::ClassificationPolicy::default();
assert_eq!(policy.public, "pass");
assert_eq!(policy.internal, "pass");
assert_eq!(policy.pii, "redact");
assert_eq!(policy.phi, "drop");
assert_eq!(policy.pci, "hash");
assert_eq!(policy.secret, "drop");
}
#[cfg(feature = "governance")]
#[test]
fn classification_policy_set_and_get_roundtrip() {
use provide_telemetry::testing::{acquire_test_state_lock, reset_telemetry_state};
let _guard = acquire_test_state_lock();
reset_telemetry_state();
let custom = provide_telemetry::ClassificationPolicy {
public: "pass".to_string(),
internal: "redact".to_string(),
pii: "drop".to_string(),
phi: "drop".to_string(),
pci: "drop".to_string(),
secret: "drop".to_string(), };
provide_telemetry::set_classification_policy(custom.clone());
let got = provide_telemetry::get_classification_policy();
assert_eq!(got.internal, "redact", "set value must be retrievable");
assert_eq!(got.pii, "drop");
provide_telemetry::set_classification_policy(provide_telemetry::ClassificationPolicy::default());
}
#[cfg(feature = "governance")]
#[test]
fn classification_policy_fields_are_distinct() {
let policy = provide_telemetry::ClassificationPolicy::default();
assert_ne!(
policy.pii, policy.pci,
"pii and pci must have different default actions"
);
assert_ne!(
policy.public, policy.phi,
"public and phi must have different default actions"
);
}
#[test]
fn test_set_and_get_strict_schema() {
use provide_telemetry::testing::{acquire_test_state_lock, reset_telemetry_state};
use provide_telemetry::{get_strict_schema, set_strict_schema};
let _guard = acquire_test_state_lock();
reset_telemetry_state();
set_strict_schema(false);
assert!(!get_strict_schema(), "default should be false");
set_strict_schema(true);
assert!(get_strict_schema(), "should be true after set");
set_strict_schema(false);
assert!(!get_strict_schema(), "should return to false");
}
#[test]
fn test_guard_attributes_enforces_limits() {
use provide_telemetry::testing::{acquire_test_state_lock, reset_telemetry_state};
use provide_telemetry::{
clear_cardinality_limits, guard_attributes, register_cardinality_limit, CardinalityLimit,
};
use std::collections::HashMap;
let _guard = acquire_test_state_lock();
reset_telemetry_state();
clear_cardinality_limits();
register_cardinality_limit(
"env",
CardinalityLimit {
max_values: 1,
ttl_seconds: 60.0,
},
);
let mut attrs: HashMap<String, String> = HashMap::new();
attrs.insert("env".to_string(), "prod".to_string());
let result = guard_attributes(attrs);
assert_eq!(result.get("env").map(String::as_str), Some("prod"));
let mut attrs2: HashMap<String, String> = HashMap::new();
attrs2.insert("env".to_string(), "staging".to_string());
attrs2.insert("region".to_string(), "us-east".to_string());
let result2 = guard_attributes(attrs2);
assert_eq!(result2.get("env").map(String::as_str), Some("__overflow__"));
assert_eq!(result2.get("region").map(String::as_str), Some("us-east"));
clear_cardinality_limits();
}
#[test]
fn test_guard_attributes_no_limits_passthrough() {
use provide_telemetry::testing::{acquire_test_state_lock, reset_telemetry_state};
use provide_telemetry::{clear_cardinality_limits, guard_attributes};
use std::collections::HashMap;
let _guard = acquire_test_state_lock();
reset_telemetry_state();
clear_cardinality_limits();
let mut attrs: HashMap<String, String> = HashMap::new();
attrs.insert("key".to_string(), "value".to_string());
let result = guard_attributes(attrs);
assert_eq!(result.get("key").map(String::as_str), Some("value"));
}