Skip to content
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
3 changes: 2 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::{
};

use async_trait::async_trait;
use axum::extract::FromRef;
use axum::Router as AxumRouter;
use dashmap::DashMap;

Expand Down Expand Up @@ -249,7 +250,7 @@ impl<T: 'static + Send + Sync> std::ops::Deref for RefGuard<'_, T> {
/// the web server to operate. It is typically used to store and manage shared
/// resources and settings that are accessible throughout the application's
/// lifetime.
#[derive(Clone)]
#[derive(Clone, FromRef)]
#[allow(clippy::module_name_repetitions)]
pub struct AppContext {
/// The environment in which the application is running.
Expand Down
95 changes: 95 additions & 0 deletions tests/controller/from_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use axum::extract::FromRef;
use loco_rs::{
app::{AppContext, SharedStore},
cache,
prelude::*,
tests_cfg,
};
use std::sync::Arc;

use crate::infra_cfg;

#[cfg(feature = "with-db")]
use sea_orm::DatabaseConnection;

/// Tests that DatabaseConnection can be extracted from AppContext via FromRef
#[cfg(feature = "with-db")]
#[tokio::test]
async fn can_extract_db_connection_from_app_context() {
let ctx = tests_cfg::app::get_app_context().await;

#[allow(clippy::items_after_statements)]
async fn action(State(ctx): State<AppContext>) -> Result<Response> {
// Use FromRef to extract DatabaseConnection from AppContext
let _db: DatabaseConnection = DatabaseConnection::from_ref(&ctx);
format::json(serde_json::json!({"extracted": "db"}))
}

let port = get_available_port().await;
let handle = infra_cfg::server::start_with_route(ctx, "/", get(action), Some(port)).await;

let res = reqwest::get(get_base_url_port(port))
.await
.expect("Valid response");

assert_eq!(res.status(), 200);

let body: serde_json::Value = res.json().await.expect("JSON response");
assert_eq!(body["extracted"], "db");

handle.abort();
}

/// Tests that Arc<Cache> can be extracted from AppContext via FromRef
#[tokio::test]
async fn can_extract_cache_from_app_context() {
let ctx = tests_cfg::app::get_app_context().await;

#[allow(clippy::items_after_statements)]
async fn action(State(ctx): State<AppContext>) -> Result<Response> {
// Use FromRef to extract Arc<Cache> from AppContext
let _cache: Arc<cache::Cache> = Arc::from_ref(&ctx);
format::json(serde_json::json!({"extracted": "cache"}))
}

let port = get_available_port().await;
let handle = infra_cfg::server::start_with_route(ctx, "/", get(action), Some(port)).await;

let res = reqwest::get(get_base_url_port(port))
.await
.expect("Valid response");

assert_eq!(res.status(), 200);

let body: serde_json::Value = res.json().await.expect("JSON response");
assert_eq!(body["extracted"], "cache");

handle.abort();
}

/// Tests that Arc<SharedStore> can be extracted from AppContext via FromRef
#[tokio::test]
async fn can_extract_shared_store_from_app_context() {
let ctx = tests_cfg::app::get_app_context().await;

#[allow(clippy::items_after_statements)]
async fn action(State(ctx): State<AppContext>) -> Result<Response> {
// Use FromRef to extract Arc<SharedStore> from AppContext
let _store: Arc<SharedStore> = Arc::from_ref(&ctx);
format::json(serde_json::json!({"extracted": "shared_store"}))
}

let port = get_available_port().await;
let handle = infra_cfg::server::start_with_route(ctx, "/", get(action), Some(port)).await;

let res = reqwest::get(get_base_url_port(port))
.await
.expect("Valid response");

assert_eq!(res.status(), 200);

let body: serde_json::Value = res.json().await.expect("JSON response");
assert_eq!(body["extracted"], "shared_store");

handle.abort();
}
1 change: 1 addition & 0 deletions tests/controller/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod extractor;
mod from_ref;
mod into_response;
mod middlewares;
Loading