shared_hashmap 0.1.2

A shared hashmap for use between processes, using shared memory
Documentation
use nix::{
    sys::wait::waitpid,
    unistd::{fork, ForkResult},
};
use std::thread::sleep;
use std::thread::spawn;
use std::time::Duration;

use shared_hashmap::SharedMemoryHashMap;

#[test]
fn test_insert() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    assert_eq!(map.get(&1), Some(1));

    assert_eq!(map.get(&2), None);
    map.insert(2, 2);
    assert_eq!(map.get(&2), Some(2));
}

#[test]
fn test_get() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    assert_eq!(map.get(&1), Some(1));
}

#[test]
fn test_get_immutable() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert("Hello", "World".to_owned());
    let mut value = map.get(&"Hello").unwrap();
    value.push('!');
    assert_eq!(map.get(&"Hello"), Some("World".to_owned()));
}

#[test]
fn test_peak() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    map.insert(2, 2);
    assert_eq!(map.peak(&1), Some(1));
}

#[test]
fn test_get_lru() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    map.insert(2, 2);
    map.insert(3, 3);
    map.get(&1);
    map.get(&3);

    assert_eq!(map.get_lru(), Some((2, 2)));

    map.get(&2);
    assert_eq!(map.get_lru(), Some((1, 1)));
}

#[test]
fn test_lru_evicted() {
    let mut map = SharedMemoryHashMap::new(168).unwrap();
    map.try_insert(1, "Hello").unwrap();
    assert_eq!(map.get(&1), Some("Hello"));
    map.try_insert(2, "Hello World").unwrap();
    assert_eq!(map.get(&1), None);
    assert_eq!(map.get(&2), Some("Hello World"));

    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    for i in 0..10000 {
        map.try_insert(i, "Hello".repeat(10)).unwrap();
    }
}

#[test]
fn test_insert_slice() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, [1, 2, 3]);
    map.insert(2, [3, 4, 5]);
    assert_eq!(map.get(&1), Some([1, 2, 3]));
    assert_eq!(map.get(&2), Some([3, 4, 5]));
}

#[test]
fn test_insert_string() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, String::from("Hello"));
    map.insert(2, String::from("World"));
    assert_eq!(map.get(&1), Some(String::from("Hello")));
    assert_eq!(map.get(&2), Some(String::from("World")));
}

#[test]
fn test_insert_too_long() {
    //let mut map = SharedMemoryHashMap::new(128).unwrap();
}

#[test]
fn test_remove() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    map.insert(2, 2);
    map.insert(3, 3);
    map.remove(&1);
    assert_eq!(map.get(&1), None);
    assert_eq!(map.get(&2), Some(2));
    assert_eq!(map.get(&3), Some(3));
    assert_eq!(map.len(), 2);

    map.remove(&3);
    assert_eq!(map.get(&1), None);
    assert_eq!(map.get(&2), Some(2));
    assert_eq!(map.get(&3), None);
    assert_eq!(map.len(), 1);

    map.remove(&2);
    assert_eq!(map.get(&1), None);
    assert_eq!(map.get(&2), None);
    assert_eq!(map.get(&3), None);
    assert_eq!(map.len(), 0);
}

#[test]
fn test_contains_key() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    assert!(map.contains_key(&1));
    assert!(!map.contains_key(&2));
}

#[test]
fn test_clear() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    map.insert(2, 2);
    map.insert(3, 3);
    map.clear();
    assert_eq!(map.get(&1), None);
    assert_eq!(map.get(&2), None);
    assert_eq!(map.get(&3), None);
    assert_eq!(map.len(), 0);
}

#[test]
fn test_clone() {
    let mut map: SharedMemoryHashMap<i32, i32> = SharedMemoryHashMap::new(1024).unwrap();
    let mut map2 = map.try_clone().unwrap();
    map.insert(1, 1);
    assert_eq!(map2.get(&1), Some(1));

    map2.clear();
    assert_eq!(map.len(), 0);
    assert_eq!(map2.len(), 0);
}

#[test]
fn test_used() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    let used = map.used();
    map.insert(2, 2);
    assert!(map.used() > used);
    map.remove(&2);
    assert_eq!(map.used(), used);

    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    let used = map.used();
    map.insert(1, 1);
    map.remove(&1);
    assert_eq!(map.used(), used);

    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    let used = map.used();
    map.insert(1, 1);
    map.clear();
    assert_eq!(map.used(), used);
}

#[test]
fn test_free() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    assert_eq!(map.free(), 1024 - map.used());
}

#[test]
fn test_race_condition() {
    let mut map = SharedMemoryHashMap::new(1024 * 1024).unwrap();
    map.insert(1, 1);
    map.insert(2, 2);
    map.insert(3, 3);

    let mut map2 = map.try_clone().unwrap();
    let mut map3 = map.try_clone().unwrap();

    spawn(move || {
        for i in 100..2000 {
            map2.try_insert(i, i).unwrap();
        }
    });
    spawn(move || {
        for i in 2000..3000 {
            map3.try_insert(i, i).unwrap();
        }
    });

    sleep(Duration::from_millis(100));
}

#[test]
fn test_fork() {
    let mut map = SharedMemoryHashMap::new(1024).unwrap();
    map.insert(1, 1);
    match unsafe { fork() } {
        Ok(ForkResult::Parent { child, .. }) => {
            map.insert(2, 2);
            waitpid(child, None).unwrap();
            assert_eq!(map.get(&3), Some(3));
        }
        Ok(ForkResult::Child) => {
            sleep(Duration::from_millis(10));
            map.insert(3, 3);
            assert_eq!(map.get(&2), Some(2));
        }
        Err(_) => {
            dbg!("Fork failed");
        }
    }
}