use tracing::{info, warn, Level};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::Layer;
use tracing_throttle::infrastructure::mocks::MockCaptureLayer;
use tracing_throttle::{Policy, TracingRateLimitLayer};
#[test]
fn test_rate_limit_layer_integration() {
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(3).unwrap())
.build()
.unwrap();
let subscriber = tracing_subscriber::registry().with(capture.clone().with_filter(rate_limit));
tracing::subscriber::with_default(subscriber, || {
for _ in 0..10 {
info!("test event");
}
});
assert_eq!(capture.count(), 3);
}
#[test]
fn test_different_messages_independent_limits() {
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(2).unwrap())
.build()
.unwrap();
let subscriber = tracing_subscriber::registry().with(capture.clone().with_filter(rate_limit));
tracing::subscriber::with_default(subscriber, || {
for _ in 0..5 {
info!("message A");
}
for _ in 0..5 {
warn!("message B");
}
});
assert_eq!(capture.count(), 4);
}
#[test]
fn test_different_levels_independent_limits() {
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(2).unwrap())
.build()
.unwrap();
let subscriber = tracing_subscriber::registry().with(capture.clone().with_filter(rate_limit));
tracing::subscriber::with_default(subscriber, || {
for _ in 0..5 {
info!("same message");
}
for _ in 0..5 {
warn!("same message");
}
});
let captured = capture.get_captured();
assert_eq!(captured.len(), 4);
let info_count = captured.iter().filter(|e| e.level == Level::INFO).count();
let warn_count = captured.iter().filter(|e| e.level == Level::WARN).count();
assert_eq!(info_count, 2);
assert_eq!(warn_count, 2);
}
#[test]
fn test_metrics_match_suppression() {
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(3).unwrap())
.build()
.unwrap();
let subscriber =
tracing_subscriber::registry().with(capture.clone().with_filter(rate_limit.clone()));
tracing::subscriber::with_default(subscriber, || {
for _ in 0..10 {
info!("test");
}
});
let metrics = rate_limit.metrics().snapshot();
assert_eq!(metrics.events_allowed, 3);
assert_eq!(metrics.events_suppressed, 7);
assert_eq!(capture.count(), 3); }
#[test]
fn test_signature_count_tracking() {
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(1).unwrap())
.build()
.unwrap();
let subscriber = tracing_subscriber::registry().with(capture.with_filter(rate_limit.clone()));
tracing::subscriber::with_default(subscriber, || {
info!("message 1");
info!("message 2");
info!("message 3");
info!("message 1"); });
assert_eq!(rate_limit.signature_count(), 4);
}
#[test]
fn test_eviction_with_small_limit() {
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(1).unwrap())
.with_max_signatures(3)
.build()
.unwrap();
let subscriber = tracing_subscriber::registry().with(capture.with_filter(rate_limit.clone()));
tracing::subscriber::with_default(subscriber, || {
info!("msg 1");
info!("msg 2");
info!("msg 3");
info!("msg 4");
});
assert_eq!(rate_limit.signature_count(), 3);
assert_eq!(rate_limit.metrics().signatures_evicted(), 1);
}
#[test]
fn test_circuit_breaker_remains_closed() {
use tracing_throttle::CircuitState;
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(2).unwrap())
.build()
.unwrap();
let subscriber = tracing_subscriber::registry().with(rate_limit.clone());
tracing::subscriber::with_default(subscriber, || {
for _ in 0..100 {
info!("test");
}
});
assert_eq!(rate_limit.circuit_breaker().state(), CircuitState::Closed);
assert_eq!(rate_limit.circuit_breaker().consecutive_failures(), 0);
}
#[test]
fn test_high_concurrency_stress() {
use std::thread;
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(100).unwrap())
.build()
.unwrap();
let subscriber =
tracing_subscriber::registry().with(capture.clone().with_filter(rate_limit.clone()));
tracing::subscriber::set_global_default(subscriber).ok();
let mut handles = vec![];
for _ in 0..10 {
let handle = thread::spawn(|| {
for _ in 0..50 {
info!("concurrent test");
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let metrics = rate_limit.metrics().snapshot();
assert_eq!(metrics.events_allowed, 100);
assert_eq!(metrics.events_suppressed, 400);
assert_eq!(capture.count(), 100);
}
#[test]
fn test_zero_limit_suppresses_all_after_first() {
let capture = MockCaptureLayer::new();
let rate_limit = TracingRateLimitLayer::builder()
.with_policy(Policy::count_based(1).unwrap())
.build()
.unwrap();
let subscriber = tracing_subscriber::registry().with(capture.clone().with_filter(rate_limit));
tracing::subscriber::with_default(subscriber, || {
for _ in 0..100 {
info!("test");
}
});
assert_eq!(capture.count(), 1);
}