persy 0.7.0

Transactional Persistence Engine
Documentation
mod helpers;

use helpers::{create_and_drop, CountDown};
use persy::PersyError;
use std::sync::Arc;
use std::thread;

#[test]
fn test_create_drop_segment() {
    create_and_drop("cds", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        assert!(persy.exists_segment("test").unwrap());
        let mut tx = persy.begin().unwrap();
        persy.drop_segment(&mut tx, "test").unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
        assert!(!persy.exists_segment("test").unwrap());
    });
}

#[test]
fn test_create_drop_double_segments_and_insert_data() {
    create_and_drop("cdss", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        persy.create_segment(&mut tx, "test1").unwrap();
        let bytes = String::from("some").into_bytes();
        persy.insert_record(&mut tx, "test", &bytes).unwrap();

        let bytes = String::from("some").into_bytes();
        persy.insert_record(&mut tx, "test1", &bytes).unwrap();
        {
            let scanner = persy.scan_tx(&mut tx, "test").unwrap();
            assert_eq!(1, scanner.into_iter().count());
        }

        let scanner = persy.scan_tx(&mut tx, "test1").unwrap();
        assert_eq!(1, scanner.into_iter().count());
    });
}

#[test]
fn test_create_drop_segment_same_tx() {
    create_and_drop("cdss", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        assert!(persy.exists_segment_tx(&mut tx, "test").unwrap());
        let err = persy.drop_segment(&mut tx, "test");
        assert!(err.is_err());
    });
}

#[test]
fn test_create_drop_recreate_segment_same_tx() {
    create_and_drop("cdcs", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        assert!(persy.exists_segment_tx(&mut tx, "test").unwrap());
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        persy.drop_segment(&mut tx, "test").unwrap();
        assert!(!persy.exists_segment_tx(&mut tx, "test").unwrap());
        persy.create_segment(&mut tx, "test").unwrap();
        assert!(persy.exists_segment_tx(&mut tx, "test").unwrap());
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
        assert!(persy.exists_segment("test").unwrap());
    });
}

#[test]
fn test_update_record_of_dropped_segment_other_tx() {
    create_and_drop("urds", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("some").into_bytes();
        let rec = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        persy.update_record(&mut tx, "test", &rec, &bytes).unwrap();

        let mut tx1 = persy.begin().unwrap();
        persy.drop_segment(&mut tx1, "test").unwrap();
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();

        let finalizer = persy.prepare_commit(tx);
        assert!(finalizer.is_err());
    });
}

#[test]
fn test_update_record_of_dropped_recreated_segment_other_tx() {
    create_and_drop("urdcs", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("some").into_bytes();
        let rec = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        persy.update_record(&mut tx, "test", &rec, &bytes).unwrap();

        let mut tx1 = persy.begin().unwrap();
        persy.drop_segment(&mut tx1, "test").unwrap();
        persy.create_segment(&mut tx1, "test").unwrap();
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();

        let finalizer = persy.prepare_commit(tx);
        assert!(finalizer.is_err());
    });
}

#[test]
fn test_delete_record_of_dropped_segment_other_tx() {
    create_and_drop("drds", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("some").into_bytes();
        let rec = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        persy.delete_record(&mut tx, "test", &rec).unwrap();

        let mut tx1 = persy.begin().unwrap();
        persy.drop_segment(&mut tx1, "test").unwrap();
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();

        let finalizer = persy.prepare_commit(tx);
        assert!(finalizer.is_err());
    });
}

#[test]
fn test_delete_record_of_dropped_created_segment_other_tx() {
    create_and_drop("drdcs", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("some").into_bytes();
        let rec = persy.insert_record(&mut tx, "test", &bytes).unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        persy.delete_record(&mut tx, "test", &rec).unwrap();

        let mut tx1 = persy.begin().unwrap();
        persy.drop_segment(&mut tx1, "test").unwrap();
        persy.create_segment(&mut tx1, "test").unwrap();
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();

        let finalizer = persy.prepare_commit(tx);
        assert!(finalizer.is_err());
    });
}

#[test]
fn test_insert_record_of_dropped_recreated_segment_other_tx() {
    create_and_drop("irdcs", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("some").into_bytes();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        persy.insert_record(&mut tx, "test", &bytes).unwrap();

        let mut tx1 = persy.begin().unwrap();
        persy.drop_segment(&mut tx1, "test").unwrap();
        persy.create_segment(&mut tx1, "test").unwrap();
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();

        let finalizer = persy.prepare_commit(tx);
        assert!(finalizer.is_err());
    });
}

#[test]
fn test_insert_record_of_dropped_segment_other_tx() {
    create_and_drop("irds", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let bytes = String::from("some").into_bytes();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        persy.insert_record(&mut tx, "test", &bytes).unwrap();

        let mut tx1 = persy.begin().unwrap();
        persy.drop_segment(&mut tx1, "test").unwrap();
        let finalizer = persy.prepare_commit(tx1).unwrap();
        persy.commit(finalizer).unwrap();

        let finalizer = persy.prepare_commit(tx);
        assert!(finalizer.is_err());
    });
}

