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 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 let db1 = template.get_immutable_database().await.unwrap();
51 let db2 = template.get_immutable_database().await.unwrap();
52
53 let mut conn1 = db1.get_pool().acquire().await.unwrap();
55 let mut conn2 = db2.get_pool().acquire().await.unwrap();
56
57 conn1
59 .execute("INSERT INTO users (email, name) VALUES ('test1@example.com', 'Test User 1')")
60 .await
61 .unwrap();
62
63 conn2
65 .execute("INSERT INTO users (email, name) VALUES ('test2@example.com', 'Test User 2')")
66 .await
67 .unwrap();
68
69 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 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 let db1 = template.get_immutable_database().await.unwrap();
102 let db2 = template.get_immutable_database().await.unwrap();
103
104 let mut conn1 = db1.get_pool().acquire().await.unwrap();
106 let mut conn2 = db2.get_pool().acquire().await.unwrap();
107
108 conn1
110 .execute("INSERT INTO users (email, name) VALUES ('test1@example.com', 'Test User 1')")
111 .await
112 .unwrap();
113
114 conn2
116 .execute("INSERT INTO users (email, name) VALUES ('test2@example.com', 'Test User 2')")
117 .await
118 .unwrap();
119
120 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 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 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 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 conn.execute(&format!(
170 "SELECT * FROM users WHERE email = 'test{}@example.com'",
171 i
172 ))
173 .await
174 .unwrap();
175 }));
176 }
177
178 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 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 let db = template.get_immutable_database().await.unwrap();
206
207 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 for handle in handles {
224 handle.await.unwrap();
225 }
226
227 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}