1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use diesel::prelude::SqliteConnection;
use diesel::r2d2::{self, ConnectionManager, PooledConnection};

pub type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;

/// Test database builder
/// 
pub struct TestDb {
    pub pool: Pool,
    pub db_path: std::path::PathBuf,
    pub tmp_dir: tempfile::TempDir,
}

impl TestDb {
    /// Creates empty SQLite database using `tempfile` ( file: `test.db` folder based on `CARGO_PKG_NAME` )
    pub fn new() -> TestDb {
        // Create temporary dir where db will be stored
        let tmp_dir = tempfile::Builder::new()
            .prefix(env!("CARGO_PKG_NAME"))
            .rand_bytes(5)
            .tempdir()
            .expect("not possible to create tempfile");

        let db_path = tmp_dir.path().join("test.db");

        // Connection manager
        let manager = r2d2::ConnectionManager::<SqliteConnection>::new(db_path.to_str().unwrap());
        // Creates database if does not exists
        let pool = r2d2::Pool::builder()
            .build(manager)
            .expect("Failed to create pool.");

        TestDb {
            tmp_dir,
            db_path,
            pool,
        }
    }

    /// Pooled connection
    pub fn conn(&self) -> Option<PooledConnection<ConnectionManager<SqliteConnection>>> {
        // Result -> Ok
        self.pool.get().ok()
    }

}

#[cfg(test)]
mod tests {
    use super::*;

    /// Expecting that created database will be deleted upon TestDb drop ( out of scope )
    #[test]
    fn test_lifecycle() {
        let test_db = TestDb::new();

        // Path with database must exists
        let path = test_db.db_path.to_owned();
        assert!(path.exists());

        let dirpath: std::path::PathBuf = test_db.tmp_dir.path().to_path_buf();

        assert!(dirpath.exists());

        // Path after TestDb is drop must not exists
        let parent = dirpath.parent().unwrap();

        let list = std::fs::read_dir(&parent).unwrap();
        for item in list {
            println!("Name: {:?}", item);
        }

        drop(test_db);

        let list = std::fs::read_dir(&parent).unwrap();
        for item in list {
            println!("Name: {:?}", item);
        }

        // On Windows/GitHub Actions problem with failing #9
        std::thread::sleep(std::time::Duration::from_millis(100));

        assert!(!dirpath.exists());
        assert!(!path.exists());
    }
}