|
1 | 1 | use sqlx::any::AnyPoolOptions;
|
| 2 | +use sqlx::Executor; |
| 3 | +use std::sync::atomic::AtomicI32; |
2 | 4 | use std::sync::{
|
3 | 5 | atomic::{AtomicUsize, Ordering},
|
4 | 6 | Arc,
|
@@ -64,3 +66,126 @@ async fn pool_should_be_returned_failed_transactions() -> anyhow::Result<()> {
|
64 | 66 |
|
65 | 67 | Ok(())
|
66 | 68 | }
|
| 69 | + |
| 70 | +#[sqlx_macros::test] |
| 71 | +async fn test_pool_callbacks() -> anyhow::Result<()> { |
| 72 | + sqlx_test::setup_if_needed(); |
| 73 | + |
| 74 | + #[derive(sqlx::FromRow, Debug, PartialEq, Eq)] |
| 75 | + struct ConnStats { |
| 76 | + id: i32, |
| 77 | + before_acquire_calls: i32, |
| 78 | + after_release_calls: i32, |
| 79 | + } |
| 80 | + |
| 81 | + let current_id = AtomicI32::new(0); |
| 82 | + |
| 83 | + let pool = AnyPoolOptions::new() |
| 84 | + .max_connections(1) |
| 85 | + .acquire_timeout(Duration::from_secs(5)) |
| 86 | + .after_connect(move |conn, meta| { |
| 87 | + assert_eq!(meta.age, Duration::ZERO); |
| 88 | + assert_eq!(meta.idle_for, Duration::ZERO); |
| 89 | + |
| 90 | + let id = current_id.fetch_add(1, Ordering::AcqRel); |
| 91 | + |
| 92 | + Box::pin(async move { |
| 93 | + let statement = format!( |
| 94 | + // language=SQL |
| 95 | + r#" |
| 96 | + CREATE TEMPORARY TABLE conn_stats( |
| 97 | + id int primary key, |
| 98 | + before_acquire_calls int default 0, |
| 99 | + after_release_calls int default 0 |
| 100 | + ); |
| 101 | + INSERT INTO conn_stats(id) VALUES ({}); |
| 102 | + "#, |
| 103 | + // Until we have generalized bind parameters |
| 104 | + id |
| 105 | + ); |
| 106 | + |
| 107 | + conn.execute(&statement[..]).await?; |
| 108 | + Ok(()) |
| 109 | + }) |
| 110 | + }) |
| 111 | + .before_acquire(|conn, meta| { |
| 112 | + // `age` and `idle_for` should both be nonzero |
| 113 | + assert_ne!(meta.age, Duration::ZERO); |
| 114 | + assert_ne!(meta.idle_for, Duration::ZERO); |
| 115 | + |
| 116 | + Box::pin(async move { |
| 117 | + let stats: ConnStats = sqlx::query_as( |
| 118 | + r#" |
| 119 | + UPDATE conn_stats |
| 120 | + SET before_acquire_calls = before_acquire_calls + 1 |
| 121 | + RETURNING * |
| 122 | + "#, |
| 123 | + ) |
| 124 | + .fetch_one(conn) |
| 125 | + .await?; |
| 126 | + |
| 127 | + // For even IDs, cap by the number of before_acquire calls. |
| 128 | + // Ignore the check for odd IDs. |
| 129 | + Ok((stats.id & 1) == 1 || stats.before_acquire_calls < 3) |
| 130 | + }) |
| 131 | + }) |
| 132 | + .after_release(|conn, meta| { |
| 133 | + // `age` should be nonzero but `idle_for` should be zero. |
| 134 | + assert_ne!(meta.age, Duration::ZERO); |
| 135 | + assert_eq!(meta.idle_for, Duration::ZERO); |
| 136 | + |
| 137 | + Box::pin(async move { |
| 138 | + let stats: ConnStats = sqlx::query_as( |
| 139 | + r#" |
| 140 | + UPDATE conn_stats |
| 141 | + SET after_release_calls = after_release_calls + 1 |
| 142 | + RETURNING * |
| 143 | + "#, |
| 144 | + ) |
| 145 | + .fetch_one(conn) |
| 146 | + .await?; |
| 147 | + |
| 148 | + // For odd IDs, cap by the number of before_release calls. |
| 149 | + // Ignore the check for even IDs. |
| 150 | + Ok((stats.id & 1) == 0 || stats.after_release_calls < 4) |
| 151 | + }) |
| 152 | + }) |
| 153 | + // Don't establish a connection yet. |
| 154 | + .connect_lazy(&dotenv::var("DATABASE_URL")?)?; |
| 155 | + |
| 156 | + // Expected pattern of (id, before_acquire_calls, after_release_calls) |
| 157 | + let pattern = [ |
| 158 | + // The connection pool starts empty. |
| 159 | + (0, 0, 0), |
| 160 | + (0, 1, 1), |
| 161 | + (0, 2, 2), |
| 162 | + (1, 0, 0), |
| 163 | + (1, 1, 1), |
| 164 | + (1, 2, 2), |
| 165 | + // We should expect one more `acquire` because the ID is odd |
| 166 | + (1, 3, 3), |
| 167 | + (2, 0, 0), |
| 168 | + (2, 1, 1), |
| 169 | + (2, 2, 2), |
| 170 | + (3, 0, 0), |
| 171 | + ]; |
| 172 | + |
| 173 | + for (id, before_acquire_calls, after_release_calls) in pattern { |
| 174 | + let conn_stats: ConnStats = sqlx::query_as("SELECT * FROM conn_stats") |
| 175 | + .fetch_one(&pool) |
| 176 | + .await?; |
| 177 | + |
| 178 | + assert_eq!( |
| 179 | + conn_stats, |
| 180 | + ConnStats { |
| 181 | + id, |
| 182 | + before_acquire_calls, |
| 183 | + after_release_calls |
| 184 | + } |
| 185 | + ); |
| 186 | + } |
| 187 | + |
| 188 | + pool.close().await; |
| 189 | + |
| 190 | + Ok(()) |
| 191 | +} |
0 commit comments