Skip to content

Commit 986f477

Browse files
committed
Ensure tests don't leak database connections
Even if a pool instance is leaked (such as when the web server is leaked), internally drop the actual pool at the end of the test to ensure all connections are closed.
1 parent 67080e8 commit 986f477

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

src/db/pool.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ const DEFAULT_SCHEMA: &str = "public";
1010

1111
#[derive(Debug, Clone)]
1212
pub struct Pool {
13+
#[cfg(test)]
14+
pool: Arc<std::sync::Mutex<Option<r2d2::Pool<PostgresConnectionManager<NoTls>>>>>,
15+
#[cfg(not(test))]
1316
pool: r2d2::Pool<PostgresConnectionManager<NoTls>>,
1417
metrics: Arc<Metrics>,
1518
max_size: u32,
@@ -43,14 +46,31 @@ impl Pool {
4346
.map_err(PoolError::PoolCreationFailed)?;
4447

4548
Ok(Pool {
49+
#[cfg(test)]
50+
pool: Arc::new(std::sync::Mutex::new(Some(pool))),
51+
#[cfg(not(test))]
4652
pool,
4753
metrics,
4854
max_size: config.max_pool_size,
4955
})
5056
}
5157

58+
fn with_pool<R>(
59+
&self,
60+
f: impl FnOnce(&r2d2::Pool<PostgresConnectionManager<NoTls>>) -> R,
61+
) -> R {
62+
#[cfg(test)]
63+
{
64+
f(&self.pool.lock().unwrap().as_ref().unwrap())
65+
}
66+
#[cfg(not(test))]
67+
{
68+
f(&self.pool)
69+
}
70+
}
71+
5272
pub fn get(&self) -> Result<PoolClient, PoolError> {
53-
match self.pool.get() {
73+
match self.with_pool(|p| p.get()) {
5474
Ok(conn) => Ok(conn),
5575
Err(err) => {
5676
self.metrics.failed_db_connections.inc();
@@ -60,16 +80,21 @@ impl Pool {
6080
}
6181

6282
pub(crate) fn used_connections(&self) -> u32 {
63-
self.pool.state().connections - self.pool.state().idle_connections
83+
self.with_pool(|p| p.state().connections - p.state().idle_connections)
6484
}
6585

6686
pub(crate) fn idle_connections(&self) -> u32 {
67-
self.pool.state().idle_connections
87+
self.with_pool(|p| p.state().idle_connections)
6888
}
6989

7090
pub(crate) fn max_size(&self) -> u32 {
7191
self.max_size
7292
}
93+
94+
#[cfg(test)]
95+
pub(crate) fn shutdown(&self) {
96+
self.pool.lock().unwrap().take();
97+
}
7398
}
7499

75100
#[derive(Debug)]

src/test/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,13 +309,16 @@ impl TestDatabase {
309309

310310
impl Drop for TestDatabase {
311311
fn drop(&mut self) {
312-
crate::db::migrate(Some(0), &mut self.conn()).expect("downgrading database works");
312+
let migration_result = crate::db::migrate(Some(0), &mut self.conn());
313313
if let Err(e) = self.conn().execute(
314314
format!("DROP SCHEMA {} CASCADE;", self.schema).as_str(),
315315
&[],
316316
) {
317317
error!("failed to drop test schema {}: {}", self.schema, e);
318318
}
319+
// Drop the connection pool so we don't leak database connections
320+
self.pool.shutdown();
321+
migration_result.expect("downgrading database works");
319322
}
320323
}
321324

0 commit comments

Comments
 (0)