camel_component_api/
dispatch.rs1use std::future::Future;
13use std::pin::Pin;
14
15use camel_api::{CamelError, Exchange};
16
17pub trait InlineRouteDispatcher: Send + Sync + 'static {
25 fn dispatch(
29 &self,
30 exchange: Exchange,
31 ) -> Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send + 'static>>;
32}
33
34#[cfg(test)]
35mod tests {
36 use std::pin::Pin;
37 use std::sync::Arc;
38
39 use tokio::sync::mpsc;
40 use tokio_util::sync::CancellationToken;
41
42 use super::InlineRouteDispatcher;
43 use crate::consumer::{ConsumerContext, ExchangeEnvelope};
44 use camel_api::{Exchange, Message};
45
46 fn test_context() -> ConsumerContext {
47 let (tx, _rx) = mpsc::channel::<ExchangeEnvelope>(1);
48 ConsumerContext::new(tx, CancellationToken::new(), "test-route".to_string())
49 }
50
51 fn test_exchange() -> Exchange {
52 Exchange::new(Message::new("payload"))
53 }
54
55 struct IdentityDispatcher;
57
58 impl InlineRouteDispatcher for IdentityDispatcher {
59 fn dispatch(
60 &self,
61 exchange: Exchange,
62 ) -> Pin<Box<dyn Future<Output = Result<Exchange, camel_api::CamelError>> + Send + 'static>>
63 {
64 Box::pin(async move { Ok(exchange) })
65 }
66 }
67
68 struct TagDispatcher(&'static str);
71
72 impl InlineRouteDispatcher for TagDispatcher {
73 fn dispatch(
74 &self,
75 mut exchange: Exchange,
76 ) -> Pin<Box<dyn Future<Output = Result<Exchange, camel_api::CamelError>> + Send + 'static>>
77 {
78 let tag = self.0;
79 Box::pin(async move {
80 exchange.set_property("dispatcher", tag);
81 Ok(exchange)
82 })
83 }
84 }
85
86 #[test]
87 fn inline_dispatcher_defaults_to_none() {
88 let ctx = test_context();
89 assert!(ctx.inline_dispatcher().is_none());
90 }
91
92 #[tokio::test]
93 async fn inline_dispatcher_set_then_get_roundtrip() {
94 let ctx = test_context();
95 ctx.set_inline_dispatcher(Arc::new(IdentityDispatcher));
96
97 let dispatcher = ctx.inline_dispatcher().expect("dispatcher must be set");
98 let clone = ctx.clone();
100 assert!(clone.inline_dispatcher().is_some());
101
102 let sent = test_exchange();
103 let correlation_id = sent.correlation_id().to_string();
104 let returned = dispatcher
105 .dispatch(sent)
106 .await
107 .expect("dispatch must be Ok");
108 assert_eq!(returned.correlation_id(), correlation_id);
109 assert!(!returned.has_error());
110 }
111
112 #[tokio::test]
113 async fn inline_dispatcher_second_set_keeps_first() {
114 let ctx = test_context();
115 ctx.set_inline_dispatcher(Arc::new(TagDispatcher("A")));
116 ctx.set_inline_dispatcher(Arc::new(TagDispatcher("B")));
117
118 let dispatcher = ctx.inline_dispatcher().expect("dispatcher must be set");
119 let returned = dispatcher
120 .dispatch(test_exchange())
121 .await
122 .expect("dispatch must be Ok");
123 assert_eq!(
124 returned.property("dispatcher").and_then(|v| v.as_str()),
125 Some("A")
126 );
127 }
128}