switchgear_testing/
db.rs

1use std::path::Path;
2use std::thread;
3
4pub struct TestMysqlDatabase {
5    db_name: String,
6    connection_url: String,
7    addr: String,
8}
9
10impl TestMysqlDatabase {
11    pub fn new(db_name: String, addr: &str, ssl: bool, ssl_ca: Option<&Path>) -> Self {
12        let addr_c = addr.to_string();
13        let db_name_clone = db_name.clone();
14        let _ = thread::spawn(move || {
15            let rt = match tokio::runtime::Runtime::new() {
16                Ok(rt) => rt,
17                Err(_) => return,
18            };
19
20            rt.block_on(async {
21                use sqlx::mysql::MySqlPoolOptions;
22
23                let pool = match MySqlPoolOptions::new()
24                    .connect(&format!("mysql://root:mysql@{addr_c}/mysql"))
25                    .await
26                {
27                    Ok(pool) => pool,
28                    Err(_) => return,
29                };
30
31                let _ = sqlx::query(&format!("CREATE DATABASE {db_name_clone}"))
32                    .execute(&pool)
33                    .await;
34            });
35        })
36        .join();
37
38        let ssl = if ssl { "?ssl-mode=VERIFY_IDENTITY" } else { "" };
39
40        let ssl_ca = match (!ssl.is_empty(), ssl_ca) {
41            (true, Some(ssl_ca)) => format!("&ssl-ca={}", ssl_ca.to_string_lossy()),
42            (_, _) => "".to_string(),
43        };
44
45        let connection_url = format!("mysql://root:mysql@{addr}/{db_name}{ssl}{ssl_ca}");
46        Self {
47            db_name,
48            connection_url,
49            addr: addr.to_string(),
50        }
51    }
52
53    pub fn connection_url(&self) -> &str {
54        &self.connection_url
55    }
56}
57
58impl Drop for TestMysqlDatabase {
59    fn drop(&mut self) {
60        let db_name = self.db_name.clone();
61        let addr = self.addr.clone();
62        let _ = thread::spawn(move || {
63            let rt = match tokio::runtime::Runtime::new() {
64                Ok(rt) => rt,
65                Err(_) => return,
66            };
67
68            rt.block_on(async {
69                use sqlx::mysql::MySqlPoolOptions;
70
71                let pool = match MySqlPoolOptions::new()
72                    .connect(&format!("mysql://root:mysql@{addr}/mysql"))
73                    .await
74                {
75                    Ok(pool) => pool,
76                    Err(_) => return,
77                };
78
79                let _ = sqlx::query(&format!("DROP DATABASE IF EXISTS {db_name}"))
80                    .execute(&pool)
81                    .await;
82            });
83        })
84        .join();
85    }
86}
87
88pub struct TestPostgresDatabase {
89    db_name: String,
90    connection_url: String,
91    addr: String,
92}
93
94impl TestPostgresDatabase {
95    pub fn new(db_name: String, addr: &str, ssl: bool, ssl_root_cert: Option<&Path>) -> Self {
96        let db_name_clone = db_name.clone();
97        let addr_c = addr.to_string();
98        let _ = thread::spawn(move || {
99            let rt = match tokio::runtime::Runtime::new() {
100                Ok(rt) => rt,
101                Err(_) => return,
102            };
103
104            rt.block_on(async {
105                use sqlx::postgres::PgPoolOptions;
106
107                let pool = match PgPoolOptions::new()
108                    .connect(&format!("postgres://postgres:postgres@{addr_c}/postgres"))
109                    .await
110                {
111                    Ok(pool) => pool,
112                    Err(_) => return,
113                };
114
115                let _ = sqlx::query(&format!("CREATE DATABASE {db_name_clone}"))
116                    .execute(&pool)
117                    .await;
118            });
119        })
120        .join();
121
122        let ssl = if ssl { "?sslmode=verify-full" } else { "" };
123
124        let ssl_root_cert = match (!ssl.is_empty(), ssl_root_cert) {
125            (true, Some(ssl_root_cert)) => {
126                format!("&sslrootcert={}", ssl_root_cert.to_string_lossy())
127            }
128            (_, _) => "".to_string(),
129        };
130
131        let connection_url =
132            format!("postgres://postgres:postgres@{addr}/{db_name}{ssl}{ssl_root_cert}");
133
134        Self {
135            db_name,
136            connection_url,
137            addr: addr.to_string(),
138        }
139    }
140
141    pub fn connection_url(&self) -> &str {
142        &self.connection_url
143    }
144}
145
146impl Drop for TestPostgresDatabase {
147    fn drop(&mut self) {
148        let db_name = self.db_name.clone();
149        let addr = self.addr.clone();
150        let _ = thread::spawn(move || {
151            let rt = match tokio::runtime::Runtime::new() {
152                Ok(rt) => rt,
153                Err(_) => return,
154            };
155
156            rt.block_on(async {
157                use sqlx::postgres::PgPoolOptions;
158
159                let pool = match PgPoolOptions::new()
160                    .connect(&format!("postgres://postgres:postgres@{addr}/postgres"))
161                    .await
162                {
163                    Ok(pool) => pool,
164                    Err(_) => return,
165                };
166
167                let _ = sqlx::query(&format!("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{db_name}' AND pid <>  pg_backend_pid()"))
168                    .execute(&pool).await;
169
170                let _ = sqlx::query(&format!("DROP DATABASE IF EXISTS {db_name}"))
171                    .execute(&pool)
172                    .await;
173            });
174        })
175            .join();
176    }
177}