#[test]
fn test_record_of_drop_segment_same_tx() {
    create_and_drop("rds", |persy| {
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();

        let mut tx = persy.begin().unwrap();
        let bytes = String::from("some").into_bytes();
        let id = persy
            .insert_record(&mut tx, "test", &bytes)
            .expect("insert record works");
        persy.drop_segment(&mut tx, "test").unwrap();
        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
        let mut tx = persy.begin().unwrap();
        persy.create_segment(&mut tx, "test").unwrap();
        assert!(
            match persy.update_record(&mut tx, "test", &id, &String::from("none").into_bytes()) {
                Err(PersyError::RecordNotFound(ref id2)) if *id2 == id => true,
                _ => false,
            }
        );
        assert_eq!(persy.read_record_tx(&mut tx, "test", &id).ok(), Some(None));

        let finalizer = persy.prepare_commit(tx).unwrap();
        persy.commit(finalizer).unwrap();
    });
}

#[test]
pub fn test_councurrent_double_create() {
    create_and_drop("concurrent_segment_double_create.", |persy| {
        let both_create = Arc::new(CountDown::new(2));
        let end = Arc::new(CountDown::new(2));
        for _ in [0; 2].iter() {
            let both_create_moved = both_create.clone();
            let end_moved = end.clone();
            let persy = persy.clone();
            thread::spawn(move || {
                let mut tx = persy.begin().expect("error on transaction begin");
                persy.create_segment(&mut tx, "def").expect("error on segment creation");
                both_create_moved.count_down().expect("lock not panic");
                both_create_moved.wait().expect("thread wait the other");
                let fin = persy.prepare_commit(tx).expect("error on commit prepare");
                persy.commit(fin).expect("error on commit");
                end_moved.count_down().expect("lock not panic");
            });
        }

        end.wait().expect("threas finisced");
        assert!(persy.exists_segment("def").unwrap());
    });
}

#[test]
pub fn test_councurrent_double_drop() {
    create_and_drop("concurrent_segment_double_drop.", |persy| {
        let mut tx = persy.begin().expect("error on transaction begin");
        persy.create_segment(&mut tx, "def").expect("error on segment creation");
        let fin = persy.prepare_commit(tx).expect("error on commit prepare");
        persy.commit(fin).expect("error on commit");
        let both_create = Arc::new(CountDown::new(2));
        let end = Arc::new(CountDown::new(2));
        for _ in [0; 2].iter() {
            let both_create_moved = both_create.clone();
            let end_moved = end.clone();
            let persy = persy.clone();
            thread::spawn(move || {
                let mut tx = persy.begin().expect("error on transaction begin");
                persy.drop_segment(&mut tx, "def").expect("error on segment creation");
                both_create_moved.count_down().expect("lock not panic");
                both_create_moved.wait().expect("thread wait the other");
                let fin = persy.prepare_commit(tx).expect("error on commit prepare");
                persy.commit(fin).expect("error on commit");
                end_moved.count_down().expect("lock not panic");
            });
        }

        end.wait().expect("threas finisced");
        assert!(!persy.exists_segment("def").unwrap());
    });
}

#[test]
pub fn test_list_segments() {
    create_and_drop("test_list_segments", |persy| {
        let mut tx = persy.begin().expect("error on transaction begin");
        persy.create_segment(&mut tx, "def").expect("error on segment creation");
        persy.create_segment(&mut tx, "two").expect("error on segment creation");
        let fin = persy.prepare_commit(tx).expect("error on commit prepare");
        persy.commit(fin).expect("error on commit");
        let segments = persy.list_segments().expect("list segments works as expected");
        assert_eq!(segments.len(), 2);
        let names = segments.into_iter().map(|(name, _id)| name).collect::<Vec<String>>();
        assert!(names.contains(&"def".to_string()));
        assert!(names.contains(&"two".to_string()));
    });
}

#[test]
pub fn test_list_segments_tx() {
    create_and_drop("test_list_segments", |persy| {
        let mut tx = persy.begin().expect("error on transaction begin");
        persy.create_segment(&mut tx, "def").expect("error on segment creation");
        persy.create_segment(&mut tx, "two").expect("error on segment creation");
        let fin = persy.prepare_commit(tx).expect("error on commit prepare");
        persy.commit(fin).expect("error on commit");

        let mut tx = persy.begin().expect("error on transaction begin");
        persy.drop_segment(&mut tx, "two").expect("error on segment drop");
        persy
            .create_segment(&mut tx, "three")
            .expect("error on segment creation");
        let segments = persy
            .list_segments_tx(&mut tx)
            .expect("list segments works as expected");
        assert_eq!(segments.len(), 2);
        let names = segments.into_iter().map(|x| x.0).collect::<Vec<String>>();
        assert!(names.contains(&"def".to_string()));
        assert!(names.contains(&"three".to_string()));
    });
}