use kvdb::{IoStatsKind, KeyValueDB};
use std::io;
pub fn test_put_and_get(db: &dyn KeyValueDB) -> io::Result<()> {
let key1 = b"key1";
let mut transaction = db.transaction();
transaction.put(0, key1, b"horse");
db.write(transaction)?;
assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
Ok(())
}
pub fn test_delete_and_get(db: &dyn KeyValueDB) -> io::Result<()> {
let key1 = b"key1";
let mut transaction = db.transaction();
transaction.put(0, key1, b"horse");
db.write(transaction)?;
assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
let mut transaction = db.transaction();
transaction.delete(0, key1);
db.write(transaction)?;
assert!(db.get(0, key1)?.is_none());
Ok(())
}
pub fn test_get_fails_with_non_existing_column(db: &dyn KeyValueDB) -> io::Result<()> {
assert!(db.get(1, &[]).is_err());
Ok(())
}
pub fn test_write_clears_buffered_ops(db: &dyn KeyValueDB) -> io::Result<()> {
let mut batch = db.transaction();
batch.put(0, b"foo", b"bar");
db.write(batch)?;
assert_eq!(db.get(0, b"foo")?.unwrap(), b"bar");
let mut batch = db.transaction();
batch.put(0, b"foo", b"baz");
db.write(batch)?;
assert_eq!(db.get(0, b"foo")?.unwrap(), b"baz");
Ok(())
}
pub fn test_iter(db: &dyn KeyValueDB) -> io::Result<()> {
let key1 = b"key1";
let key2 = b"key2";
let mut transaction = db.transaction();
transaction.put(0, key1, key1);
transaction.put(0, key2, key2);
db.write(transaction)?;
let contents: Vec<_> = db.iter(0).into_iter().collect();
assert_eq!(contents.len(), 2);
assert_eq!(&*contents[0].0, key1);
assert_eq!(&*contents[0].1, key1);
assert_eq!(&*contents[1].0, key2);
assert_eq!(&*contents[1].1, key2);
Ok(())
}
pub fn test_iter_with_prefix(db: &dyn KeyValueDB) -> io::Result<()> {
let key1 = b"0";
let key2 = b"ab";
let key3 = b"abc";
let key4 = b"abcd";
let mut batch = db.transaction();
batch.put(0, key1, key1);
batch.put(0, key2, key2);
batch.put(0, key3, key3);
batch.put(0, key4, key4);
db.write(batch)?;
let contents: Vec<_> = db.iter_with_prefix(0, b"").into_iter().collect();
assert_eq!(contents.len(), 4);
assert_eq!(&*contents[0].0, key1);
assert_eq!(&*contents[1].0, key2);
assert_eq!(&*contents[2].0, key3);
assert_eq!(&*contents[3].0, key4);
let contents: Vec<_> = db.iter_with_prefix(0, b"a").into_iter().collect();
assert_eq!(contents.len(), 3);
assert_eq!(&*contents[0].0, key2);
assert_eq!(&*contents[1].0, key3);
assert_eq!(&*contents[2].0, key4);
let contents: Vec<_> = db.iter_with_prefix(0, b"abc").into_iter().collect();
assert_eq!(contents.len(), 2);
assert_eq!(&*contents[0].0, key3);
assert_eq!(&*contents[1].0, key4);
let contents: Vec<_> = db.iter_with_prefix(0, b"abcde").into_iter().collect();
assert_eq!(contents.len(), 0);
let contents: Vec<_> = db.iter_with_prefix(0, b"0").into_iter().collect();
assert_eq!(contents.len(), 1);
assert_eq!(&*contents[0].0, key1);
Ok(())
}
pub const IO_STATS_NUM_COLUMNS: u32 = 3;
pub fn test_io_stats(db: &dyn KeyValueDB) -> io::Result<()> {
let key1 = b"kkk";
let mut batch = db.transaction();
batch.put(0, key1, key1);
batch.put(1, key1, key1);
batch.put(2, key1, key1);
for _ in 0..10 {
db.get(0, key1)?;
}
db.write(batch)?;
let io_stats = db.io_stats(IoStatsKind::SincePrevious);
assert_eq!(io_stats.transactions, 1);
assert_eq!(io_stats.writes, 3);
assert_eq!(io_stats.bytes_written, 18);
assert_eq!(io_stats.reads, 10);
assert_eq!(io_stats.bytes_read, 30);
let new_io_stats = db.io_stats(IoStatsKind::SincePrevious);
assert_eq!(new_io_stats.transactions, 0);
let new_io_stats = db.io_stats(IoStatsKind::Overall);
assert_eq!(new_io_stats.bytes_written, 18);
let mut batch = db.transaction();
batch.delete(0, key1);
batch.delete(1, key1);
batch.delete(2, key1);
assert_eq!(db.io_stats(IoStatsKind::SincePrevious).writes, 0);
db.write(batch)?;
assert_eq!(db.io_stats(IoStatsKind::SincePrevious).writes, 3);
Ok(())
}
pub const DELETE_PREFIX_NUM_COLUMNS: u32 = 7;
pub fn test_delete_prefix(db: &dyn KeyValueDB) -> io::Result<()> {
let keys = [
&[][..],
&[0u8][..],
&[0, 1][..],
&[1][..],
&[1, 0][..],
&[1, 255][..],
&[1, 255, 255][..],
&[2][..],
&[2, 0][..],
&[2, 255][..],
&[255; 16][..],
];
let init_db = |ix: u32| -> io::Result<()> {
let mut batch = db.transaction();
for (i, key) in keys.iter().enumerate() {
batch.put(ix, key, &[i as u8]);
}
db.write(batch)?;
Ok(())
};
let check_db = |ix: u32, content: [bool; 11]| -> io::Result<()> {
let mut state = [true; 11];
for (c, key) in keys.iter().enumerate() {
state[c] = db.get(ix, key)?.is_some();
}
assert_eq!(state, content, "at {}", ix);
Ok(())
};
let tests: [_; DELETE_PREFIX_NUM_COLUMNS as usize] = [
(&[1u8][..], [true, true, true, false, false, false, false, true, true, true, true]),
(&[1u8, 255, 255][..], [true, true, true, true, true, true, false, true, true, true, true]),
(&[1, 2][..], [true, true, true, true, true, true, true, true, true, true, true]),
(&[8][..], [true, true, true, true, true, true, true, true, true, true, true]),
(&[255, 255][..], [true, true, true, true, true, true, true, true, true, true, false]),
(&[255][..], [true, true, true, true, true, true, true, true, true, true, false]),
(&[][..], [false, false, false, false, false, false, false, false, false, false, false]),
];
for (ix, test) in tests.iter().enumerate() {
let ix = ix as u32;
init_db(ix)?;
let mut batch = db.transaction();
batch.delete_prefix(ix, test.0);
db.write(batch)?;
check_db(ix, test.1)?;
}
Ok(())
}
pub fn test_complex(db: &dyn KeyValueDB) -> io::Result<()> {
let key1 = b"02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
let key2 = b"03c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
let key3 = b"04c00000000b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
let key4 = b"04c01111110b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
let key5 = b"04c02222220b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc";
let mut batch = db.transaction();
batch.put(0, key1, b"cat");
batch.put(0, key2, b"dog");
batch.put(0, key3, b"caterpillar");
batch.put(0, key4, b"beef");
batch.put(0, key5, b"fish");
db.write(batch)?;
assert_eq!(&*db.get(0, key1)?.unwrap(), b"cat");
let contents: Vec<_> = db.iter(0).into_iter().collect();
assert_eq!(contents.len(), 5);
assert_eq!(contents[0].0.to_vec(), key1.to_vec());
assert_eq!(&*contents[0].1, b"cat");
assert_eq!(contents[1].0.to_vec(), key2.to_vec());
assert_eq!(&*contents[1].1, b"dog");
let mut prefix_iter = db.iter_with_prefix(0, b"04c0");
assert_eq!(*prefix_iter.next().unwrap().1, b"caterpillar"[..]);
assert_eq!(*prefix_iter.next().unwrap().1, b"beef"[..]);
assert_eq!(*prefix_iter.next().unwrap().1, b"fish"[..]);
let mut batch = db.transaction();
batch.delete(0, key1);
db.write(batch)?;
assert!(db.get(0, key1)?.is_none());
let mut batch = db.transaction();
batch.put(0, key1, b"cat");
db.write(batch)?;
let mut transaction = db.transaction();
transaction.put(0, key3, b"elephant");
transaction.delete(0, key1);
db.write(transaction)?;
assert!(db.get(0, key1)?.is_none());
assert_eq!(&*db.get(0, key3)?.unwrap(), b"elephant");
assert_eq!(&*db.get_by_prefix(0, key3).unwrap(), b"elephant");
assert_eq!(&*db.get_by_prefix(0, key2).unwrap(), b"dog");
let mut transaction = db.transaction();
transaction.put(0, key1, b"horse");
transaction.delete(0, key3);
db.write(transaction)?;
assert!(db.get(0, key3)?.is_none());
assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
assert!(db.get(0, key3)?.is_none());
assert_eq!(&*db.get(0, key1)?.unwrap(), b"horse");
Ok(())
}