Skip to content

Commit

Permalink
move to src/testing
Browse files Browse the repository at this point in the history
  • Loading branch information
NexVeridian committed Jan 21, 2025
1 parent cd7d90f commit 32e0f8f
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 92 deletions.
66 changes: 66 additions & 0 deletions src/testing/request.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,46 @@
use std::net::SocketAddr;

use axum_test::{TestServer, TestServerConfig};
use tokio::net::TcpListener;

use crate::{
app::{AppContext, Hooks},
boot::{self, BootResult},
config::Server,
environment::Environment,
Result,
};

/// The port on which the test server will run.
pub const TEST_PORT_SERVER: i32 = 5555;

/// The hostname to which the test server binds.
pub const TEST_BINDING_SERVER: &str = "localhost";

/// Constructs and returns the base URL used for the test server.
#[allow(dead_code)]
pub fn get_base_url() -> String {
format!("http://{TEST_BINDING_SERVER}:{TEST_PORT_SERVER}/")
}

/// Constructs and returns the base URL used for the test server.
pub fn get_base_url_port(port: i32) -> String {
format!("http://{TEST_BINDING_SERVER}:{port}/")
}

/// Returns a unique port number. Usually increments by 1 starting from 59126
pub async fn get_available_port() -> i32 {
let addr = format!("{}:0", TEST_BINDING_SERVER);
let listener = TcpListener::bind(addr)
.await
.expect("Failed to bind to address");
let port = listener
.local_addr()
.expect("Failed to get local address")
.port() as i32;
port
}

/// Bootstraps test application with test environment hard coded.
///
/// # Errors
Expand Down Expand Up @@ -37,6 +69,40 @@ pub async fn boot_test<H: Hooks>() -> Result<BootResult> {
H::boot(boot::StartMode::ServerOnly, &Environment::Test, config).await
}

/// Bootstraps test application with test environment hard coded,
/// and with a unique port.
///
/// # Errors
/// when could not bootstrap the test environment
///
/// # Example
///
/// The provided example demonstrates how to boot the test case with the
/// application context, and a with a unique port.
///
/// ```rust,ignore
/// use myapp::app::App;
/// use loco_rs::testing::prelude::*;
/// use migration::Migrator;
///
/// #[tokio::test]
/// async fn test_create_user() {
/// let port = get_available_port().await;
/// let boot = boot_test_unique_port::<App, Migrator>(Some(port)).await;
///
/// /// .....
/// assert!(false)
/// }
pub async fn boot_test_unique_port<H: Hooks>(port: Option<i32>) -> Result<BootResult> {
let mut config = H::load_config(&Environment::Test).await?;
config.server = Server {
port: port.unwrap_or(TEST_PORT_SERVER),
binding: TEST_BINDING_SERVER.to_string(),
..config.server
};
H::boot(boot::StartMode::ServerOnly, &Environment::Test, config).await
}

#[allow(clippy::future_not_send)]
/// Initiates a test request with a provided callback.
///
Expand Down
24 changes: 12 additions & 12 deletions tests/controller/into_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ async fn not_found() {
controller::not_found()
}

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

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

Expand Down Expand Up @@ -44,11 +44,11 @@ async fn internal_server_error() {
Err(Error::InternalServerError)
}

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

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

Expand Down Expand Up @@ -76,11 +76,11 @@ async fn unauthorized() {
controller::unauthorized("user not unauthorized")
}

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

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

Expand Down Expand Up @@ -108,11 +108,11 @@ async fn fallback() {
Err(Error::Message(String::new()))
}

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

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

Expand Down Expand Up @@ -147,11 +147,11 @@ async fn custom_error() {
))
}

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

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

Expand Down Expand Up @@ -185,13 +185,13 @@ async fn json_rejection() {
format::json(())
}

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

