#![cfg(target_arch = "wasm32")]
#![allow(unused_imports)]
use absurder_sql::storage::{BLOCK_SIZE, BlockStorage};
use absurder_sql::types::DatabaseError;
use js_sys::Date;
use std::time::Duration;
use wasm_bindgen::JsCast;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn test_basic_leader_election() {
let db_name = "leader_election_test";
let storage1 = BlockStorage::new(db_name).await.expect("create storage1");
sleep_ms(100).await;
assert!(
storage1.is_leader().await,
"First instance should become leader"
);
let storage2 = BlockStorage::new(db_name).await.expect("create storage2");
sleep_ms(100).await;
assert!(
storage1.is_leader().await,
"First instance should remain leader"
);
assert!(
!storage2.is_leader().await,
"Second instance should be follower"
);
web_sys::console::log_1(&"Basic leader election test completed".into());
}
#[wasm_bindgen_test]
async fn test_leader_lease_expiry_handover() {
let db_name = "lease_expiry_test";
let storage1 = BlockStorage::new(db_name).await.expect("create storage1");
sleep_ms(100).await;
assert!(
storage1.is_leader().await,
"First instance should become leader"
);
let storage2 = BlockStorage::new(db_name).await.expect("create storage2");
sleep_ms(100).await;
assert!(
!storage2.is_leader().await,
"Second instance should be follower"
);
storage1
.stop_leader_election()
.await
.expect("stop leader election");
sleep_ms(6000).await;
assert!(
storage2.is_leader().await,
"Second instance should become leader after lease expiry"
);
web_sys::console::log_1(&"Leader lease expiry handover test completed".into());
}
#[wasm_bindgen_test]
async fn test_multiple_instances_single_leader() {
let db_name = "multiple_instances_test";
let storage1 = BlockStorage::new(db_name).await.expect("create storage1");
let storage2 = BlockStorage::new(db_name).await.expect("create storage2");
let storage3 = BlockStorage::new(db_name).await.expect("create storage3");
sleep_ms(200).await;
let mut leader_count = 0;
if storage1.is_leader().await {
leader_count += 1;
}
if storage2.is_leader().await {
leader_count += 1;
}
if storage3.is_leader().await {
leader_count += 1;
}
assert_eq!(leader_count, 1, "Exactly one instance should be leader");
web_sys::console::log_1(
&format!(
"Multiple instances test completed - {} leaders found",
leader_count
)
.into(),
);
}
#[wasm_bindgen_test]
async fn test_broadcast_channel_communication() {
let db_name = "broadcast_test";
let storage1 = BlockStorage::new(db_name).await.expect("create storage1");
sleep_ms(100).await;
assert!(
storage1.is_leader().await,
"First instance should become leader"
);
let storage2 = BlockStorage::new(db_name).await.expect("create storage2");
sleep_ms(100).await;
assert!(
!storage2.is_leader().await,
"Second instance should be follower"
);
storage1
.send_leader_heartbeat()
.await
.expect("send heartbeat");
sleep_ms(50).await;
let last_heartbeat = storage2
.get_last_leader_heartbeat()
.await
.expect("get last heartbeat");
assert!(
last_heartbeat > 0,
"Follower should have received leader heartbeat"
);
web_sys::console::log_1(&"BroadcastChannel communication test completed".into());
}
async fn sleep_ms(ms: u32) {
use wasm_bindgen_futures::JsFuture;
use web_sys::js_sys;
let promise = js_sys::Promise::new(&mut |resolve, _| {
let closure = wasm_bindgen::closure::Closure::wrap(Box::new(move || {
resolve.call0(&wasm_bindgen::JsValue::NULL).unwrap();
}) as Box<dyn FnMut()>);
web_sys::window()
.unwrap()
.set_timeout_with_callback_and_timeout_and_arguments_0(
closure.as_ref().unchecked_ref(),
ms as i32,
)
.unwrap();
closure.forget();
});
JsFuture::from(promise).await.unwrap();
}