#![cfg(all(
feature = "memory",
feature = "macros",
feature = "json",
feature = "testing"
))]
use std::num::ParseIntError;
use ruststream::memory::{MemoryBroker, MemoryPosition, Retaining, Retention};
use ruststream::prelude::*;
use ruststream::testing::TestApp;
use serde::{Deserialize, Serialize};
#[derive(Outgoing, Serialize, Deserialize)]
struct Ticket {
label: String,
}
#[subscriber("returns.plain")]
async fn settle_plain(ticket: &Ticket) -> HandlerOutcome {
let _ = &ticket.label;
HandlerOutcome::ack()
}
#[subscriber("returns.unit")]
async fn settle_unit(ticket: &Ticket) {
let _ = &ticket.label;
}
#[subscriber("returns.ok")]
async fn settle_ok(ticket: &Ticket) -> Result<(), HandlerOutcome> {
let _ = &ticket.label;
Ok(())
}
#[subscriber("returns.batch")]
async fn settle_batch(tickets: &[Ticket]) -> Result<(), HandlerOutcome> {
let _ = tickets.len();
Ok(())
}
#[subscriber("returns.parsed")]
async fn settle_parsed(ticket: &Ticket) -> Result<(), ParseIntError> {
let _: u32 = ticket.label.parse()?;
Ok(())
}
#[subscriber("returns.outcome")]
async fn settle_outcome(ticket: &Ticket) -> Result<HandlerOutcome, ParseIntError> {
let count: u32 = ticket.label.parse()?;
if count == 0 {
return Ok(HandlerOutcome::drop());
}
Ok(HandlerOutcome::ack())
}
fn ticket(label: &str) -> Ticket {
Ticket {
label: label.to_owned(),
}
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn every_settling_return_form_acks_a_finished_body() {
let app =
RustStream::new(AppInfo::new("returns", "0.1.0")).with_broker(MemoryBroker::new(), |b| {
b.include(settle_plain);
b.include(settle_unit);
b.include(settle_ok);
});
let tb = TestApp::start(app).await.expect("harness start");
for name in ["returns.plain", "returns.unit", "returns.ok"] {
tb.message(&ticket("7"))
.to(name)
.publish()
.await
.expect("inject");
tb.broker::<MemoryBroker>()
.subscriber(name)
.assert_called_once()
.settled(HandlerOutcome::ack());
}
tb.shutdown().await.expect("graceful shutdown");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn a_batch_body_settles_its_whole_batch() {
let broker = MemoryBroker::retaining(Retention::Messages(nonzero!(8)));
let publisher = broker.publisher();
for label in ["1", "2"] {
publisher
.message(&ticket(label))
.to("returns.batch")
.publish()
.await
.expect("publish");
}
let app = RustStream::new(AppInfo::new("returns", "0.1.0")).with_broker(broker, |b| {
b.include(
settle_batch
.batch(nonzero!(8))
.start_at(MemoryPosition::start()),
);
});
let tb = TestApp::start(app).await.expect("harness start");
tb.settle().await.expect("the replayed batch settles");
tb.broker::<MemoryBroker<Retaining>>()
.subscriber("returns.batch")
.assert_batch_sizes(&[2])
.settled(HandlerOutcome::ack());
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn a_result_returning_body_settles_by_the_arm_it_takes() {
let app =
RustStream::new(AppInfo::new("returns", "0.1.0")).with_broker(MemoryBroker::new(), |b| {
b.include(settle_parsed);
b.include(settle_outcome);
});
let tb = TestApp::start(app).await.expect("harness start");
tb.message(&ticket("not a number"))
.to("returns.parsed")
.publish()
.await
.expect("inject");
tb.broker::<MemoryBroker>()
.subscriber("returns.parsed")
.assert_called_once()
.settled(HandlerOutcome::drop());
tb.message(&ticket("3"))
.to("returns.outcome")
.publish()
.await
.expect("inject");
tb.broker::<MemoryBroker>()
.subscriber("returns.outcome")
.assert_called_once()
.settled(HandlerOutcome::ack());
tb.message(&ticket("0"))
.to("returns.outcome")
.publish()
.await
.expect("inject");
tb.broker::<MemoryBroker>()
.subscriber("returns.outcome")
.assert_called(2)
.settled(HandlerOutcome::drop());
tb.shutdown().await.expect("graceful shutdown");
}