#![cfg(not(target_arch = "wasm32"))]
use absurder_sql::storage::{BLOCK_SIZE, BlockStorage, SyncPolicy};
use serial_test::serial;
use tempfile::TempDir;
#[path = "common/mod.rs"]
mod common;
#[tokio::test(start_paused = true, flavor = "current_thread")]
#[serial]
async fn test_tokio_interval_triggers_flush_on_time_advance() {
let tmp = TempDir::new().expect("tempdir");
common::set_var("ABSURDERSQL_FS_BASE", tmp.path());
let mut storage = BlockStorage::new("manager_test_db").await.unwrap();
let block_id = storage.allocate_block().await.unwrap();
let data = vec![7u8; BLOCK_SIZE];
storage.write_block(block_id, data).await.unwrap();
assert_eq!(
storage.get_dirty_count(),
1,
"precondition: one dirty block"
);
let policy = SyncPolicy {
interval_ms: Some(200),
max_dirty: None,
max_dirty_bytes: None,
debounce_ms: None,
verify_after_write: false,
};
storage.enable_auto_sync_with_policy(policy);
tokio::time::advance(std::time::Duration::from_millis(250)).await;
tokio::task::yield_now().await;
tokio::time::advance(std::time::Duration::from_millis(1)).await;
tokio::task::yield_now().await;
assert_eq!(
storage.get_dirty_count(),
0,
"dirty blocks should be flushed by tokio interval"
);
assert!(
storage.get_timer_sync_count() >= 1,
"timer sync count should increment"
);
}
#[tokio::test(flavor = "current_thread")]
#[serial]
async fn test_threshold_triggers_immediate_flush_without_debounce() {
let tmp = TempDir::new().expect("tempdir");
common::set_var("ABSURDERSQL_FS_BASE", tmp.path());
let mut storage = BlockStorage::new("threshold_immediate_db").await.unwrap();
let block_id = storage.allocate_block().await.unwrap();
let data = vec![1u8; BLOCK_SIZE];
let policy = SyncPolicy {
interval_ms: None,
max_dirty: Some(1),
max_dirty_bytes: None,
debounce_ms: None,
verify_after_write: false,
};
storage.enable_auto_sync_with_policy(policy);
storage.write_block(block_id, data).await.unwrap();
assert_eq!(
storage.get_dirty_count(),
0,
"threshold should flush immediately without debounce"
);
assert_eq!(
storage.get_timer_sync_count(),
0,
"timer syncs should not be used"
);
assert_eq!(
storage.get_debounce_sync_count(),
0,
"debounce syncs should not be used"
);
}
#[tokio::test(flavor = "current_thread")]
#[serial]
async fn test_debounce_flushes_after_idle_following_threshold() {
let tmp = TempDir::new().expect("tempdir");
common::set_var("ABSURDERSQL_FS_BASE", tmp.path());
let mut storage = BlockStorage::new("debounce_after_idle_db").await.unwrap();
let b1 = storage.allocate_block().await.unwrap();
let b2 = storage.allocate_block().await.unwrap();
let data1 = vec![2u8; BLOCK_SIZE];
let data2 = vec![3u8; BLOCK_SIZE];
let policy = SyncPolicy {
interval_ms: None,
max_dirty: Some(2),
max_dirty_bytes: None,
debounce_ms: Some(20),
verify_after_write: false,
};
storage.enable_auto_sync_with_policy(policy);
storage.write_block(b1, data1).await.unwrap();
storage.write_block(b2, data2).await.unwrap();
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
tokio::task::yield_now().await;
assert_eq!(
storage.get_dirty_count(),
0,
"debounce should flush after idle period following threshold"
);
assert!(
storage.get_debounce_sync_count() >= 1,
"debounce sync count should increment"
);
}