use std::future::Future;
use std::pin::Pin;
use camel_api::{CamelError, Exchange};
pub trait InlineRouteDispatcher: Send + Sync + 'static {
fn dispatch(
&self,
exchange: Exchange,
) -> Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send + 'static>>;
}
#[cfg(test)]
mod tests {
use std::pin::Pin;
use std::sync::Arc;
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;
use super::InlineRouteDispatcher;
use crate::consumer::{ConsumerContext, ExchangeEnvelope};
use camel_api::{Exchange, Message};
fn test_context() -> ConsumerContext {
let (tx, _rx) = mpsc::channel::<ExchangeEnvelope>(1);
ConsumerContext::new(tx, CancellationToken::new(), "test-route".to_string())
}
fn test_exchange() -> Exchange {
Exchange::new(Message::new("payload"))
}
struct IdentityDispatcher;
impl InlineRouteDispatcher for IdentityDispatcher {
fn dispatch(
&self,
exchange: Exchange,
) -> Pin<Box<dyn Future<Output = Result<Exchange, camel_api::CamelError>> + Send + 'static>>
{
Box::pin(async move { Ok(exchange) })
}
}
struct TagDispatcher(&'static str);
impl InlineRouteDispatcher for TagDispatcher {
fn dispatch(
&self,
mut exchange: Exchange,
) -> Pin<Box<dyn Future<Output = Result<Exchange, camel_api::CamelError>> + Send + 'static>>
{
let tag = self.0;
Box::pin(async move {
exchange.set_property("dispatcher", tag);
Ok(exchange)
})
}
}
#[test]
fn inline_dispatcher_defaults_to_none() {
let ctx = test_context();
assert!(ctx.inline_dispatcher().is_none());
}
#[tokio::test]
async fn inline_dispatcher_set_then_get_roundtrip() {
let ctx = test_context();
ctx.set_inline_dispatcher(Arc::new(IdentityDispatcher));
let dispatcher = ctx.inline_dispatcher().expect("dispatcher must be set");
let clone = ctx.clone();
assert!(clone.inline_dispatcher().is_some());
let sent = test_exchange();
let correlation_id = sent.correlation_id().to_string();
let returned = dispatcher
.dispatch(sent)
.await
.expect("dispatch must be Ok");
assert_eq!(returned.correlation_id(), correlation_id);
assert!(!returned.has_error());
}
#[tokio::test]
async fn inline_dispatcher_second_set_keeps_first() {
let ctx = test_context();
ctx.set_inline_dispatcher(Arc::new(TagDispatcher("A")));
ctx.set_inline_dispatcher(Arc::new(TagDispatcher("B")));
let dispatcher = ctx.inline_dispatcher().expect("dispatcher must be set");
let returned = dispatcher
.dispatch(test_exchange())
.await
.expect("dispatch must be Ok");
assert_eq!(
returned.property("dispatcher").and_then(|v| v.as_str()),
Some("A")
);
}
}