db_testkit/
tests.rs

1#[cfg(test)]
2use crate::{
3    backend::{Connection, DatabasePool},
4    backends::PostgresBackend,
5    env::get_postgres_url,
6    migrations::{RunSql, SqlSource},
7    pool::PoolConfig,
8    template::DatabaseTemplate,
9};
10
11#[cfg(all(test, feature = "mysql"))]
12use crate::{backends::MySqlBackend, env::get_mysql_url};
13
14#[allow(dead_code)]
15const SQL_SCRIPTS: &[&str] = &[
16    r#"
17    CREATE TABLE users (
18        id SERIAL PRIMARY KEY,
19        email VARCHAR(255) UNIQUE NOT NULL,
20        name VARCHAR(255) NOT NULL
21    );
22    "#,
23    r#"
24    ALTER TABLE users ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
25    "#,
26];
27
28#[tokio::test]
29#[cfg(feature = "postgres")]
30async fn test_postgres_template() {
31    let backend = PostgresBackend::new(&get_postgres_url().unwrap())
32        .await
33        .unwrap();
34
35    let template = DatabaseTemplate::new(backend, PoolConfig::default(), 5)
36        .await
37        .unwrap();
38
39    // Initialize template with SQL scripts
40    template
41        .initialize_template(|mut conn| async move {
42            conn.run_sql_scripts(&SqlSource::Embedded(SQL_SCRIPTS))
43                .await?;
44            Ok(())
45        })
46        .await
47        .unwrap();
48
49    // Get two separate databases
50    let db1 = template.get_immutable_database().await.unwrap();
51    let db2 = template.get_immutable_database().await.unwrap();
52
53    // Verify they are separate
54    let mut conn1 = db1.get_pool().acquire().await.unwrap();
55    let mut conn2 = db2.get_pool().acquire().await.unwrap();
56
57    // Insert into db1
58    conn1
59        .execute("INSERT INTO users (email, name) VALUES ('test1@example.com', 'Test User 1')")
60        .await
61        .unwrap();
62
63    // Insert into db2
64    conn2
65        .execute("INSERT INTO users (email, name) VALUES ('test2@example.com', 'Test User 2')")
66        .await
67        .unwrap();
68
69    // Verify data is separate
70    conn1
71        .execute("SELECT email FROM users WHERE email = 'test1@example.com'")
72        .await
73        .unwrap();
74
75    conn2
76        .execute("SELECT email FROM users WHERE email = 'test2@example.com'")
77        .await
78        .unwrap();
79}
80
81#[tokio::test]
82#[cfg(feature = "mysql")]
83async fn test_mysql_template() {
84    let backend = MySqlBackend::new(&get_mysql_url().unwrap()).unwrap();
85
86    let template = DatabaseTemplate::new(backend, PoolConfig::default(), 5)
87        .await
88        .unwrap();
89
90    // Initialize template with SQL scripts
91    template
92        .initialize_template(|mut conn| async move {
93            conn.run_sql_scripts(&SqlSource::Embedded(SQL_SCRIPTS))
94                .await?;
95            Ok(())
96        })
97        .await
98        .unwrap();
99
100    // Get two separate databases
101    let db1 = template.get_immutable_database().await.unwrap();
102    let db2 = template.get_immutable_database().await.unwrap();
103
104    // Verify they are separate
105    let mut conn1 = db1.get_pool().acquire().await.unwrap();
106    let mut conn2 = db2.get_pool().acquire().await.unwrap();
107
108    // Insert into db1
109    conn1
110        .execute("INSERT INTO users (email, name) VALUES ('test1@example.com', 'Test User 1')")
111        .await
112        .unwrap();
113
114    // Insert into db2
115    conn2
116        .execute("INSERT INTO users (email, name) VALUES ('test2@example.com', 'Test User 2')")
117        .await
118        .unwrap();
119
120    // Verify data is separate
121    conn1
122        .execute("SELECT email FROM users WHERE email = 'test1@example.com'")
123        .await
124        .unwrap();
125
126    conn2
127        .execute("SELECT email FROM users WHERE email = 'test2@example.com'")
128        .await
129        .unwrap();
130}
131
132#[tokio::test]
133#[cfg(feature = "postgres")]
134async fn test_parallel_databases() {
135    let backend = PostgresBackend::new(&get_postgres_url().unwrap())
136        .await
137        .unwrap();
138    let template = DatabaseTemplate::new(backend, PoolConfig::default(), 10)
139        .await
140        .unwrap();
141
142    // Initialize template
143    template
144        .initialize_template(|mut conn| async move {
145            conn.run_sql_scripts(&SqlSource::Embedded(SQL_SCRIPTS))
146                .await?;
147            Ok(())
148        })
149        .await
150        .unwrap();
151
152    // Create multiple databases concurrently
153    let mut handles = vec![];
154    for i in 0..5 {
155        let template = template.clone();
156        handles.push(tokio::spawn(async move {
157            let db = template.get_immutable_database().await.unwrap();
158            let mut conn = db.get_pool().acquire().await.unwrap();
159
160            // Insert data specific to this instance
161            conn.execute(&format!(
162                "INSERT INTO users (email, name) VALUES ('test{}@example.com', 'Test User {}')",
163                i, i
164            ))
165            .await
166            .unwrap();
167
168            // Verify only our data exists
169            conn.execute(&format!(
170                "SELECT * FROM users WHERE email = 'test{}@example.com'",
171                i
172            ))
173            .await
174            .unwrap();
175        }));
176    }
177
178    // Wait for all operations to complete
179    for handle in handles {
180        handle.await.unwrap();
181    }
182}
183
184#[tokio::test]
185#[cfg(feature = "postgres")]
186async fn test_concurrent_operations() {
187    let backend = PostgresBackend::new(&get_postgres_url().unwrap())
188        .await
189        .unwrap();
190    let template = DatabaseTemplate::new(backend, PoolConfig::default(), 1)
191        .await
192        .unwrap();
193
194    // Initialize template
195    template
196        .initialize_template(|mut conn| async move {
197            conn.run_sql_scripts(&SqlSource::Embedded(SQL_SCRIPTS))
198                .await?;
199            Ok(())
200        })
201        .await
202        .unwrap();
203
204    // Get a single database
205    let db = template.get_immutable_database().await.unwrap();
206
207    // Run concurrent operations on the same database
208    let mut handles = vec![];
209    for i in 0..5 {
210        let pool = db.get_pool().clone();
211        handles.push(tokio::spawn(async move {
212            let mut conn = pool.acquire().await.unwrap();
213            conn.execute(&format!(
214                "INSERT INTO users (email, name) VALUES ('concurrent{}@example.com', 'Concurrent User {}')",
215                i, i
216            ))
217            .await
218            .unwrap();
219        }));
220    }
221
222    // Wait for all operations to complete
223    for handle in handles {
224        handle.await.unwrap();
225    }
226
227    // Verify all data was inserted
228    let mut conn = db.get_pool().acquire().await.unwrap();
229    for i in 0..5 {
230        conn.execute(&format!(
231            "SELECT * FROM users WHERE email = 'concurrent{}@example.com'",
232            i
233        ))
234        .await
235        .unwrap();
236    }
237}