Skip to main content

camel_api/
producer.rs

1//! Producer context for dependency injection.
2//!
3//! This module provides [`ProducerContext`] for holding shared dependencies
4//! that producers need access to, such as the runtime command/query handle.
5
6use crate::runtime::RuntimeHandle;
7use std::sync::Arc;
8
9/// Context provided to producers for dependency injection.
10///
11/// `ProducerContext` holds references to shared infrastructure components
12/// that producers may need access to during message production.
13#[derive(Clone)]
14pub struct ProducerContext {
15    runtime: Option<Arc<dyn RuntimeHandle>>,
16}
17
18impl ProducerContext {
19    /// Creates a new empty `ProducerContext`.
20    pub fn new() -> Self {
21        Self { runtime: None }
22    }
23
24    /// Attaches a runtime command/query handle.
25    pub fn with_runtime(mut self, runtime: Arc<dyn RuntimeHandle>) -> Self {
26        self.runtime = Some(runtime);
27        self
28    }
29
30    /// Returns the runtime command/query handle, if configured.
31    pub fn runtime(&self) -> Option<&Arc<dyn RuntimeHandle>> {
32        self.runtime.as_ref()
33    }
34}
35
36impl Default for ProducerContext {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use crate::CamelError;
46    use crate::runtime::{
47        RuntimeCommand, RuntimeCommandBus, RuntimeCommandResult, RuntimeQuery, RuntimeQueryBus,
48        RuntimeQueryResult,
49    };
50    use async_trait::async_trait;
51    use futures::executor::block_on;
52
53    struct NoopRuntime;
54
55    #[async_trait]
56    impl RuntimeCommandBus for NoopRuntime {
57        async fn execute(&self, _cmd: RuntimeCommand) -> Result<RuntimeCommandResult, CamelError> {
58            Ok(RuntimeCommandResult::Accepted)
59        }
60    }
61
62    #[async_trait]
63    impl RuntimeQueryBus for NoopRuntime {
64        async fn ask(&self, _query: RuntimeQuery) -> Result<RuntimeQueryResult, CamelError> {
65            Ok(RuntimeQueryResult::Routes { route_ids: vec![] })
66        }
67    }
68
69    #[test]
70    fn producer_context_new_is_empty() {
71        let ctx = ProducerContext::new();
72        assert!(ctx.runtime().is_none());
73    }
74
75    #[test]
76    fn producer_context_default_is_empty() {
77        let ctx = ProducerContext::default();
78        assert!(ctx.runtime().is_none());
79    }
80
81    #[test]
82    fn producer_context_with_runtime_sets_handle() {
83        let runtime: Arc<dyn RuntimeHandle> = Arc::new(NoopRuntime);
84        let ctx = ProducerContext::new().with_runtime(runtime.clone());
85
86        let attached = ctx.runtime().expect("runtime should be set");
87        assert!(Arc::ptr_eq(attached, &runtime));
88    }
89
90    #[test]
91    fn producer_context_clone_keeps_same_runtime_handle() {
92        let runtime: Arc<dyn RuntimeHandle> = Arc::new(NoopRuntime);
93        let ctx = ProducerContext::new().with_runtime(runtime.clone());
94        let cloned = ctx.clone();
95
96        assert!(Arc::ptr_eq(cloned.runtime().unwrap(), &runtime));
97    }
98
99    #[test]
100    fn producer_context_with_runtime_can_execute_command() {
101        let runtime: Arc<dyn RuntimeHandle> = Arc::new(NoopRuntime);
102        let ctx = ProducerContext::new().with_runtime(runtime);
103        let result = block_on(ctx.runtime().unwrap().execute(RuntimeCommand::StartRoute {
104            route_id: "r1".into(),
105            command_id: "c1".into(),
106            causation_id: None,
107        }))
108        .unwrap();
109
110        assert_eq!(result, RuntimeCommandResult::Accepted);
111    }
112
113    #[test]
114    fn producer_context_with_runtime_can_execute_query() {
115        let runtime: Arc<dyn RuntimeHandle> = Arc::new(NoopRuntime);
116        let ctx = ProducerContext::new().with_runtime(runtime);
117        let result = block_on(ctx.runtime().unwrap().ask(RuntimeQuery::ListRoutes)).unwrap();
118
119        assert_eq!(result, RuntimeQueryResult::Routes { route_ids: vec![] });
120    }
121
122    #[test]
123    fn producer_context_with_runtime_replaces_previous_runtime() {
124        let first: Arc<dyn RuntimeHandle> = Arc::new(NoopRuntime);
125        let second: Arc<dyn RuntimeHandle> = Arc::new(NoopRuntime);
126        let ctx = ProducerContext::new()
127            .with_runtime(first)
128            .with_runtime(second.clone());
129
130        assert!(Arc::ptr_eq(ctx.runtime().unwrap(), &second));
131    }
132}