postgresql_commands/
pg_test_fsync.rs

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::traits::CommandBuilder;
use crate::Settings;
use std::convert::AsRef;
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;

/// `pg_test_fsync` command to determine fastest `wal_sync_method` for `PostgreSQL`
#[derive(Clone, Debug, Default)]
pub struct PgTestFsyncBuilder {
    program_dir: Option<PathBuf>,
    envs: Vec<(OsString, OsString)>,
    filename: Option<OsString>,
    secs_per_test: Option<usize>,
}

impl PgTestFsyncBuilder {
    /// Create a new [`PgTestFsyncBuilder`]
    #[must_use]
    pub fn new() -> Self {
        Self::default()
    }

    /// Create a new [`PgTestFsyncBuilder`] from [Settings]
    pub fn from(settings: &dyn Settings) -> Self {
        Self::new().program_dir(settings.get_binary_dir())
    }

    /// Location of the program binary
    #[must_use]
    pub fn program_dir<P: Into<PathBuf>>(mut self, path: P) -> Self {
        self.program_dir = Some(path.into());
        self
    }

    /// Set the filename
    #[must_use]
    pub fn filename<S: AsRef<OsStr>>(mut self, filename: S) -> Self {
        self.filename = Some(filename.as_ref().to_os_string());
        self
    }

    /// Set the seconds per test
    #[must_use]
    pub fn secs_per_test(mut self, secs: usize) -> Self {
        self.secs_per_test = Some(secs);
        self
    }
}

impl CommandBuilder for PgTestFsyncBuilder {
    /// Get the program name
    fn get_program(&self) -> &'static OsStr {
        "pg_test_fsync".as_ref()
    }

    /// Location of the program binary
    fn get_program_dir(&self) -> &Option<PathBuf> {
        &self.program_dir
    }

    /// Get the arguments for the command
    fn get_args(&self) -> Vec<OsString> {
        let mut args: Vec<OsString> = Vec::new();

        if let Some(filename) = &self.filename {
            args.push("-f".into());
            args.push(filename.into());
        }

        if let Some(secs) = &self.secs_per_test {
            args.push("-s".into());
            args.push(secs.to_string().into());
        }

        args
    }

    /// Get the environment variables for the command
    fn get_envs(&self) -> Vec<(OsString, OsString)> {
        self.envs.clone()
    }

    /// Set an environment variable for the command
    fn env<S: AsRef<OsStr>>(mut self, key: S, value: S) -> Self {
        self.envs
            .push((key.as_ref().to_os_string(), value.as_ref().to_os_string()));
        self
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::traits::CommandToString;
    use crate::TestSettings;
    use test_log::test;

    #[test]
    fn test_builder_new() {
        let command = PgTestFsyncBuilder::new().program_dir(".").build();
        assert_eq!(
            PathBuf::from(".").join("pg_test_fsync"),
            PathBuf::from(command.to_command_string().replace('"', ""))
        );
    }

    #[test]
    fn test_builder_from() {
        let command = PgTestFsyncBuilder::from(&TestSettings).build();
        #[cfg(not(target_os = "windows"))]
        let command_prefix = r#""./pg_test_fsync""#;
        #[cfg(target_os = "windows")]
        let command_prefix = r#"".\\pg_test_fsync""#;

        assert_eq!(format!("{command_prefix}"), command.to_command_string());
    }

    #[test]
    fn test_builder() {
        let command = PgTestFsyncBuilder::new()
            .env("PGDATABASE", "database")
            .filename("filename")
            .secs_per_test(10)
            .build();
        #[cfg(not(target_os = "windows"))]
        let command_prefix = r#"PGDATABASE="database" "#;
        #[cfg(target_os = "windows")]
        let command_prefix = String::new();

        assert_eq!(
            format!(r#"{command_prefix}"pg_test_fsync" "-f" "filename" "-s" "10""#),
            command.to_command_string()
        );
    }
}