#![expect(clippy::expect_used, reason = "test harness: a panic here names the setup or assertion failure precisely")]
use super::common::*;
use backbone_mailing::application::service::mailing_write_service::{
MailingSendConfig, MailingUpsertCommand, MailingWriteService,
};
use backbone_mailing::infrastructure::persistence::trace_repository::TraceRepository;
use uuid::Uuid;
fn audience_cmd(audience_id: Uuid, subject: &str) -> MailingUpsertCommand {
MailingUpsertCommand {
subject: subject.into(),
preview: None,
body_html: format!("<p>{subject}</p>"),
email_from: "probe@example.id".into(),
reply_to: None,
mailing_domain_raw: serde_json::json!([
["mailing_audience_id", "=", audience_id.to_string()]
]),
target_model: "mailing_contact".into(),
schedule_type: "immediate".into(),
schedule_date: None,
use_exclusion_list: true,
campaign_id: None,
source_id: None,
ab_test_id: None,
ab_testing_enabled: false,
ab_testing_pc: 0,
}
}
fn cfg(claim_batch: i64, recipients_per_pass: i64) -> MailingSendConfig {
MailingSendConfig {
claim_batch,
recipients_per_pass,
mail_enqueue_batch: 10,
inter_batch_delay_ms: 0,
max_enqueues_per_second: None,
resolver_hard_cap: 100_000,
}
}
async fn duplicate_pairs(pool: &sqlx::PgPool) -> i64 {
count(
pool,
r#"SELECT count(*) FROM (
SELECT mailing_id, recipient_id
FROM mailing.mailing_traces
WHERE trace_status <> 'cancel'
AND (metadata->>'deleted_at') IS NULL
GROUP BY mailing_id, recipient_id
HAVING count(*) > 1
) d"#,
)
.await
}
async fn distinct_reached(pool: &sqlx::PgPool) -> i64 {
count(
pool,
r#"SELECT count(DISTINCT (mailing_id, recipient_id))
FROM mailing.mailing_traces
WHERE trace_status <> 'cancel'
AND (metadata->>'deleted_at') IS NULL"#,
)
.await
}
#[tokio::test]
async fn concurrent_workers_claim_disjoint_sets_and_complete_everything() {
let Some(db) = TestDb::new("two").await else {
return skipped("two");
};
const AUDIENCES: usize = 6;
const MEMBERS: usize = 25;
let mut mailing_ids = Vec::with_capacity(AUDIENCES);
for i in 0..AUDIENCES {
let (audience_id, _) =
seed_audience(&db.pool, &format!("two{i}"), MEMBERS).await;
let engine = MailingWriteService::new(db.pool.clone());
let id = engine
.create_mailing(&audience_cmd(audience_id, &format!("Probe {i}")))
.await
.expect("create");
engine.launch(id, "immediate", None).await.expect("launch");
mailing_ids.push(id);
}
let worker_a = MailingWriteService::new(db.pool.clone()).with_send_config(cfg(3, 500));
let worker_b = MailingWriteService::new(db.pool.clone()).with_send_config(cfg(3, 500));
let (a, b) = tokio::join!(worker_a.send_queue_sweep(), worker_b.send_queue_sweep());
let (a, b) = (a.expect("worker A"), b.expect("worker B"));
assert_eq!(a.claimed, 3, "worker A claimed {}", a.claimed);
assert_eq!(b.claimed, 3, "worker B claimed {}", b.claimed);
assert_eq!(a.completed + b.completed, AUDIENCES, "all six completed");
let per_mailing: Vec<(Uuid, i64)> = sqlx::query_as(
r#"SELECT mailing_id, count(*) FROM mailing.mailing_traces
WHERE trace_status <> 'cancel' AND (metadata->>'deleted_at') IS NULL
GROUP BY 1"#,
)
.fetch_all(&db.pool)
.await
.expect("per-mailing grouping");
assert_eq!(per_mailing.len(), AUDIENCES);
for (_mid, n) in &per_mailing {
assert_eq!(*n, MEMBERS as i64, "each mailing reached its 25 members");
}
assert_eq!(duplicate_pairs(&db.pool).await, 0, "no duplicate pairs");
assert_eq!(
distinct_reached(&db.pool).await,
(AUDIENCES * MEMBERS) as i64
);
assert_eq!(
a.minted + b.minted,
AUDIENCES * MEMBERS,
"minted counts sum to the exact audience"
);
assert_eq!(
count(&db.pool, "SELECT count(*) FROM messaging.mails").await,
(AUDIENCES * MEMBERS) as i64
);
assert_eq!(
count(&db.pool, "SELECT count(*) FROM messaging.mail_messages").await,
(AUDIENCES * MEMBERS) as i64
);
let states: Vec<(Uuid, String)> = sqlx::query_as(
r#"SELECT id, state::text FROM mailing.mailings ORDER BY id"#,
)
.fetch_all(&db.pool)
.await
.expect("states");
assert!(states.iter().all(|(_, s)| s == "done"));
db.dispose().await;
}
#[tokio::test]
async fn overlapping_workers_on_one_mailing_never_double_send() {
let Some(db) = TestDb::new("ovl").await else {
return skipped("ovl");
};
const AUDIENCE: usize = 60;
const PASS: usize = 25;
let (audience_id, emails) = seed_audience(&db.pool, "ovl", AUDIENCE).await;
let engine = MailingWriteService::new(db.pool.clone());
let id = engine
.create_mailing(&audience_cmd(audience_id, "Overlap probe"))
.await
.expect("create");
engine.launch(id, "immediate", None).await.expect("launch");
let solo = MailingWriteService::new(db.pool.clone()).with_send_config(cfg(16, PASS as i64));
let first = solo.send_queue_sweep().await.expect("pass 1");
assert_eq!(first.claimed, 1);
assert_eq!(first.minted, PASS, "the pass budget bounds the batch");
assert_eq!(first.still_sending, 1);
assert_eq!(first.completed, 0);
assert_eq!(duplicate_pairs(&db.pool).await, 0);
assert_eq!(distinct_reached(&db.pool).await, PASS as i64);
let worker_a = MailingWriteService::new(db.pool.clone()).with_send_config(cfg(16, PASS as i64));
let worker_b = MailingWriteService::new(db.pool.clone()).with_send_config(cfg(16, PASS as i64));
let (a, b) = tokio::join!(worker_a.send_queue_sweep(), worker_b.send_queue_sweep());
let (a, b) = (a.expect("overlap A"), b.expect("overlap B"));
let reached = distinct_reached(&db.pool).await;
assert!(
((2 * PASS) as i64..=(AUDIENCE as i64)).contains(&reached),
"union after the overlap round was {reached}"
);
assert_eq!(
duplicate_pairs(&db.pool).await,
0,
"the fence held: no (mailing, recipient) pair doubled"
);
assert_eq!(
a.minted + b.minted,
reached as usize - PASS,
"minted counts exactly account for the new rows"
);
let mut rounds = 0;
loop {
let out = solo.send_queue_sweep().await.expect("resume sweep");
rounds += 1;
if out.completed == 1 || out.claimed == 0 || rounds > 6 {
break;
}
}
assert_eq!(
distinct_reached(&db.pool).await,
AUDIENCE as i64,
"every member reached exactly once"
);
assert_eq!(duplicate_pairs(&db.pool).await, 0);
let state: String =
sqlx::query_scalar("SELECT state::text FROM mailing.mailings WHERE id = $1")
.bind(id)
.fetch_one(&db.pool)
.await
.expect("state");
assert_eq!(state, "done");
assert_eq!(
count(&db.pool, "SELECT count(*) FROM messaging.mails").await,
AUDIENCE as i64,
"one mail row per member, no duplicates from the overlap"
);
assert_eq!(
count(
&db.pool,
r#"SELECT count(*) FROM mailing.mailing_traces t
WHERE t.trace_status <> 'cancel'
AND (t.metadata->>'deleted_at') IS NULL
AND t.mail_id IS NULL"#
)
.await,
0,
"every live trace carries its mail row"
);
let _ = emails;
db.dispose().await;
}
#[tokio::test]
async fn orphan_repair_heals_aged_gaps_and_leaves_live_windows_alone() {
let Some(db) = TestDb::new("fix").await else {
return skipped("fix");
};
let engine = MailingWriteService::new(db.pool.clone());
let mut mailings = Vec::new();
for subject in ["Aged gap", "Live window"] {
let (audience_id, _) = seed_audience(&db.pool, subject, 0).await;
let id = engine
.create_mailing(&audience_cmd(audience_id, subject))
.await
.expect("create");
let mut tx = db.pool.begin().await.expect("tx");
let trace_id = Uuid::new_v4();
TraceRepository::mint_trace(
&mut tx,
trace_id,
id,
None,
"mailing_contact",
Uuid::new_v4(),
&format!("{subject}@example.id"),
"outgoing",
None,
false,
)
.await
.expect("orphan mint");
tx.commit().await.expect("commit");
engine.launch(id, "immediate", None).await.expect("launch");
mailings.push((id, trace_id, subject));
}
sqlx::query(
r#"UPDATE mailing.mailing_traces
SET metadata = jsonb_build_object('created_at',
to_jsonb(now() - interval '10 minutes'))
WHERE id = $1"#,
)
.bind(mailings[0].1)
.execute(&db.pool)
.await
.expect("backdate");
let out = engine.send_queue_sweep().await.expect("sweep");
assert_eq!(out.repaired, 1, "only the aged gap is repaired");
assert_eq!(out.completed_empty, 2);
let aged_mail: Option<Uuid> =
sqlx::query_scalar("SELECT mail_id FROM mailing.mailing_traces WHERE id = $1")
.bind(mailings[0].1)
.fetch_one(&db.pool)
.await
.expect("aged row");
assert!(aged_mail.is_some(), "the crash gap healed: enqueue + attach ran");
let fresh_mail: Option<Uuid> =
sqlx::query_scalar("SELECT mail_id FROM mailing.mailing_traces WHERE id = $1")
.bind(mailings[1].1)
.fetch_one(&db.pool)
.await
.expect("fresh row");
assert!(
fresh_mail.is_none(),
"the live mint→enqueue window was NOT double-enqueued"
);
assert_eq!(
count(&db.pool, "SELECT count(*) FROM messaging.mails").await,
1,
"exactly one mail row — no duplicate send at the seam"
);
db.dispose().await;
}