use super::app::{Msg, Sent};
use tokio::sync::mpsc;
pub(super) async fn send_batch(requests: mpsc::Sender<Sent>, batch: Vec<Sent>) -> Msg {
for sent in batch {
if let Err(mpsc::error::SendError(sent)) = requests.send(sent).await {
return Msg::BatchSent { unsent: Some(sent) };
}
}
Msg::BatchSent { unsent: None }
}
pub(super) fn enable_refusal_message(
err: &crate::commands::dogs::EnableRefusal,
name: &str,
) -> String {
use crate::commands::dogs::EnableRefusal;
match err {
EnableRefusal::Config(err) => err.to_string(),
EnableRefusal::UnknownDog { .. } => {
format!("{name} is not a dog shep knows about")
}
}
}
#[cfg(test)]
mod tests {
use super::super::app::{Msg, Sent};
use tokio::sync::mpsc;
use super::*;
#[tokio::test]
async fn send_batch_delivers_every_entry_past_a_full_channel() {
let (request_tx, mut request_rx) = mpsc::channel(2);
let batch: Vec<Sent> = (0..5)
.map(|n| Sent::SheepConfig {
name: format!("sheep-{n}"),
})
.collect();
let expected = batch.clone();
let handle = tokio::spawn(send_batch(request_tx, batch));
let mut received = Vec::new();
for _ in 0..5 {
received.push(
request_rx
.recv()
.await
.expect("the batch is still arriving"),
);
}
assert_eq!(
received, expected,
"every entry landed, in the order it was filed"
);
let msg = handle.await.expect("send_batch does not panic");
assert!(matches!(msg, Msg::BatchSent { unsent: None }), "{msg:?}");
}
#[tokio::test]
async fn send_batch_reports_the_first_casualty_once_the_channel_is_closed() {
let (request_tx, request_rx) = mpsc::channel(2);
drop(request_rx);
let batch = vec![Sent::SheepConfig {
name: "sheep-0".to_string(),
}];
let Msg::BatchSent { unsent } = send_batch(request_tx, batch).await else {
panic!("wanted a BatchSent");
};
assert_eq!(
unsent,
Some(Sent::SheepConfig {
name: "sheep-0".to_string()
})
);
}
}