use std::collections::BTreeMap;
use std::time::Duration;
use camel_api::Value;
use futures::future::BoxFuture;
use crate::adapters::{
FakeAdapter, IncomingMessage, PartnerAdapter, PartnerRouter, ReceiveError, TransportError,
};
struct BoundStub {
authority: Option<String>,
}
impl PartnerAdapter for BoundStub {
fn receive<'a>(
&'a self,
_lane_key: &'a str,
_source_uri: &'a str,
_deadline: Duration,
) -> BoxFuture<'a, Result<IncomingMessage, ReceiveError>> {
Box::pin(async {
Err(ReceiveError::Transport(TransportError::Other {
message: "the stub never delivers".to_string(),
}))
})
}
fn bound_authority(&self) -> Option<String> {
self.authority.clone()
}
}
fn router_with(entries: &[(&str, &str)]) -> PartnerRouter {
PartnerRouter::new(
entries
.iter()
.map(|(key, authority)| {
(
key.to_string(),
Box::new(BoundStub {
authority: Some(authority.to_string()),
}) as Box<dyn PartnerAdapter>,
)
})
.collect(),
)
}
#[test]
fn wire_target_rewrites_authority_only() {
let router = router_with(&[("http://127.0.0.1:0/orders", "127.0.0.1:45678")]);
assert_eq!(
router.wire_target("http://127.0.0.1:0/orders", "http://127.0.0.1:0/orders?x=1"),
Some("http://127.0.0.1:45678/orders?x=1".to_string())
);
}
#[test]
fn wire_target_passthrough_when_not_partner() {
let router = router_with(&[("http://127.0.0.1:0/orders", "127.0.0.1:45678")]);
assert_eq!(
router.wire_target("http://10.9.8.7:1/nowhere", "http://10.9.8.7:1/nowhere"),
None
);
}
#[test]
fn wire_target_matches_bound_authority() {
let router = router_with(&[("http://127.0.0.1:0/orders", "127.0.0.1:45678")]);
assert_eq!(
router.wire_target("http://${PARTNER}/orders", "http://127.0.0.1:45678/orders"),
Some("http://127.0.0.1:45678/orders".to_string())
);
}
#[test]
fn lane_key_for_prefers_declared_key() {
let router = router_with(&[("http://127.0.0.1:0/orders", "127.0.0.1:45678")]);
assert_eq!(
router.lane_key_for("http://127.0.0.1:0/orders", "http://127.0.0.1:45678/orders"),
Some("http://127.0.0.1:0/orders".to_string())
);
}
#[test]
fn lane_key_for_resolves_dynamic_ref() {
let router = router_with(&[("http://127.0.0.1:0/orders", "127.0.0.1:45678")]);
assert_eq!(
router.lane_key_for("http://${PARTNER}/orders", "http://127.0.0.1:45678/orders"),
Some("http://127.0.0.1:0/orders".to_string())
);
}
#[tokio::test]
async fn incoming_message_carries_arrival_instant() {
let fake = FakeAdapter::scripted(vec![IncomingMessage {
body: Value::String("queued".to_string()),
headers: BTreeMap::new(),
status: None,
method: None,
path: None,
arrival: std::time::Instant::now(),
}]);
let router = PartnerRouter::new(BTreeMap::from([(
"partner://fake".to_string(),
Box::new(fake) as Box<dyn PartnerAdapter>,
)]));
tokio::time::sleep(Duration::from_millis(50)).await;
let message = router
.receive("partner://fake", "partner://fake", Duration::from_secs(1))
.await
.expect("the scripted message must arrive");
assert!(
message.arrival.elapsed() >= Duration::from_millis(50),
"arrival must be stamped at construction (the wire), not at \
receive consumption: elapsed {:?}",
message.arrival.elapsed()
);
assert!(
message.arrival.elapsed() < Duration::from_secs(5),
"arrival sanity bound: the message was stamped milliseconds ago"
);
}