Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added diesel::r2d2::TestCustomizer #4186

Merged
merged 2 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Increasing the minimal supported Rust version will always be coupled at least wi
* Support for libsqlite3-sys 0.29.0
* Add support for built-in PostgreSQL range operators and functions
* Support for postgres multirange type
* Added `diesel::r2d2::TestCustomizer`, which allows users to customize their `diesel::r2d2::Pool`s
in a way that makes the pools suitable for use in parallel tests.

## [2.2.0] 2024-05-31

Expand Down
93 changes: 92 additions & 1 deletion diesel/src/r2d2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,85 @@
//! of the `AnsiTransactionManager` struct) is in an `InError` state
//! or contains an open transaction when the connection goes out of scope.
//!

//!
//! # Testing with connections pools
//!
//! When testing with connection pools, it is recommended to set the pool size to 1,
//! and use a customizer to ensure that the transactions are never committed.
//! The tests using a pool prepared this way can be run in parallel, because
//! the changes are never committed to the database and are local to each test.
//!
//! # Example
//!
//! ```rust
//! # include!("doctest_setup.rs");
//! use diesel::prelude::*;
//! use diesel::r2d2::ConnectionManager;
//! use diesel::r2d2::CustomizeConnection;
//! use diesel::r2d2::TestCustomizer;
//! # use diesel::r2d2::Error as R2D2Error;
//! use diesel::r2d2::Pool;
//! use diesel::result::Error;
//! use std::thread;
//!
//! # fn main() {}
//!
//! pub fn get_testing_pool() -> Pool<ConnectionManager<DbConnection>> {
//! let url = database_url_for_env();
//! let manager = ConnectionManager::<DbConnection>::new(url);
//!
//! Pool::builder()
//! .test_on_check_out(true)
//! .max_size(1) // Max pool size set to 1
//! .connection_customizer(Box::new(TestCustomizer)) // Test customizer
//! .build(manager)
//! .expect("Could not build connection pool")
//! }
//!
//! table! {
//! users {
//! id -> Integer,
//! name -> Text,
//! }
//! }
//!
//! #[cfg(test)]
//! mod tests {
//! use super::*;
//!
//! #[test]
//! fn test_1() {
//! let pool = get_testing_pool();
//! let mut conn = pool.get().unwrap();
//!
//! crate::sql_query(
//! "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)",
//! )
//! .execute(&mut conn)
//! .unwrap();
//!
//! crate::insert_into(users::table)
//! .values(users::name.eq("John"))
//! .execute(&mut conn)
//! .unwrap();
//! }
//!
//! #[test]
//! fn test_2() {
//! let pool = get_testing_pool();
//! let mut conn = pool.get().unwrap();
//!
//! crate::sql_query(
//! "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT NOT NULL)",
//! )
//! .execute(&mut conn)
//! .unwrap();
//!
//! let user_count = users::table.count().get_result::<i64>(&mut conn).unwrap();
//! assert_eq!(user_count, 0); // Because the transaction from test_1 was never committed
//! }
//! }
//! ```
pub use r2d2::*;

/// A re-export of [`r2d2::Error`], which is only used by methods on [`r2d2::Pool`].
Expand Down Expand Up @@ -361,6 +439,19 @@ impl Query for CheckConnectionQuery {

impl<C> RunQueryDsl<C> for CheckConnectionQuery {}

/// A connection customizer designed for use in tests. Implements
/// [CustomizeConnection] in a way that ensures transactions
/// in a pool customized by it are never committed.
#[derive(Debug, Clone, Copy)]
pub struct TestCustomizer;

impl<C: Connection> CustomizeConnection<C, crate::r2d2::Error> for TestCustomizer {
fn on_acquire(&self, conn: &mut C) -> Result<(), crate::r2d2::Error> {
conn.begin_test_transaction()
.map_err(crate::r2d2::Error::QueryError)
}
}

#[cfg(test)]
mod tests {
use std::sync::mpsc;
Expand Down
Loading