use std::sync::Arc;
use haematite::{Database, DatabaseConfig, EventStore};
use liminal::durability::{DurableStore, HaematiteStore};
use liminal::protocol::{CausalContext, MessageEnvelope, SchemaId};
use tempfile::TempDir;
use super::services::{ConnectionServices, LiminalConnectionServices};
use crate::config::types::{ChannelDef, ServerConfig};
fn disk_store() -> Result<(Arc<dyn DurableStore>, TempDir), Box<dyn std::error::Error>> {
let dir = tempfile::tempdir()?;
let database = Database::create(DatabaseConfig {
data_dir: dir.path().join("db"),
shard_count: 4,
distributed: None,
executor_threads: None,
node_cache_budget: Some(haematite::NodeCacheBudget::Unlimited),
})?;
let store: Arc<dyn DurableStore> =
Arc::new(HaematiteStore::new(Arc::new(EventStore::new(database))));
Ok((store, dir))
}
fn mixed_channels_config() -> Result<ServerConfig, Box<dyn std::error::Error>> {
Ok(ServerConfig {
listen_address: "127.0.0.1:0".parse()?,
health_listen_address: "127.0.0.1:0".parse()?,
drain_timeout_ms: 30_000,
channels: vec![
ChannelDef {
name: "orders".to_owned(),
schema_ref: None,
durable: true,
loaded_schema: None,
},
ChannelDef {
name: "events".to_owned(),
schema_ref: None,
durable: false,
loaded_schema: None,
},
],
routing_rules: Vec::new(),
persistence_path: None,
cluster: None,
auth: None,
services: crate::config::types::ServicesConfig::default(),
limits: crate::config::types::LimitsConfig::default(),
participant: None,
websocket: None,
})
}
fn envelope(payload: &[u8]) -> MessageEnvelope {
MessageEnvelope::new(
SchemaId::new([0_u8; SchemaId::WIRE_LEN]),
CausalContext::independent(),
payload.to_vec(),
)
}
fn delivered(
services: &LiminalConnectionServices,
channel: &str,
key: &str,
payload: &[u8],
) -> Result<bool, Box<dyn std::error::Error>> {
let subscription = services.subscribe_handle_for_test(channel)?;
services.publish(channel, &envelope(payload), Some(key))?;
let received = subscription.try_next()?.is_some();
drop(subscription);
Ok(received)
}
#[test]
fn ephemeral_dedup_dies_with_the_incarnation_while_durable_dedup_survives()
-> Result<(), Box<dyn std::error::Error>> {
let (store, _dir) = disk_store()?;
let config = mixed_channels_config()?;
{
let services =
LiminalConnectionServices::from_config_with_store(&config, Arc::clone(&store))?;
assert!(
delivered(&services, "events", "shared-key", br#"{"n":1}"#)?,
"a first keyed publish to an ephemeral channel is delivered"
);
assert!(
!delivered(&services, "events", "shared-key", br#"{"n":1}"#)?,
"a SAME-INCARNATION retry is suppressed: the bus still owns the message"
);
assert!(
delivered(&services, "orders", "shared-key", br#"{"n":1}"#)?,
"a first keyed publish to a durable channel is delivered"
);
assert!(
!delivered(&services, "orders", "shared-key", br#"{"n":1}"#)?,
"a same-incarnation durable retry is suppressed too"
);
}
let services = LiminalConnectionServices::from_config_with_store(&config, Arc::clone(&store))?;
assert!(
delivered(&services, "events", "shared-key", br#"{"n":1}"#)?,
"EPHEMERAL: the incarnation-scoped receipt died with its message, so the \
producer's retry re-claims and re-delivers — at-least-once, which is \
exactly ephemeral's contract"
);
assert!(
!delivered(&services, "orders", "shared-key", br#"{"n":1}"#)?,
"DURABLE: the message survived, so the surviving receipt is truthful and \
must keep suppressing"
);
Ok(())
}
#[test]
fn a_keyed_publish_dropped_by_every_subscriber_releases_its_claim()
-> Result<(), Box<dyn std::error::Error>> {
let (store, _dir) = disk_store()?;
let config = mixed_channels_config()?;
let services = LiminalConnectionServices::from_config_with_store(&config, store)?;
let starved = services.subscribe_handle_for_test_with_install(
"events",
Some(liminal::channel::InboxInstall {
budget: liminal::channel::ConnectionInboxBudget::new(1),
depth_cap: usize::MAX,
notifier: None,
capacity: Some(liminal::pressure::ConsumerCapacity::new(64, 64)?),
}),
)?;
let dropped = services.publish("events", &envelope(br#"{"n":1}"#), Some("dropped-key"))?;
assert!(
!dropped.delivered,
"the fixture must actually drop it: a delivered publish proves nothing"
);
assert!(
starved.is_overflowed(),
"and it must be dropped by the §5 door this pin is about"
);
let healthy = services.subscribe_handle_for_test("events")?;
services.publish("events", &envelope(br#"{"n":1}"#), Some("dropped-key"))?;
assert!(
healthy.try_next()?.is_some(),
"the dropped publish released its claim, so the retry re-claims and \
delivers; a completed receipt would have suppressed it forever"
);
let kept = services.subscribe_handle_for_test("events")?;
services.publish("events", &envelope(br#"{"n":2}"#), Some("kept-key"))?;
assert!(kept.try_next()?.is_some(), "the first keyed publish lands");
services.publish("events", &envelope(br#"{"n":2}"#), Some("kept-key"))?;
assert!(
kept.try_next()?.is_none(),
"an admitted publish completed its receipt, so the retry is suppressed"
);
drop(starved);
Ok(())
}
#[test]
fn a_keyed_publish_dropped_on_a_durable_channel_releases_its_claim()
-> Result<(), Box<dyn std::error::Error>> {
let (store, _dir) = disk_store()?;
let config = mixed_channels_config()?;
let services = LiminalConnectionServices::from_config_with_store(&config, store)?;
let starved = services.subscribe_handle_for_test_with_install(
"orders",
Some(liminal::channel::InboxInstall {
budget: liminal::channel::ConnectionInboxBudget::new(1),
depth_cap: usize::MAX,
notifier: None,
capacity: Some(liminal::pressure::ConsumerCapacity::new(64, 64)?),
}),
)?;
let dropped = services.publish("orders", &envelope(br#"{"n":1}"#), Some("dropped-key"))?;
assert!(
!dropped.delivered,
"the fixture must actually drop it: a delivered publish proves nothing"
);
assert!(
starved.is_overflowed(),
"and it must be dropped by the §5 door this pin is about"
);
let healthy = services.subscribe_handle_for_test("orders")?;
services.publish("orders", &envelope(br#"{"n":1}"#), Some("dropped-key"))?;
assert!(
healthy.try_next()?.is_some(),
"the dropped publish released its claim, so the retry re-claims and \
delivers; a completed receipt would have suppressed it forever"
);
let kept = services.subscribe_handle_for_test("orders")?;
services.publish("orders", &envelope(br#"{"n":2}"#), Some("kept-key"))?;
assert!(kept.try_next()?.is_some(), "the first keyed publish lands");
services.publish("orders", &envelope(br#"{"n":2}"#), Some("kept-key"))?;
assert!(
kept.try_next()?.is_none(),
"an admitted publish completed its receipt, so the retry is suppressed"
);
drop(starved);
Ok(())
}
#[test]
fn the_two_namespaces_do_not_share_a_key() -> Result<(), Box<dyn std::error::Error>> {
let (store, _dir) = disk_store()?;
let config = mixed_channels_config()?;
let services = LiminalConnectionServices::from_config_with_store(&config, store)?;
assert!(
delivered(&services, "events", "same-key", br#"{"n":1}"#)?,
"the ephemeral publish claims the key in ITS namespace"
);
assert!(
delivered(&services, "orders", "same-key", br#"{"n":1}"#)?,
"the durable publish claims the SAME key in its own namespace, uncontested"
);
Ok(())
}