#[cfg(test)]
mod tests {
use crate::encoding::{Decode, Encode};
use crate::memtable::{
FrozenMemtable, Memtable, MemtableGetResult, MemtablePointEntry, ReadMemtable,
};
use tempfile::TempDir;
#[test]
fn point_entry_put_accessors() {
let entry = MemtablePointEntry::Put {
value: b"hello".to_vec(),
timestamp: 1000,
lsn: 5,
};
assert_eq!(entry.lsn(), 5);
assert_eq!(entry.timestamp(), 1000);
assert!(!entry.is_delete());
assert_eq!(entry.value(), Some(b"hello".as_slice()));
}
#[test]
fn point_entry_delete_accessors() {
let entry = MemtablePointEntry::Delete {
timestamp: 2000,
lsn: 10,
};
assert_eq!(entry.lsn(), 10);
assert_eq!(entry.timestamp(), 2000);
assert!(entry.is_delete());
assert_eq!(entry.value(), None);
}
#[test]
fn encode_decode_put_round_trip() {
let original = MemtablePointEntry::Put {
value: b"data".to_vec(),
timestamp: 42,
lsn: 7,
};
let mut buf = Vec::new();
original.encode_to(&mut buf).unwrap();
let (decoded, consumed) = MemtablePointEntry::decode_from(&buf).unwrap();
assert_eq!(consumed, buf.len());
assert_eq!(decoded, original);
}
#[test]
fn encode_decode_delete_round_trip() {
let original = MemtablePointEntry::Delete {
timestamp: 99,
lsn: 3,
};
let mut buf = Vec::new();
original.encode_to(&mut buf).unwrap();
let (decoded, consumed) = MemtablePointEntry::decode_from(&buf).unwrap();
assert_eq!(consumed, buf.len());
assert_eq!(decoded, original);
}
#[test]
fn decode_invalid_tag_returns_error() {
let invalid = vec![0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let result = MemtablePointEntry::decode_from(&invalid);
assert!(result.is_err());
}
#[test]
fn read_memtable_trait_memtable() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mt = Memtable::new(path.to_str().unwrap(), None, 4096).unwrap();
mt.put(b"k1".to_vec(), b"v1".to_vec()).unwrap();
mt.put(b"k2".to_vec(), b"v2".to_vec()).unwrap();
mt.delete(b"k3".to_vec()).unwrap();
let reader: &dyn ReadMemtable = &mt;
assert_eq!(
reader.get(b"k1").unwrap(),
MemtableGetResult::Put(b"v1".to_vec())
);
assert_eq!(reader.get(b"k3").unwrap(), MemtableGetResult::Delete);
assert_eq!(reader.get(b"missing").unwrap(), MemtableGetResult::NotFound);
let records: Vec<_> = reader.scan(b"k1", b"k3").unwrap().collect();
assert_eq!(records.len(), 2);
assert!(reader.max_lsn().is_some());
assert!(reader.max_lsn().unwrap() >= 3);
}
#[test]
fn read_memtable_trait_frozen() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mt = Memtable::new(path.to_str().unwrap(), None, 4096).unwrap();
mt.put(b"fk1".to_vec(), b"fv1".to_vec()).unwrap();
mt.put(b"fk2".to_vec(), b"fv2".to_vec()).unwrap();
let frozen = FrozenMemtable::new(mt);
let reader: &dyn ReadMemtable = &frozen;
assert_eq!(
reader.get(b"fk1").unwrap(),
MemtableGetResult::Put(b"fv1".to_vec())
);
let records: Vec<_> = reader.scan(b"fk1", b"fk3").unwrap().collect();
assert_eq!(records.len(), 2);
assert!(reader.max_lsn().is_some());
}
#[test]
fn frozen_memtable_wal_seq() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mt = Memtable::new(path.to_str().unwrap(), None, 4096).unwrap();
let seq = mt.wal_seq();
let frozen = FrozenMemtable::new(mt);
assert_eq!(frozen.wal_seq(), seq);
}
#[test]
fn hex_key_short() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mt = Memtable::new(path.to_str().unwrap(), None, 4096).unwrap();
mt.put(b"short".to_vec(), b"v".to_vec()).unwrap();
let _ = mt.get(b"short").unwrap();
}
#[test]
fn hex_key_long() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mt = Memtable::new(path.to_str().unwrap(), None, 4096).unwrap();
let long_key = vec![0xAB; 64]; mt.put(long_key.clone(), b"v".to_vec()).unwrap();
let _ = mt.get(&long_key).unwrap();
}
#[test]
fn frozen_creation_timestamp() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mt = Memtable::new(path.to_str().unwrap(), None, 4096).unwrap();
let frozen = FrozenMemtable::new(mt);
assert!(frozen.creation_timestamp() > 0);
}
}