Skip to content

Commit

Permalink
Inline axum-test-helper. (#33)
Browse files Browse the repository at this point in the history
Its dependency tree does not agree with us.

We can simply reproduce the [`TestClient`][test_client.rs] from the
internals of `axum` ourselves (which is what `axum-test-helper` does,
too).

Our version has even fewer features, because we only need to support
`GET` requests.

[test_client.rs]:
https://github.com/tokio-rs/axum/blob/axum-v0.6.20/axum/src/test_helpers/test_client.rs
  • Loading branch information
SamirTalwar authored Aug 26, 2024
1 parent ece6065 commit 8954156
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 72 deletions.
35 changes: 1 addition & 34 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ tracing-subscriber = { version = "0.3", default-features = false, features = ["a
url = "2"

[dev-dependencies]
axum-test-helper = "0.3"
anyhow = "1"
26 changes: 0 additions & 26 deletions crates/sdk/src/connector/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,29 +112,3 @@ impl Connector for Example {
todo!()
}
}

#[cfg(test)]
mod tests {
use std::path::PathBuf;

use axum_test_helper::TestClient;
use http::StatusCode;

use super::*;

#[tokio::test]
async fn capabilities_match_ndc_spec_version() -> Result<()> {
let state =
crate::default_main::init_server_state(Example::default(), &PathBuf::new()).await?;
let app = crate::default_main::create_router::<Example>(state, None, None);

let client = TestClient::new(app);
let response = client.get("/capabilities").send().await;

assert_eq!(response.status(), StatusCode::OK);

let body: ndc_models::CapabilitiesResponse = response.json().await;
assert_eq!(body.version, ndc_models::VERSION);
Ok(())
}
}
62 changes: 51 additions & 11 deletions crates/sdk/src/json_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ impl<A: serde::Serialize> IntoResponse for JsonResponse<A> {
#[cfg(test)]
mod tests {
use axum::{routing, Router};
use axum_test_helper::TestClient;
use reqwest::StatusCode;

use super::test_client::TestClient;
use super::*;

#[tokio::test]
async fn serializes_value_to_json() {
async fn serializes_value_to_json() -> anyhow::Result<()> {
let app = Router::new().route(
"/",
routing::get(|| async {
Expand All @@ -75,8 +75,8 @@ mod tests {
}),
);

let client = TestClient::new(app);
let response = client.get("/").send().await;
let client = TestClient::new(app)?;
let response = client.get("/").send().await?;

assert_eq!(response.status(), StatusCode::OK);

Expand All @@ -86,21 +86,22 @@ mod tests {
vec!["application/json"]
);

let body = response.text().await;
let body = response.text().await?;
assert_eq!(body, r#"{"name":"Alice Appleton","age":42}"#);
Ok(())
}

#[tokio::test]
async fn writes_json_string_directly() {
async fn writes_json_string_directly() -> anyhow::Result<()> {
let app = Router::new().route(
"/",
routing::get(|| async {
JsonResponse::Serialized::<Person>(r#"{"name":"Bob Davis","age":7}"#.into())
JsonResponse::Serialized::<Person>(Bytes::from(r#"{"name":"Bob Burger","age":7}"#))
}),
);

let client = TestClient::new(app);
let response = client.get("/").send().await;
let client = TestClient::new(app)?;
let response = client.get("/").send().await?;

assert_eq!(response.status(), StatusCode::OK);

Expand All @@ -110,8 +111,9 @@ mod tests {
vec!["application/json"]
);

let body = response.text().await;
assert_eq!(body, r#"{"name":"Bob Davis","age":7}"#);
let body = response.text().await?;
assert_eq!(body, r#"{"name":"Bob Burger","age":7}"#);
Ok(())
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
Expand All @@ -120,3 +122,41 @@ mod tests {
age: u16,
}
}

#[cfg(test)]
pub mod test_client {
use std::net::SocketAddr;

const LOCALHOST: std::net::IpAddr = std::net::IpAddr::V6(std::net::Ipv6Addr::LOCALHOST);

pub struct TestClient {
address: SocketAddr,
client: reqwest::Client,
}

impl TestClient {
pub fn new(router: axum::Router) -> anyhow::Result<Self> {
let listener = std::net::TcpListener::bind(std::net::SocketAddr::new(LOCALHOST, 0))?;
let address = listener.local_addr()?;

// we ignore the handle and let the test runner clean up the server
tokio::spawn(async move {
axum::Server::from_tcp(listener)
.expect("server error")
.serve(router.into_make_service())
.await
.expect("server error");
});

let client = reqwest::Client::builder()
.redirect(reqwest::redirect::Policy::none())
.build()?;

Ok(TestClient { address, client })
}

pub fn get(&self, url: &str) -> reqwest::RequestBuilder {
self.client.get(format!("http://{}{}", self.address, url))
}
}
}

0 comments on commit 8954156

Please sign in to comment.