#![allow(clippy::expect_used, clippy::unwrap_used)]
mod support;
use std::error::Error;
use std::time::{Duration, Instant};
use frame_conv::{ConversationHandle, CursorCommit, SubscriptionItem};
use serde::{Deserialize, Serialize};
use support::{FileStore, QUANTUM, RunningServer, attachment, store_dir};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct ContactAdded {
name: String,
total: u32,
}
#[test]
fn slow_subscriber_surfaces_nothing_and_drain_is_complete() -> Result<(), Box<dyn Error>> {
let server = RunningServer::start()?;
let stores = store_dir("backpressure")?;
let (mut publisher, _pub_grant) = ConversationHandle::open(
&attachment(server.endpoint()),
FileStore::new(stores.join("publisher.lpcr")),
)?;
let conversation = publisher.conversation();
let (mut subscriber, _sub_grant) = ConversationHandle::join(
&attachment(server.endpoint()),
conversation,
FileStore::new(stores.join("subscriber.lpcr")),
)?;
let mut receipts = Vec::new();
for total in 1..=12_u32 {
let receipt = publisher.publish_event(&ContactAdded {
name: format!("contact-{total}"),
total,
})?;
receipts.push(receipt.seq);
}
assert_eq!(receipts.len(), 12);
assert!(
receipts
.windows(2)
.all(|pair| pair[1].value() == pair[0].value() + 1),
"all 12 commits must occupy contiguous sequences: {receipts:?}"
);
let publisher_counters = publisher.anomaly_counters();
assert_eq!(publisher_counters.unexpected_frames, 0);
assert_eq!(publisher_counters.gaps, 0);
let mut drained = Vec::new();
let until = Instant::now() + 4 * QUANTUM;
while drained.len() < 12 && Instant::now() < until {
if let Some(SubscriptionItem::Event { body, seq, .. }) =
subscriber.next_event::<ContactAdded>(Duration::from_secs(1))?
{
drained.push((body.total, seq));
}
}
let expected: Vec<(u32, frame_conv::ConversationSeq)> = receipts
.iter()
.enumerate()
.map(|(index, seq)| (u32::try_from(index).unwrap_or(0) + 1, *seq))
.collect();
assert_eq!(
drained, expected,
"the drain must be complete, ordered, at the committed sequences"
);
assert_eq!(subscriber.anomaly_counters().gaps, 0);
let last = expected[11].1;
let commit = subscriber.commit_cursor(last)?;
assert!(
matches!(commit, CursorCommit::Committed { .. }),
"the post-drain ack must commit: {commit:?}"
);
std::fs::remove_dir_all(&stores)?;
server.shutdown()?;
Ok(())
}