let client = reqwest::Client::new();
let res = client
.post(infra_cfg::server::get_base_url_port(port))
.post(get_base_url_port(port))
.json(&serde_json::json!({}))
.send()
.await
Expand Down
72 changes: 27 additions & 45 deletions tests/controller/middlewares.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ async fn panic(#[case] enable: bool) {
ctx.config.server.middlewares.catch_panic =
Some(middleware::catch_panic::CatchPanic { enable });

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

if enable {
let res = res.expect("valid response");
Expand Down Expand Up @@ -63,12 +63,12 @@ async fn etag(#[case] enable: bool) {

ctx.config.server.middlewares.etag = Some(middleware::etag::Etag { enable });

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

let res = reqwest::Client::new()
.get(infra_cfg::server::get_base_url_port(port))
.get(get_base_url_port(port))
.header("if-none-match", "loco-etag")
.send()
.await
Expand Down Expand Up @@ -100,12 +100,12 @@ async fn remote_ip(#[case] enable: bool, #[case] expected: &str) {
trusted_proxies: Some(vec!["192.1.1.1/8".to_string()]),
});

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

let res = reqwest::Client::new()
.get(infra_cfg::server::get_base_url_port(port))
.get(get_base_url_port(port))
.header(
"x-forwarded-for",
reqwest::header::HeaderValue::from_static("51.50.51.50,192.1.1.1"),
Expand Down Expand Up @@ -135,11 +135,11 @@ async fn timeout(#[case] enable: bool) {
ctx.config.server.middlewares.timeout_request =
Some(middleware::timeout::TimeOut { enable, timeout: 2 });

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

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

Expand Down Expand Up @@ -187,14 +187,11 @@ async fn cors(

ctx.config.server.middlewares.cors = Some(middleware);

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle = infra_cfg::server::start_from_ctx(ctx, Some(port.clone())).await;

let res = reqwest::Client::new()
.request(
reqwest::Method::OPTIONS,
infra_cfg::server::get_base_url_port(port),
)
.request(reqwest::Method::OPTIONS, get_base_url_port(port))
.send()
.await
.expect("valid response");
Expand Down Expand Up @@ -234,14 +231,11 @@ async fn limit_payload(#[case] limit: middleware::limit_payload::DefaultBodyLimi
ctx.config.server.middlewares.limit_payload =
Some(middleware::limit_payload::LimitPayload { body_limit: limit });

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle = infra_cfg::server::start_from_ctx(ctx, Some(port.clone())).await;

let res = reqwest::Client::new()
.request(
reqwest::Method::POST,
infra_cfg::server::get_base_url_port(port),
)
.request(reqwest::Method::POST, get_base_url_port(port))
.body("send body".repeat(100))
.send()
.await
Expand Down Expand Up @@ -290,27 +284,21 @@ async fn static_assets() {
precompressed: false,
});

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle = infra_cfg::server::start_from_ctx(ctx, Some(port.clone())).await;

let get_static_html = reqwest::get(format!(
"{}static/static.html",
infra_cfg::server::get_base_url_port(port)
))
.await
.expect("valid response");
let get_static_html = reqwest::get(format!("{}static/static.html", get_base_url_port(port)))
.await
.expect("valid response");

assert_eq!(
get_static_html.text().await.expect("text response"),
"<h1>static content</h1>".to_string()
);

let get_fallback = reqwest::get(format!(
"{}static/logo.png",
infra_cfg::server::get_base_url_port(port)
))
.await
.expect("valid response");
let get_fallback = reqwest::get(format!("{}static/logo.png", get_base_url_port(port)))
.await
.expect("valid response");

assert_eq!(
get_fallback.text().await.expect("text response"),
Expand Down Expand Up @@ -344,14 +332,11 @@ async fn secure_headers(
},
);

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle = infra_cfg::server::start_from_ctx(ctx, Some(port.clone())).await;

let res = reqwest::Client::new()
.request(
reqwest::Method::POST,
infra_cfg::server::get_base_url_port(port),
)
.request(reqwest::Method::POST, get_base_url_port(port))
.send()
.await
.expect("response");
Expand Down Expand Up @@ -422,15 +407,12 @@ async fn fallback(

ctx.config.server.middlewares.fallback = Some(fallback_config);

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle = infra_cfg::server::start_from_ctx(ctx, Some(port.clone())).await;

let res = reqwest::get(format!(
"{}not-found",
infra_cfg::server::get_base_url_port(port)
))
.await
.expect("valid response");
let res = reqwest::get(format!("{}not-found", get_base_url_port(port)))
.await
.expect("valid response");

if let Some(code) = code {
assert_eq!(res.status(), code);
Expand Down Expand Up @@ -461,10 +443,10 @@ async fn powered_by_header(#[case] ident: Option<String>) {

ctx.config.server.ident.clone_from(&ident);

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle = infra_cfg::server::start_from_ctx(ctx, Some(port.clone())).await;

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

Expand Down
8 changes: 4 additions & 4 deletions tests/controller/validation_extractor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async fn simple_validation(JsonValidate(_params): JsonValidate<Data>) -> Result<
async fn can_validation_with_response() {
let ctx = tests_cfg::app::get_app_context().await;

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle = infra_cfg::server::start_with_route(
ctx,
"/",
Expand All @@ -39,7 +39,7 @@ async fn can_validation_with_response() {

let client = reqwest::Client::new();
let res = client
.post(infra_cfg::server::get_base_url_port(port))
.post(get_base_url_port(port))
.json(&serde_json::json!({"name": "test", "email": "invalid"}))
.send()
.await
Expand Down Expand Up @@ -68,14 +68,14 @@ async fn can_validation_with_response() {
async fn can_validation_without_response() {
let ctx = tests_cfg::app::get_app_context().await;

let port = infra_cfg::server::get_available_port().await;
let port = get_available_port().await;
let handle =
infra_cfg::server::start_with_route(ctx, "/", post(simple_validation), Some(port.clone()))
.await;

let client = reqwest::Client::new();
let res = client
.post(infra_cfg::server::get_base_url_port(port))
.post(get_base_url_port(port))
.json(&serde_json::json!({"name": "test", "email": "invalid"}))
.send()
.await
Expand Down
Loading

0 comments on commit 32e0f8f

Please sign in to comment.