use bpm_engine::bpm_engine_adapter_memory::MemoryRepo;
use bpm_engine::bpm_engine_storage::ParallelJoinRepo;
use std::sync::Arc;
#[tokio::test]
async fn parallel_join_single_fork_convergence() {
let repo = Arc::new(MemoryRepo::new());
let group_id = "fork-0".to_string();
let expected = 3u32;
repo.ensure_group(&group_id, expected).await.unwrap();
let done_1 = repo.try_join(&group_id).await.unwrap();
assert!(
!done_1,
"join with expected=3 should not fire after only 1 arrival"
);
let done_2 = repo.try_join(&group_id).await.unwrap();
assert!(
!done_2,
"join with expected=3 should not fire after only 2 arrivals"
);
let done_3 = repo.try_join(&group_id).await.unwrap();
assert!(
done_3,
"join with expected=3 should fire after all 3 arrivals"
);
}
#[tokio::test]
async fn parallel_join_multi_fork_convergence() {
let repo = Arc::new(MemoryRepo::new());
let group_a = "fork1-0".to_string();
repo.ensure_group(&group_a, 2).await.unwrap();
let group_b = "fork2-0".to_string();
repo.ensure_group(&group_b, 2).await.unwrap();
assert_ne!(
group_a, group_b,
"different fork executions should produce different group_ids"
);
let done_a1 = repo.try_join(&group_a).await.unwrap();
assert!(!done_a1, "group A should not fire after only 1 arrival");
let done_b1 = repo.try_join(&group_b).await.unwrap();
assert!(!done_b1, "group B should not fire after only 1 arrival");
let done_a2 = repo.try_join(&group_a).await.unwrap();
assert!(done_a2, "group A should fire after its 2nd arrival");
let done_b2 = repo.try_join(&group_b).await.unwrap();
assert!(done_b2, "group B should fire after its 2nd arrival");
}
#[tokio::test]
async fn parallel_join_out_of_order() {
let repo = Arc::new(MemoryRepo::new());
let group_id = "fork-0".to_string();
let expected = 3u32;
repo.ensure_group(&group_id, expected).await.unwrap();
let done_1 = repo.try_join(&group_id).await.unwrap();
assert!(!done_1, "join should not fire after only 1st arrival");
let done_2 = repo.try_join(&group_id).await.unwrap();
assert!(!done_2, "join should not fire after only 2nd arrival");
let done_3 = repo.try_join(&group_id).await.unwrap();
assert!(
done_3,
"join should fire after 3rd arrival regardless of order"
);
}
#[tokio::test]
async fn parallel_join_group_id_collision_detection() {
let repo = Arc::new(MemoryRepo::new());
let group_a = "fork-node1-0".to_string();
let group_b = "fork-node2-0".to_string();
assert_ne!(
group_a, group_b,
"different fork executions should produce different group_ids"
);
repo.ensure_group(&group_a, 2).await.unwrap();
repo.ensure_group(&group_b, 2).await.unwrap();
repo.try_join(&group_a).await.unwrap(); let done_a = repo.try_join(&group_a).await.unwrap(); assert!(done_a, "group A should be done after 2 arrivals");
repo.try_join(&group_b).await.unwrap(); let done_b = repo.try_join(&group_b).await.unwrap(); assert!(done_b, "group B should be done after 2 arrivals");
}
#[tokio::test]
async fn parallel_join_waits_for_all_branches() {
let repo = Arc::new(MemoryRepo::new());
let group_id = "test-group".to_string();
let expected = 3u32;
repo.ensure_group(&group_id, expected).await.unwrap();
let done_1 = repo.try_join(&group_id).await.unwrap();
assert!(
!done_1,
"join with expected=3 should not complete after only 1 arrival"
);
let done_2 = repo.try_join(&group_id).await.unwrap();
assert!(
!done_2,
"join with expected=3 should not complete after only 2 arrivals"
);
let done_3 = repo.try_join(&group_id).await.unwrap();
assert!(
done_3,
"join with expected=3 should complete after all 3 arrivals"
);
}
#[tokio::test]
async fn parallel_join_repo_counter_behavior() {
let repo = Arc::new(MemoryRepo::new());
let group_id = "counter-test".to_string();
repo.ensure_group(&group_id, 2).await.unwrap();
let done1 = repo.try_join(&group_id).await.unwrap();
assert!(!done1);
let done2 = repo.try_join(&group_id).await.unwrap();
assert!(done2);
let done3 = repo.try_join(&group_id).await.unwrap();
assert!(
!done3,
"try_join should return false after join is already complete"
);
}
#[tokio::test]
async fn parallel_join_zero_expected_completes_immediately() {
let repo = Arc::new(MemoryRepo::new());
let group_id = "zero-expected".to_string();
repo.ensure_group(&group_id, 0).await.unwrap();
let done = repo.try_join(&group_id).await.unwrap();
assert!(
done,
"join with expected=0 should complete on first try_join call"
);
}
#[tokio::test]
async fn parallel_join_multiple_groups_tracked_independently() {
let repo = Arc::new(MemoryRepo::new());
repo.ensure_group("group-A", 1).await.unwrap();
repo.ensure_group("group-B", 2).await.unwrap();
repo.ensure_group("group-C", 3).await.unwrap();
let done_a = repo.try_join("group-A").await.unwrap();
assert!(done_a, "group-A should complete immediately");
let done_b1 = repo.try_join("group-B").await.unwrap();
assert!(!done_b1, "group-B should not complete after 1 arrival");
let done_c1 = repo.try_join("group-C").await.unwrap();
assert!(!done_c1, "group-C should not complete after 1 arrival");
let done_b2 = repo.try_join("group-B").await.unwrap();
assert!(done_b2, "group-B should complete after 2 arrivals");
let done_c2 = repo.try_join("group-C").await.unwrap();
assert!(!done_c2, "group-C should not complete after 2 arrivals");
let done_c3 = repo.try_join("group-C").await.unwrap();
assert!(done_c3, "group-C should complete after 3 arrivals");
}