use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn stale_snapshot_expiry_suspends_then_converges_with_replay() -> TestResult {
let backing = Arc::new(StaleReadStore::new(3));
let store: Arc<dyn EventStore> = Arc::clone(&backing) as Arc<dyn EventStore>;
let (workflow_id, run_id) = seed_pending_activity_then_deadline(&store, 7).await?;
let harness =
AwaitHarness::over_store(Arc::clone(&store), workflow_id.clone(), run_id.clone()).await?;
harness.install_fresh_read_bridge();
backing.set_stale_target(&workflow_id, 1);
harness.arm_live_scope(7);
assert_eq!(
harness.step(),
Ok(ActivityAwaitStep::Suspend),
"a snapshot lacking both events must park, not branch"
);
assert_eq!(harness.history_len().await?, 4);
assert_eq!(
harness.step(),
Ok(ActivityAwaitStep::Failed(
"timeout:deadline expired".to_owned()
))
);
let history = harness.store.read_history(&workflow_id).await?;
assert!(
matches!(history.last(), Some(Event::ActivityFailed { .. })),
"the timeout branch must be recorded durably: {history:#?}"
);
let history_len = history.len();
harness.shutdown()?;
let replay = AwaitHarness::over_store(store, workflow_id, run_id).await?;
replay.arm_replayed_expired_scope(7);
assert_eq!(
replay.step(),
Ok(ActivityAwaitStep::Failed(
"timeout:deadline expired".to_owned()
)),
"replay must take the same branch as the converged live run"
);
assert_eq!(replay.history_len().await?, history_len);
replay.shutdown()
}
#[tokio::test(flavor = "multi_thread")]
async fn delivered_completion_settles_durably_ahead_of_snapshot_expiry() -> TestResult {
let backing = Arc::new(StaleReadStore::new(0));
let store: Arc<dyn EventStore> = Arc::clone(&backing) as Arc<dyn EventStore>;
let (workflow_id, run_id) = seed_pending_activity_then_deadline(&store, 7).await?;
let harness =
AwaitHarness::over_store(Arc::clone(&store), workflow_id.clone(), run_id.clone()).await?;
harness.arm_live_scope(7);
harness.runtime.deliver_activity_completion_message(
harness.pid,
"activity:0",
r#""r0""#.to_owned(),
)?;
assert_eq!(
harness.step(),
Ok(ActivityAwaitStep::Completed(br#""r0""#.to_vec()))
);
let history = harness.store.read_history(&workflow_id).await?;
assert!(
matches!(history.last(), Some(Event::ActivityCompleted { .. })),
"the completion must be recorded durably: {history:#?}"
);
let history_len = history.len();
harness.shutdown()?;
let replay = AwaitHarness::over_store(store, workflow_id, run_id).await?;
replay.arm_replayed_expired_scope(7);
assert_eq!(
replay.step(),
Ok(ActivityAwaitStep::Completed(br#""r0""#.to_vec())),
"replay must resolve the recorded completion, not re-derive the race"
);
assert_eq!(replay.history_len().await?, history_len);
replay.shutdown()
}
#[tokio::test(flavor = "multi_thread")]
async fn poisoned_take_fails_typed_and_monitor_drains_retained_state() -> TestResult {
let backing = Arc::new(StaleReadStore::new(0));
let store: Arc<dyn EventStore> = Arc::clone(&backing) as Arc<dyn EventStore>;
let (workflow_id, run_id) = seed_pending_activity_then_deadline(&store, 7).await?;
let harness = AwaitHarness::over_store(store, workflow_id, run_id).await?;
let baseline = harness.runtime.activity_delivery_gate_count();
harness
.runtime
.deliver_activity_completion_message_with_attempt(
harness.pid,
"activity:0",
r#""retained""#.to_owned(),
Some(3),
)?;
assert_eq!(harness.runtime.retained_activity_completions(), 1);
assert_eq!(
harness.runtime.retained_activity_attempt_count_for_test(),
1
);
harness
.runtime
.force_activity_delivery_poison_for_test(harness.pid)?;
let step = harness.step_typed();
assert!(matches!(
step,
Err(EngineError::ActivityDeliveryPoisoned { process_id })
if process_id == harness.pid
));
assert_eq!(
harness.history_len().await?,
4,
"poison must neither suspend nor record a fabricated attempt-one completion"
);
let (monitor_sender, monitor_receiver) = std::sync::mpsc::channel();
harness
.runtime
.monitor_process_for_test(harness.pid, move |outcome| {
if monitor_sender.send(outcome).is_err() {
tracing::error!("poisoned-take monitor receiver dropped");
}
})?;
harness.runtime.cancel_pid(harness.pid)?;
let monitored = monitor_receiver.recv_timeout(std::time::Duration::from_secs(10))?;
assert!(matches!(
monitored,
Err(EngineError::ActivityDeliveryPoisoned { process_id })
if process_id == harness.pid
));
assert_eq!(harness.runtime.retained_activity_completions(), 0);
assert_eq!(
harness.runtime.retained_activity_attempt_count_for_test(),
0
);
assert_eq!(harness.runtime.activity_delivery_gate_count(), baseline);
harness.shutdown()
}
#[tokio::test(flavor = "multi_thread")]
async fn awaited_terminal_records_the_noted_final_attempt() -> TestResult {
let backing = Arc::new(StaleReadStore::new(0));
let store: Arc<dyn EventStore> = Arc::clone(&backing) as Arc<dyn EventStore>;
let (workflow_id, run_id) = seed_pending_activity_then_deadline(&store, 7).await?;
let harness = AwaitHarness::over_store(Arc::clone(&store), workflow_id.clone(), run_id).await?;
harness
.runtime
.deliver_activity_failure_message_with_attempt(
harness.pid,
"activity:0",
"retryable:reset three".to_owned(),
Some(3),
)?;
assert_eq!(
harness.step(),
Ok(ActivityAwaitStep::Failed(
"retryable:reset three".to_owned()
))
);
let history = store.read_history(&workflow_id).await?;
assert!(
matches!(
history.last(),
Some(Event::ActivityFailed { attempt: 3, error, .. })
if error.message == "retryable:reset three"
),
"the recorded terminal must carry the noted final attempt: {history:#?}"
);
harness.shutdown()
}