#![cfg(feature = "testing")]
use std::future::{Future, ready};
use std::time::Duration;
use ruststream::runtime::{Context, Handle, subscriber};
use ruststream::testing::TestApp;
use ruststream_fred::prelude::*;
use serde::{Deserialize, Serialize};
const URL: &str = "redis://localhost:6379";
const BLOCK: Duration = Duration::from_millis(50);
#[derive(Debug, Deserialize, Outgoing, PartialEq, Serialize)]
struct Order {
id: u64,
}
#[subscriber(
RedisStream::new("windowed").group("workers"),
start_at(RedisGroupPosition::beginning())
)]
async fn windowed(order: &Order) -> HandlerOutcome {
let _ = order.id;
HandlerOutcome::ack()
}
struct TakeOrder;
impl Handle<Order> for TakeOrder {
fn handle(
&self,
order: &Order,
_outs: &(),
_ctx: &mut Context<'_>,
) -> impl Future<Output = Result<(), HandlerOutcome>> {
let _ = order.id;
ready(Ok(()))
}
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn block_follows_start_at() {
let app = RustStream::new(AppInfo::new("svc", "0.1.0")).with_broker(
RedisBroker::standalone(URL),
|b| {
b.include(windowed.pipeline().block(BLOCK));
b.include(
subscriber(RedisStream::new("manual").group("workers"), TakeOrder)
.undocumented()
.build()
.start_at(RedisGroupPosition::beginning())
.block(BLOCK),
);
b.include(
subscriber(
RedisStream::new("manual.windowed").group("workers"),
TakeOrder,
)
.undocumented()
.build()
.start_at(RedisGroupPosition::beginning())
.pipeline()
.atomic()
.block(BLOCK),
);
},
);
let tb = TestApp::start(app).await.expect("start");
let keys = ["windowed", "manual", "manual.windowed"];
for (id, key) in (1..).zip(keys) {
tb.broker::<RedisBroker>()
.message(&Order { id })
.to(key)
.publish()
.await
.expect("publish");
}
for (id, key) in (1..).zip(keys) {
tb.broker::<RedisBroker>()
.subscriber(key)
.assert_called_once()
.with(&Order { id })
.settled(HandlerOutcome::ack());
}
tb.shutdown().await.expect("shutdown");
}