//! No-operation queue adapter implementation. //! //! This module provides a queue adapter that discards all work items, //! useful for testing or when queue processing is disabled. use async_trait::async_trait; use std::time::Duration; use tokio::time::sleep; use super::adapter::QueueAdapter; use super::error::Result; /// No-operation queue adapter that discards all work items. /// /// This adapter is useful for configurations where queuing is disabled /// or as a fallback when other queue adapters fail to initialize. /// All work items pushed to this queue are silently discarded. /// /// # Features /// /// - Zero resource usage /// - Always healthy /// - Discards all work items /// - Never returns items from pull /// /// # Use Cases /// /// - Testing environments where queue processing isn't needed /// - Graceful degradation when queue backends are unavailable /// - Configurations where queue processing is explicitly disabled /// /// # Examples /// /// ``` /// use quickdid::queue::NoopQueueAdapter; /// use quickdid::queue::QueueAdapter; /// /// # async fn example() -> anyhow::Result<()> { /// let queue = NoopQueueAdapter::::new(); /// /// // Push is silently discarded /// queue.push("ignored".to_string()).await?; /// /// // Pull never returns items (blocks indefinitely) /// // let item = queue.pull().await; // Would block forever /// /// // Always reports healthy /// assert!(queue.is_healthy().await); /// /// // Always reports empty /// assert_eq!(queue.depth().await, Some(0)); /// # Ok(()) /// # } /// ``` pub struct NoopQueueAdapter where T: Send + Sync + 'static, { _phantom: std::marker::PhantomData, } impl NoopQueueAdapter where T: Send + Sync + 'static, { /// Create a new no-op queue adapter. /// /// # Examples /// /// ``` /// use quickdid::queue::NoopQueueAdapter; /// /// let queue = NoopQueueAdapter::::new(); /// ``` pub fn new() -> Self { Self { _phantom: std::marker::PhantomData, } } } impl Default for NoopQueueAdapter where T: Send + Sync + 'static, { fn default() -> Self { Self::new() } } #[async_trait] impl QueueAdapter for NoopQueueAdapter where T: Send + Sync + 'static, { async fn pull(&self) -> Option { // Never returns any work - sleeps to avoid busy-waiting sleep(Duration::from_secs(60)).await; None } async fn push(&self, _work: T) -> Result<()> { // Silently discard the work Ok(()) } async fn ack(&self, _item: &T) -> Result<()> { // No-op Ok(()) } async fn try_push(&self, _work: T) -> Result<()> { // Silently discard the work Ok(()) } async fn depth(&self) -> Option { // Always empty Some(0) } async fn is_healthy(&self) -> bool { // Always healthy true } } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_noop_queue_push() { let queue = NoopQueueAdapter::::new(); // Push should always succeed queue.push("test1".to_string()).await.unwrap(); queue.push("test2".to_string()).await.unwrap(); queue.push("test3".to_string()).await.unwrap(); } #[tokio::test] async fn test_noop_queue_try_push() { let queue = NoopQueueAdapter::::new(); // Try push should always succeed queue.try_push(1).await.unwrap(); queue.try_push(2).await.unwrap(); queue.try_push(3).await.unwrap(); } #[tokio::test] async fn test_noop_queue_ack() { let queue = NoopQueueAdapter::::new(); // Ack should always succeed queue.ack(&"any".to_string()).await.unwrap(); } #[tokio::test] async fn test_noop_queue_depth() { let queue = NoopQueueAdapter::::new(); // Should always report empty assert_eq!(queue.depth().await, Some(0)); // Even after pushing items queue.push("item".to_string()).await.unwrap(); assert_eq!(queue.depth().await, Some(0)); } #[tokio::test] async fn test_noop_queue_health() { let queue = NoopQueueAdapter::::new(); // Should always be healthy assert!(queue.is_healthy().await); } #[tokio::test] async fn test_noop_queue_default() { let queue: NoopQueueAdapter = Default::default(); // Default instance should work normally queue.push("test".to_string()).await.unwrap(); assert!(queue.is_healthy().await); } #[tokio::test(flavor = "multi_thread")] async fn test_noop_queue_pull_blocks() { use tokio::time::timeout; let queue = NoopQueueAdapter::::new(); // Pull should block and not return immediately let result = timeout(Duration::from_millis(100), queue.pull()).await; assert!(result.is_err(), "Pull should have timed out"); } #[tokio::test] async fn test_noop_queue_with_custom_type() { use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] struct CustomWork { id: u64, data: Vec, } let queue = NoopQueueAdapter::::new(); let work = CustomWork { id: 123, data: vec!["test".to_string()], }; // Should handle custom types without issue queue.push(work.clone()).await.unwrap(); queue.ack(&work).await.unwrap(); assert_eq!(queue.depth().await, Some(0)); } }