Skip to content

Commit

Permalink
docs: Use MockProvideRef<DatabaseConnection> in an example test
Browse files Browse the repository at this point in the history
Add an example of using `MockProvideRef<DatabaseConnection>` to provide
a `MockDatabase` from SeaORM in a test.
  • Loading branch information
spencewenski committed Nov 17, 2024
1 parent 684e52b commit 83c1a94
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 6 deletions.
8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ otel = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp",
grpc = ["dep:tonic"]
testing = ["dep:insta", "dep:rstest", "dep:testcontainers-modules"]
test-containers = ["testing", "dep:testcontainers-modules"]
testing-mocks = ["testing", "dep:mockall"]
testing-mocks = ["testing", "dep:mockall", "sea-orm?/mock"]
config-yml = ["config/yaml"]

[dependencies]
Expand Down Expand Up @@ -110,10 +110,10 @@ strum_macros = { workspace = true }
itertools = { workspace = true }
toml = "0.8.0"
url = { version = "2.5.0", features = ["serde"] }
uuid = { version = "1.10.0", features = ["v4", "serde"] }
uuid = { workspace = true }
futures = "0.3.30"
futures-core = "0.3.31"
chrono = { version = "0.4.34", features = ["serde"] }
chrono = { workspace = true, features = ["serde"] }
byte-unit = { version = "5.0.0", features = ["serde"] }
convert_case = "0.6.0"
const_format = "0.2.32"
Expand Down Expand Up @@ -198,6 +198,8 @@ cargo-manifest = "0.15.0"
typed-builder = "0.20.0"
rand = "0.8.5"
thiserror = "2.0.0"
uuid = { version = "1.10.0", features = ["v4", "serde"] }
chrono = { version = "0.4.34", features = ["serde"] }

[package.metadata.docs.rs]
# Have docs.rs pass `--all-features` to ensure all features have their documentation built.
Expand Down
7 changes: 7 additions & 0 deletions examples/full/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ serde = { workspace = true, features = ["derive"] }
lettre = { workspace = true, features = ["pool"] }
sendgrid = { workspace = true }

# Other
uuid = { workspace = true, features = ["v7"] }
chrono = { workspace = true, features = ["serde"] }

[dev-dependencies]
roadster = { version = "0.6", path = "../..", features = ["testing-mocks"] }

[build-dependencies]
tonic-build = { workspace = true }
vergen = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions examples/full/src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
/// be in the same crate as our application-specific logic in order to use `impl` on the models
/// contained in [`entity`].
pub mod entity;

pub mod user;
72 changes: 72 additions & 0 deletions examples/full/src/model/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::model::entity::prelude::User;
use crate::model::entity::user;
use roadster::app::context::ProvideRef;
use roadster::error::RoadsterResult;
use sea_orm::{DatabaseConnection, EntityTrait};
use uuid::Uuid;

impl user::Model {
pub async fn find_by_id(
db: impl ProvideRef<DatabaseConnection>,
id: Uuid,
) -> RoadsterResult<Self> {
let user =
User::find_by_id(id)
.one(db.provide())
.await?
.ok_or(sea_orm::DbErr::RecordNotFound(format!(
"User with id {id} not found"
)))?;

Ok(user)
}
}

#[cfg(test)]
mod tests {
use crate::model::entity::user;
use chrono::Utc;
use roadster::app::context::MockProvideRef;
use sea_orm::{DatabaseBackend, DatabaseConnection, MockDatabase};
use uuid::Uuid;

#[tokio::test]
async fn find_by_id() {
let id = Uuid::now_v7();
let mut provide_db = MockProvideRef::<DatabaseConnection>::new();
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_query_results([vec![test_user(id)]])
.into_connection();
provide_db.expect_provide().return_const(db);

let user = user::Model::find_by_id(provide_db, id).await.unwrap();

assert_eq!(id, user.id);
assert_eq!(id.to_string(), user.name);
assert_eq!(id.to_string(), user.username);
}

fn test_user(id: Uuid) -> user::Model {
let now = Utc::now();
user::Model {
id,
created_at: now.into(),
updated_at: now.into(),
name: id.to_string(),
username: id.to_string(),
email: format!("{id}@example.com"),
password: "password".to_string(),
last_sign_in_at: now.into(),
password_updated_at: now.into(),
email_confirmation_sent_at: None,
email_confirmation_token: None,
email_confirmed_at: None,
recovery_sent_at: None,
recovery_token: None,
email_change_sent_at: None,
email_change_token_new: None,
email_change_token_current: None,
deleted_at: None,
}
}
}
4 changes: 3 additions & 1 deletion src/app/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,9 @@ impl ProvideRef<DatabaseConnection> for AppContext {
}
}

#[cfg(feature = "db-sql")]
/// Unfortunately, [`Provide<DatabaseConnection>`] can not be implemented when the `sea-orm/mock`
/// feature is enabled because `MockDatabase` is not [`Clone`]
#[cfg(all(feature = "db-sql", not(feature = "testing-mocks")))]
impl Provide<DatabaseConnection> for AppContext {
fn provide(&self) -> DatabaseConnection {
self.db().clone()
Expand Down
4 changes: 2 additions & 2 deletions src/service/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ where

info!("Received shutdown signal. Shutting down gracefully.");

#[cfg(feature = "db-sql")]
#[cfg(all(feature = "db-sql", not(feature = "testing-mocks")))]
let db_close_result = {
info!("Closing the DB connection pool.");
context.db().clone().close().await
Expand All @@ -251,7 +251,7 @@ where
info!("Running App::graceful_shutdown.");
let app_graceful_shutdown_result = app_graceful_shutdown.await;

#[cfg(feature = "db-sql")]
#[cfg(all(feature = "db-sql", not(feature = "testing-mocks")))]
db_close_result?;
app_graceful_shutdown_result?;

Expand Down

0 comments on commit 83c1a94

Please sign in to comment.