From 033cd48969e974814e4803e24d02f90a88e15a7d Mon Sep 17 00:00:00 2001 From: Samir Talwar Date: Tue, 20 Aug 2024 11:27:28 +0200 Subject: [PATCH] Inline axum-test-helper. 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 --- Cargo.lock | 35 +--------------- crates/sdk/Cargo.toml | 2 +- crates/sdk/src/connector/example.rs | 26 ------------ crates/sdk/src/json_response.rs | 62 ++++++++++++++++++++++++----- 4 files changed, 53 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 222e13f..5c5d07e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,24 +211,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "axum-test-helper" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298f62fa902c2515c169ab0bfb56c593229f33faa01131215d58e3d4898e3aa9" -dependencies = [ - "axum", - "bytes", - "http", - "http-body", - "hyper", - "reqwest", - "serde", - "tokio", - "tower", - "tower-service", -] - [[package]] name = "backtrace" version = "0.3.73" @@ -1000,10 +982,10 @@ dependencies = [ name = "ndc-sdk" version = "0.4.0" dependencies = [ + "anyhow", "async-trait", "axum", "axum-extra", - "axum-test-helper", "bytes", "clap", "http", @@ -1540,12 +1522,10 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", "winreg", ] @@ -2505,19 +2485,6 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" -[[package]] -name = "wasm-streams" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.70" diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index d27e1ae..26f1238 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -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" diff --git a/crates/sdk/src/connector/example.rs b/crates/sdk/src/connector/example.rs index b125f3b..e5ffe66 100644 --- a/crates/sdk/src/connector/example.rs +++ b/crates/sdk/src/connector/example.rs @@ -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::(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(()) - } -} diff --git a/crates/sdk/src/json_response.rs b/crates/sdk/src/json_response.rs index 85be6e8..6cebb01 100644 --- a/crates/sdk/src/json_response.rs +++ b/crates/sdk/src/json_response.rs @@ -58,13 +58,13 @@ impl IntoResponse for JsonResponse { #[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 { @@ -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); @@ -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::(r#"{"name":"Bob Davis","age":7}"#.into()) + JsonResponse::Serialized::(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); @@ -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)] @@ -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 { + 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)) + } + } +}