use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn all_stale_snapshot_expiry_suspends_then_converges_with_replay() -> TestResult {
let scope_timer = aion_core::TimerId::anonymous(7);
let backing = Arc::new(crate::runtime::nif_test_stores::StaleReadStore::new(6));
let store: Arc<dyn EventStore> = Arc::clone(&backing) as Arc<dyn EventStore>;
let mut events = pending_batch(&["a", "b"]);
events.push(completed(0, r#""done-a""#));
events.push(scope_deadline_fired(7));
let (workflow_id, run_id) = seed_history(&store, &events).await?;
let harness =
CollectHarness::over_store(Arc::clone(&store), workflow_id.clone(), run_id.clone()).await?;
install_fresh_read_bridge(&harness);
backing.set_stale_target(&workflow_id, 1);
harness
.state
.timeout_scopes
.insert(21, TimeoutScope::live_for_test(harness.pid, scope_timer));
harness
.state
.timeout_scope_stacks
.insert(harness.pid, vec![21]);
let two = specs(&["a", "b"]);
assert_eq!(
harness.step(CollectKind::All, &two),
Ok(CollectStep::Suspend),
"a snapshot lacking the deadline must park, not branch"
);
assert_eq!(harness.cancelled_ordinals().await?, Vec::<u64>::new());
assert_eq!(
harness.step(CollectKind::All, &two),
Ok(CollectStep::ScopeExpired(
"timeout:deadline expired".to_owned()
))
);
assert_eq!(harness.cancelled_ordinals().await?, vec![1]);
assert_eq!(harness.pinned(), None);
let history_len = store.read_history(&workflow_id).await?.len();
harness.shutdown()?;
let replay = CollectHarness::over_store(store, workflow_id, run_id).await?;
replay.state.timeout_scopes.insert(
1,
TimeoutScope::replayed_expired_with_deadline_for_test(
replay.pid,
aion_core::TimerId::anonymous(7),
),
);
replay
.state
.timeout_scope_stacks
.insert(replay.pid, vec![1]);
assert_eq!(
replay.step(CollectKind::All, &two),
Ok(CollectStep::ScopeExpired(
"timeout:deadline expired".to_owned()
)),
"replay must take the same branch as the converged live run"
);
assert_eq!(
replay.store.read_history(&replay.workflow_id).await?.len(),
history_len,
"replay must append nothing"
);
replay.shutdown()
}
#[tokio::test(flavor = "multi_thread")]
async fn race_stale_snapshot_expiry_suspends_then_settles_the_recorded_winner() -> TestResult {
let scope_timer = aion_core::TimerId::anonymous(7);
let backing = Arc::new(crate::runtime::nif_test_stores::StaleReadStore::new(5));
let store: Arc<dyn EventStore> = Arc::clone(&backing) as Arc<dyn EventStore>;
let mut events = pending_batch(&["a", "b"]);
events.push(scope_deadline_fired(7));
let (workflow_id, run_id) = seed_history(&store, &events).await?;
let harness =
CollectHarness::over_store(Arc::clone(&store), workflow_id.clone(), run_id.clone()).await?;
install_fresh_read_bridge(&harness);
backing.set_stale_target(&workflow_id, 1);
harness
.state
.timeout_scopes
.insert(23, TimeoutScope::live_for_test(harness.pid, scope_timer));
harness
.state
.timeout_scope_stacks
.insert(harness.pid, vec![23]);
let two = specs(&["a", "b"]);
assert_eq!(
harness.step(CollectKind::Race, &two),
Ok(CollectStep::Suspend),
"a snapshot lacking the deadline must park, not branch"
);
assert_eq!(harness.cancelled_ordinals().await?, Vec::<u64>::new());
harness.deps.runtime.deliver_activity_completion_message(
harness.pid,
"activity:0",
r#""r0""#.to_owned(),
)?;
assert_eq!(
harness.step(CollectKind::Race, &two),
Ok(CollectStep::RaceWon(Ok(r#""r0""#.to_owned())))
);
assert_eq!(harness.cancelled_ordinals().await?, vec![1]);
assert_eq!(harness.pinned(), None);
let history_len = store.read_history(&workflow_id).await?.len();
harness.shutdown()?;
let replay = CollectHarness::over_store(store, workflow_id, run_id).await?;
replay.state.timeout_scopes.insert(
1,
TimeoutScope::replayed_expired_with_deadline_for_test(
replay.pid,
aion_core::TimerId::anonymous(7),
),
);
replay
.state
.timeout_scope_stacks
.insert(replay.pid, vec![1]);
assert_eq!(
replay.step(CollectKind::Race, &two),
Ok(CollectStep::RaceWon(Ok(r#""r0""#.to_owned()))),
"replay must settle the recorded winner, not re-derive the race"
);
assert_eq!(
replay.store.read_history(&replay.workflow_id).await?.len(),
history_len,
"replay must append nothing"
);
replay.shutdown()
}