#[test]
#[cfg(feature = "gpu")]
fn test_imp_064_priority_queue() {
use crate::gpu::{PriorityRequest, PriorityRequestQueue};
let mut queue = PriorityRequestQueue::new();
assert!(queue.is_empty(), "IMP-064: New queue should be empty");
assert_eq!(queue.len(), 0, "IMP-064: New queue length should be 0");
queue.enqueue(PriorityRequest::new(1, "low_priority".to_string()));
queue.enqueue(PriorityRequest::new(3, "high_priority".to_string()));
queue.enqueue(PriorityRequest::new(2, "medium_priority".to_string()));
assert_eq!(queue.len(), 3, "IMP-064: Should have 3 requests");
let req = queue.dequeue_highest();
assert!(req.is_some(), "IMP-064: Should dequeue request");
assert_eq!(
req.expect("test").data(),
"high_priority",
"IMP-064: Highest priority first"
);
let req = queue.dequeue_highest();
assert_eq!(
req.expect("test").data(),
"medium_priority",
"IMP-064: Medium priority second"
);
let req = queue.dequeue_highest();
assert_eq!(
req.expect("test").data(),
"low_priority",
"IMP-064: Low priority last"
);
assert!(queue.is_empty(), "IMP-064: Queue should be empty");
assert!(
queue.dequeue_highest().is_none(),
"IMP-064: Dequeue empty returns None"
);
queue.enqueue(PriorityRequest::new(5, "first".to_string()));
queue.enqueue(PriorityRequest::new(5, "second".to_string()));
queue.enqueue(PriorityRequest::new(5, "third".to_string()));
assert_eq!(
queue.dequeue_highest().expect("test").data(),
"first",
"IMP-064: FIFO for same priority"
);
assert_eq!(
queue.dequeue_highest().expect("test").data(),
"second",
"IMP-064: FIFO order"
);
assert_eq!(
queue.dequeue_highest().expect("test").data(),
"third",
"IMP-064: FIFO order"
);
}
#[test]
#[cfg(feature = "gpu")]
fn test_imp_065_rate_limiter() {
use crate::gpu::TokenRateLimiter;
use std::time::Duration;
let mut limiter = TokenRateLimiter::new(10.0, 5);
assert_eq!(
limiter.tokens_available(),
5,
"IMP-065: Should start with burst capacity"
);
assert!(limiter.try_acquire(3), "IMP-065: Should acquire 3 tokens");
assert_eq!(
limiter.tokens_available(),
2,
"IMP-065: Should have 2 remaining"
);
assert!(
!limiter.try_acquire(3),
"IMP-065: Should fail to acquire 3 when only 2 available"
);
assert_eq!(
limiter.tokens_available(),
2,
"IMP-065: Tokens unchanged on failed acquire"
);
assert!(
limiter.try_acquire(2),
"IMP-065: Should acquire remaining 2"
);
assert_eq!(
limiter.tokens_available(),
0,
"IMP-065: Should have 0 remaining"
);
std::thread::sleep(Duration::from_millis(200)); limiter.refill();
let available = limiter.tokens_available();
assert!(
available >= 1,
"IMP-065: Should have refilled at least 1 token, got {}",
available
);
assert!(available <= 5, "IMP-065: Should not exceed burst capacity");
}
#[test]
#[cfg(feature = "gpu")]
fn test_imp_066_resource_tracker() {
use crate::gpu::ResourceTracker;
let mut tracker = ResourceTracker::new(1024 * 1024 * 1024, 100);
assert_eq!(
tracker.memory_usage(),
0,
"IMP-066: Initial memory usage is 0"
);
assert_eq!(
tracker.compute_usage(),
0,
"IMP-066: Initial compute usage is 0"
);
assert!(
tracker.can_allocate(512 * 1024 * 1024, 50),
"IMP-066: Should be able to allocate 512MB, 50% compute"
);
assert!(
!tracker.can_allocate(2 * 1024 * 1024 * 1024, 50),
"IMP-066: Cannot allocate more than capacity"
);
let alloc_id = tracker.allocate(256 * 1024 * 1024, 30);
assert!(alloc_id.is_some(), "IMP-066: Allocation should succeed");
assert_eq!(
tracker.memory_usage(),
256 * 1024 * 1024,
"IMP-066: Memory usage updated"
);
assert_eq!(
tracker.compute_usage(),
30,
"IMP-066: Compute usage updated"
);
let alloc_id_2 = tracker.allocate(128 * 1024 * 1024, 20);
assert!(
alloc_id_2.is_some(),
"IMP-066: Second allocation should succeed"
);
assert_eq!(
tracker.memory_usage(),
384 * 1024 * 1024,
"IMP-066: Memory accumulated"
);
assert_eq!(tracker.compute_usage(), 50, "IMP-066: Compute accumulated");
tracker.release(alloc_id.expect("test"));
assert_eq!(
tracker.memory_usage(),
128 * 1024 * 1024,
"IMP-066: Memory released"
);
assert_eq!(tracker.compute_usage(), 20, "IMP-066: Compute released");
let (mem_pct, compute_pct) = tracker.usage_percentage();
let expected_mem_pct = (128.0 * 1024.0 * 1024.0) / (1024.0 * 1024.0 * 1024.0) * 100.0;
assert!(
(mem_pct - expected_mem_pct).abs() < 0.1,
"IMP-066: Memory percentage correct"
);
assert!(
(compute_pct - 20.0).abs() < 0.1,
"IMP-066: Compute percentage correct"
);
}
#[test]
#[cfg(feature = "gpu")]
fn test_imp_067_inference_metrics() {
use crate::gpu::InferenceMetrics;
use std::time::Duration;
let mut metrics = InferenceMetrics::new();
assert_eq!(
metrics.total_inferences(),
0,
"IMP-067: No inferences initially"
);
assert_eq!(metrics.total_tokens(), 0, "IMP-067: No tokens initially");
metrics.record_inference(Duration::from_millis(10), 5); metrics.record_inference(Duration::from_millis(20), 10); metrics.record_inference(Duration::from_millis(15), 8); assert_eq!(
metrics.total_inferences(),
3,
"IMP-067: Should have 3 inferences"
);
assert_eq!(metrics.total_tokens(), 23, "IMP-067: Should have 23 tokens");
let p50 = metrics.latency_percentile(50);
assert!(p50.is_some(), "IMP-067: Should have p50");
let p50_ms = p50.expect("test").as_millis();
assert!(
p50_ms >= 10 && p50_ms <= 20,
"IMP-067: p50 should be ~15ms, got {}ms",
p50_ms
);
let throughput = metrics.throughput();
assert!(throughput > 0.0, "IMP-067: Throughput should be positive");
metrics.reset();
assert_eq!(metrics.total_inferences(), 0, "IMP-067: Inferences reset");
assert_eq!(metrics.total_tokens(), 0, "IMP-067: Tokens reset");
}
#[test]
#[cfg(feature = "gpu")]
fn test_imp_068_health_checker() {
use crate::gpu::HealthChecker;
let mut checker = HealthChecker::new();
assert!(
checker.is_healthy(),
"IMP-068: Healthy when no checks registered"
);
checker.register_check("gpu", Box::new(|| true));
assert_eq!(checker.check_count(), 1, "IMP-068: Should have 1 check");
let results = checker.check_all();
assert_eq!(results.len(), 1, "IMP-068: Should have 1 result");
assert!(
results.get("gpu").copied().unwrap_or(false),
"IMP-068: GPU should be healthy"
);
assert!(checker.is_healthy(), "IMP-068: Overall should be healthy");
checker.register_check("memory", Box::new(|| false));
let results = checker.check_all();
assert!(
!results.get("memory").copied().unwrap_or(true),
"IMP-068: Memory should be unhealthy"
);
assert!(
!checker.is_healthy(),
"IMP-068: Overall should be unhealthy"
);
checker.clear();
assert_eq!(checker.check_count(), 0, "IMP-068: No checks after clear");
assert!(checker.is_healthy(), "IMP-068: Healthy after clear");
}
#[test]
#[cfg(feature = "gpu")]
fn test_imp_069_graceful_shutdown() {
use crate::gpu::ShutdownCoordinator;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
let mut coordinator = ShutdownCoordinator::new();
assert!(
!coordinator.is_shutting_down(),
"IMP-069: Not shutting down initially"
);
assert_eq!(
coordinator.pending_requests(),
0,
"IMP-069: No pending requests"
);
let handler_called = Arc::new(AtomicBool::new(false));
let handler_called_clone = handler_called.clone();
coordinator.register_handler(Box::new(move || {
handler_called_clone.store(true, Ordering::SeqCst);
}));
assert_eq!(
coordinator.handler_count(),
1,
"IMP-069: Should have 1 handler"
);
coordinator.request_started();
coordinator.request_started();
assert_eq!(
coordinator.pending_requests(),
2,
"IMP-069: Should have 2 pending"
);
coordinator.initiate_shutdown();
assert!(
coordinator.is_shutting_down(),
"IMP-069: Should be shutting down"
);
assert!(
handler_called.load(Ordering::SeqCst),
"IMP-069: Handler should be called"
);
coordinator.request_completed();
assert_eq!(
coordinator.pending_requests(),
1,
"IMP-069: Should have 1 pending"
);
coordinator.request_completed();
assert_eq!(
coordinator.pending_requests(),
0,
"IMP-069: Should have 0 pending"
);
assert!(
coordinator.is_complete(),
"IMP-069: Should be complete when shutdown + no pending"
);
}