stygian_graph/adapters/
noop.rs

1//! No-op service adapter for testing
2//!
3//! A minimal implementation of ScrapingService that does nothing but return
4//! success. Used to validate that the port trait compiles and can be implemented.
5
6use crate::domain::error::Result;
7use crate::ports::{ScrapingService, ServiceInput, ServiceOutput};
8use async_trait::async_trait;
9use serde_json::json;
10
11/// No-operation scraping service
12///
13/// Returns empty data with success metadata. Useful for testing pipeline
14/// execution without performing actual I/O operations.
15///
16/// # Example
17///
18/// ```
19/// use stygian_graph::adapters::noop::NoopService;
20/// use stygian_graph::ports::{ScrapingService, ServiceInput};
21/// use serde_json::json;
22///
23/// # #[tokio::main]
24/// # async fn main() {
25/// let service = NoopService;
26/// let input = ServiceInput {
27///     url: "https://example.com".to_string(),
28///     params: json!({}),
29/// };
30///
31/// let output = service.execute(input).await.unwrap();
32/// assert_eq!(output.data, "");
33/// assert_eq!(output.metadata["success"], true);
34/// # }
35/// ```
36pub struct NoopService;
37
38#[async_trait]
39impl ScrapingService for NoopService {
40    async fn execute(&self, input: ServiceInput) -> Result<ServiceOutput> {
41        Ok(ServiceOutput {
42            data: String::new(),
43            metadata: json!({
44                "success": true,
45                "url": input.url,
46                "service": self.name(),
47            }),
48        })
49    }
50
51    fn name(&self) -> &'static str {
52        "noop"
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use serde_json::json;
60
61    #[tokio::test]
62    async fn test_noop_service_executes() -> Result<()> {
63        let service = NoopService;
64        let input = ServiceInput {
65            url: "https://example.com".to_string(),
66            params: json!({"test": true}),
67        };
68
69        let output = service.execute(input).await?;
70        assert_eq!(output.data, "", "NoopService returns empty data");
71        assert_eq!(
72            output.metadata.get("success"),
73            Some(&serde_json::json!(true)),
74            "Metadata should indicate success"
75        );
76        assert_eq!(
77            output.metadata.get("url"),
78            Some(&serde_json::json!("https://example.com")),
79            "Metadata should include URL"
80        );
81        Ok(())
82    }
83
84    #[tokio::test]
85    async fn test_noop_service_name() {
86        let service = NoopService;
87        assert_eq!(service.name(), "noop");
88    }
89
90    #[tokio::test]
91    async fn test_noop_service_is_send_sync() {
92        // Compile-time check that NoopService implements Send + Sync
93        fn assert_send_sync<T: Send + Sync>() {}
94        assert_send_sync::<NoopService>();
95    }
96
97    #[tokio::test]
98    async fn test_multiple_executions() {
99        let service = NoopService;
100
101        // Execute multiple times to ensure stateless behavior
102        for i in 0..5 {
103            let url = format!("https://example.com/page{i}");
104            let input = ServiceInput {
105                url,
106                params: json!({"iteration": i}),
107            };
108
109            let result = service.execute(input).await;
110            assert!(result.is_ok(), "All executions should succeed");
111        }
112    }
113}