extern crate alloc;
use remdb::{DataType, RemDb, Result};
use std::sync::LazyLock;
struct TestPlatform;
impl remdb::platform::Platform for TestPlatform {
fn get_timestamp(&self) -> u64 {
0
}
fn get_timestamp_us(&self) -> u64 {
0
}
fn spin_lock(&self, lock: &mut u32) {
unsafe {
while core::sync::atomic::AtomicU32::from_ptr(lock as *mut u32)
.compare_exchange(
0,
1,
core::sync::atomic::Ordering::Acquire,
core::sync::atomic::Ordering::Relaxed,
)
.is_err()
{
core::hint::spin_loop();
}
}
}
fn spin_unlock(&self, lock: &mut u32) {
unsafe {
core::sync::atomic::AtomicU32::from_ptr(lock as *mut u32)
.store(0, core::sync::atomic::Ordering::Release);
}
}
fn compiler_barrier(&self) {
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
fn full_memory_barrier(&self) {
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
fn memcpy(&self, dest: *mut u8, src: *const u8, size: usize) {
unsafe {
core::ptr::copy_nonoverlapping(src, dest, size);
}
}
fn memset(&self, dest: *mut u8, value: u8, size: usize) {
unsafe {
core::ptr::write_bytes(dest, value, size);
}
}
fn delay_ms(&self, _ms: u32) {
}
fn delay_us(&self, _us: u32) {
}
fn file_open(
&self,
_path: &str,
_mode: remdb::platform::FileMode,
) -> remdb::platform::FileResult<remdb::platform::FileHandle> {
Ok(core::ptr::null())
}
fn file_close(&self, _handle: remdb::platform::FileHandle) -> remdb::platform::FileResult<()> {
Ok(())
}
fn file_write(
&self,
_handle: remdb::platform::FileHandle,
_buffer: *const u8,
_size: usize,
) -> remdb::platform::FileResult<usize> {
Ok(0)
}
fn file_read(
&self,
_handle: remdb::platform::FileHandle,
_buffer: *mut u8,
_size: usize,
) -> remdb::platform::FileResult<usize> {
Ok(0)
}
fn file_seek(
&self,
_handle: remdb::platform::FileHandle,
_offset: i64,
_whence: remdb::platform::SeekWhence,
) -> remdb::platform::FileResult<u64> {
Ok(0)
}
fn file_remove(&self, _path: &str) -> remdb::platform::FileResult<()> {
Ok(())
}
fn file_size(&self, _path: &str) -> remdb::platform::FileResult<usize> {
Ok(0)
}
fn crc32(&self, _data: *const u8, _size: usize) -> u32 {
0
}
}
static TEST_PLATFORM: TestPlatform = TestPlatform;
static mut DB_MEMORY: Vec<u8> = Vec::new();
static DEFAULT_ALLOCATOR: remdb::config::DefaultMemoryAllocator =
remdb::config::DefaultMemoryAllocator;
static TEST_CONFIG: LazyLock<remdb::config::DbConfig> = LazyLock::new(|| {
remdb::config::DbConfig {
tables: vec![],
total_memory: 1024 * 1024 * 10, low_power_mode_supported: false,
low_power_max_records: None,
default_max_records: 1000,
memory_allocator: &DEFAULT_ALLOCATOR,
wal_config: remdb::config::WALConfig {
log_path: "./wal",
log_mode: remdb::config::LogMode::Sync,
checkpoint_interval_ms: 60000,
log_file_size_limit: 16 * 1024 * 1024,
log_prealloc_size: 1024 * 1024,
log_segment_size: 16 * 1024 * 1024,
max_consecutive_invalid: 100,
retained_checkpoints: 2,
skip_threshold: 1000,
skip_block_size: 1024 * 1024,
max_skip_attempts: 3,
compression_type: remdb::config::WALCompressionType::None,
compression_level: 3,
},
time_series_defaults: remdb::config::TimeSeriesConfig::DEFAULT,
#[cfg(feature = "pubsub")]
pubsub_config: None,
#[cfg(feature = "ha")]
ha_config: None,
model_worker_config: Default::default(),
}
});
#[test]
#[serial_test::serial]
fn test_create_table_with_composite_pk() -> Result<()> {
remdb::platform::init_platform(&TEST_PLATFORM);
remdb::reset_global_db();
let mut new_memory = vec![0u8; 8388608];
remdb::memory::allocator::init_global_allocator(new_memory.as_mut_ptr(), new_memory.len())?;
unsafe {
DB_MEMORY = new_memory;
}
let mut db = RemDb::new(&TEST_CONFIG);
db.init()?;
let fields = [
("id1", DataType::UInt32, 4, None, None),
("id2", DataType::UInt32, 4, None, None),
("name", DataType::VarChar, 64, None, None),
("value", DataType::Float64, 8, None, None),
];
let primary_key = Some(vec![0, 1]);
db.create_table("test_composite", &fields, primary_key)?;
Ok(())
}
#[test]
#[serial_test::serial]
fn test_insert_and_query_with_composite_pk() -> Result<()> {
remdb::platform::init_platform(&TEST_PLATFORM);
remdb::reset_global_db();
let mut new_memory = vec![0u8; 8388608];
remdb::memory::allocator::init_global_allocator(new_memory.as_mut_ptr(), new_memory.len())?;
unsafe {
DB_MEMORY = new_memory;
}
let mut db = RemDb::new(&TEST_CONFIG);
db.init()?;
let fields = [
("id1", DataType::UInt32, 4, None, None),
("id2", DataType::UInt32, 4, None, None),
("name", DataType::VarChar, 64, None, None),
("value", DataType::Float64, 8, None, None),
];
let primary_key = Some(vec![0, 1]);
db.create_table("test_composite", &fields, primary_key)?;
let table_id = 1; let table = db.get_table_mut(table_id)?;
let mut record = [0u8; 4 + 4 + 64 + 8];
let id1: u32 = 1;
let id2: u32 = 1;
let name = "test1";
let value: f64 = 100.5;
record[0..4].copy_from_slice(&id1.to_le_bytes());
record[4..8].copy_from_slice(&id2.to_le_bytes());
let name_bytes = name.as_bytes();
record[8..8 + name_bytes.len()].copy_from_slice(name_bytes);
record[8 + 64..8 + 64 + 8].copy_from_slice(&value.to_le_bytes());
let _record_id = table.insert(record.as_ptr() as *const u8)?;
let id2: u32 = 2;
record[4..8].copy_from_slice(&id2.to_le_bytes());
let _record_id = table.insert(record.as_ptr() as *const u8)?;
let id1: u32 = 2;
let id2: u32 = 1;
record[0..4].copy_from_slice(&id1.to_le_bytes());
record[4..8].copy_from_slice(&id2.to_le_bytes());
let _record_id = table.insert(record.as_ptr() as *const u8)?;
let result = table.insert(record.as_ptr() as *const u8);
assert!(result.is_err());
Ok(())
}
#[test]
#[serial_test::serial]
fn test_composite_pk_with_three_fields() -> Result<()> {
remdb::platform::init_platform(&TEST_PLATFORM);
remdb::reset_global_db();
let mut new_memory = vec![0u8; 8388608];
remdb::memory::allocator::init_global_allocator(new_memory.as_mut_ptr(), new_memory.len())?;
unsafe {
DB_MEMORY = new_memory;
}
let mut db = RemDb::new(&TEST_CONFIG);
db.init()?;
let fields = [
("device_id", DataType::UInt32, 0, None, None),
("metric_id", DataType::UInt32, 0, None, None),
("timestamp", DataType::UInt64, 0, None, None),
("value", DataType::Float64, 0, None, None),
];
let primary_key = Some(vec![0, 1, 2]);
db.create_table("metrics", &fields, primary_key)?;
Ok(())
}