use crate::internals::HttpTransportLayer;
use crate::transport_layer::IntoTransportLayer;
use crate::transport_layer::TransportLayer;
use crate::transport_layer::TransportLayerBuilder;
use crate::util::ServeHandle;
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
use axum::extract::Request;
use axum::response::Response;
use axum::serve::IncomingStream;
use axum::serve::Serve;
use std::convert::Infallible;
use tokio::net::TcpListener;
use tokio::spawn;
use tower::Service;
impl<M, S> IntoTransportLayer for Serve<TcpListener, M, S>
where
M: for<'a> Service<IncomingStream<'a, TcpListener>, Error = Infallible, Response = S>
+ Send
+ 'static,
for<'a> <M as Service<IncomingStream<'a, TcpListener>>>::Future: Send,
S: Service<Request, Response = Response, Error = Infallible> + Clone + Send + 'static,
S::Future: Send,
{
fn into_http_transport_layer(
self,
_builder: TransportLayerBuilder,
) -> Result<Box<dyn TransportLayer>> {
Err(anyhow!(
"`Serve` must be started with http or mock transport. Do not set any transport on `TestServerConfig`."
))
}
fn into_mock_transport_layer(self) -> Result<Box<dyn TransportLayer>> {
Err(anyhow!(
"`Serve` cannot be mocked, as it's underlying implementation requires a real connection. Do not set any transport on `TestServerConfig`."
))
}
fn into_default_transport(
self,
_builder: TransportLayerBuilder,
) -> Result<Box<dyn TransportLayer>> {
let socket_addr = self.local_addr()?;
let join_handle = spawn(async move {
self.await
.context("Failed to create ::axum::Server for TestServer")
.expect("Expect server to start serving");
});
let server_address = format!("http://{socket_addr}");
let server_url = server_address.parse()?;
Ok(Box::new(HttpTransportLayer::new(
ServeHandle::new(join_handle),
None,
server_url,
)))
}
}
#[cfg(test)]
mod test_into_http_transport_layer {
use crate::TestServer;
use crate::testing::catch_panic_error_message;
use crate::util::new_random_tokio_tcp_listener;
use axum::Router;
use axum::routing::IntoMakeService;
use axum::routing::get;
use axum::serve;
use pretty_assertions::assert_str_eq;
async fn get_ping() -> &'static str {
"pong!"
}
#[tokio::test]
async fn it_should_panic_when_run_with_http() {
let app: IntoMakeService<Router> = Router::new()
.route("/ping", get(get_ping))
.into_make_service();
let port = new_random_tokio_tcp_listener().unwrap();
let application = serve(port, app);
let message = catch_panic_error_message(|| {
TestServer::builder().http_transport().build(application);
});
assert_str_eq!("Failed to build TestServer,
`Serve` must be started with http or mock transport. Do not set any transport on `TestServerConfig`.
", message);
}
}
#[cfg(test)]
mod test_into_mock_transport_layer {
use crate::TestServer;
use crate::testing::catch_panic_error_message;
use crate::util::new_random_tokio_tcp_listener;
use axum::Router;
use axum::routing::IntoMakeService;
use axum::routing::get;
use axum::serve;
use pretty_assertions::assert_str_eq;
async fn get_ping() -> &'static str {
"pong!"
}
#[tokio::test]
async fn it_should_panic_when_run_with_mock_http() {
let app: IntoMakeService<Router> = Router::new()
.route("/ping", get(get_ping))
.into_make_service();
let port = new_random_tokio_tcp_listener().unwrap();
let application = serve(port, app);
let message = catch_panic_error_message(|| {
TestServer::builder().mock_transport().build(application);
});
assert_str_eq!("Failed to build TestServer,
`Serve` cannot be mocked, as it's underlying implementation requires a real connection. Do not set any transport on `TestServerConfig`.
", message);
}
}
#[cfg(test)]
mod test_into_default_transport {
use crate::TestServer;
use crate::util::new_random_tokio_tcp_listener;
use axum::Router;
use axum::routing::IntoMakeService;
use axum::routing::get;
use axum::serve;
async fn get_ping() -> &'static str {
"pong!"
}
#[tokio::test]
async fn it_should_run_service() {
let app: IntoMakeService<Router> = Router::new()
.route("/ping", get(get_ping))
.into_make_service();
let port = new_random_tokio_tcp_listener().unwrap();
let application = serve(port, app);
let server = TestServer::builder().build(application);
server.get(&"/ping").await.assert_text(&"pong!");
}
}