Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a http_client::HttpClient implementation for tide::Server #697

Merged
merged 1 commit into from
Oct 3, 2020
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
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ async-std = { version = "1.6.0", features = ["unstable"] }
async-trait = "0.1.36"
femme = { version = "2.0.1", optional = true }
futures-util = "0.3.5"
log = { version = "0.4.8", features = ["std"] }
http-client = { version = "6.0.0", default-features = false }
http-types = "2.2.1"
kv-log-macro = "1.0.4"
log = { version = "0.4.8", features = ["std"] }
pin-project-lite = "0.1.7"
route-recognizer = "0.2.0"
serde = "1.0.102"
Expand All @@ -57,7 +58,7 @@ lazy_static = "1.4.0"
logtest = "2.0.0"
portpicker = "0.1.0"
serde = { version = "1.0.102", features = ["derive"] }
surf = { version = "2.0.0-alpha.3", default-features = false, features = ["h1-client"] }
surf = { version = "2.0.0-alpha.7", default-features = false, features = ["h1-client"] }
tempfile = "3.1.0"

[[test]]
Expand Down
15 changes: 14 additions & 1 deletion src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::log;
use crate::middleware::{Middleware, Next};
use crate::router::{Router, Selection};
use crate::{Endpoint, Request, Route};

/// An HTTP server.
///
/// Servers are built up as a combination of *state*, *endpoints* and *middleware*:
Expand All @@ -24,7 +25,6 @@ use crate::{Endpoint, Request, Route};
/// - Middleware extends the base Tide framework with additional request or
/// response processing, such as compression, default headers, or logging. To
/// add middleware to an app, use the [`Server::middleware`] method.
#[allow(missing_debug_implementations)]
pub struct Server<State> {
router: Arc<Router<State>>,
state: State,
Expand Down Expand Up @@ -245,6 +245,12 @@ impl<State: Clone + Send + Sync + 'static> Server<State> {
}
}

impl<State: Send + Sync + 'static> std::fmt::Debug for Server<State> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Server").finish()
}
}

impl<State: Clone> Clone for Server<State> {
fn clone(&self) -> Self {
Self {
Expand Down Expand Up @@ -284,6 +290,13 @@ impl<State: Clone + Sync + Send + 'static, InnerState: Clone + Sync + Send + 'st
}
}

#[crate::utils::async_trait]
impl<State: Clone + Send + Sync + Unpin + 'static> http_client::HttpClient for Server<State> {
async fn send(&self, req: crate::http::Request) -> crate::http::Result<crate::http::Response> {
self.respond(req).await
}
}

#[cfg(test)]
mod test {
use crate as tide;
Expand Down
10 changes: 6 additions & 4 deletions tests/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ mod test_utils;
use test_utils::ServerTestingExt;

#[async_std::test]
async fn log_tests() {
async fn log_tests() -> tide::Result<()> {
let mut logger = logtest::start();
test_server_listen(&mut logger).await;
test_only_log_once(&mut logger).await;
test_only_log_once(&mut logger).await?;
Ok(())
}

async fn test_server_listen(logger: &mut logtest::Logger) {
Expand All @@ -29,14 +30,14 @@ async fn test_server_listen(logger: &mut logtest::Logger) {
);
}

async fn test_only_log_once(logger: &mut logtest::Logger) {
async fn test_only_log_once(logger: &mut logtest::Logger) -> tide::Result<()> {
let mut app = tide::new();
app.at("/").nest({
let mut app = tide::new();
app.at("/").get(|_| async { Ok("nested") });
app
});
app.get("/").await;
assert!(app.get("/").await?.status().is_success());

let entries: Vec<_> = logger.collect();

Expand All @@ -55,4 +56,5 @@ async fn test_only_log_once(logger: &mut logtest::Logger) {
.filter(|entry| entry.args() == "--> Response sent")
.count()
);
Ok(())
}
29 changes: 16 additions & 13 deletions tests/nested.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod test_utils;
use test_utils::ServerTestingExt;

#[async_std::test]
async fn nested() {
async fn nested() -> tide::Result<()> {
let mut inner = tide::new();
inner.at("/foo").get(|_| async { Ok("foo") });
inner.at("/bar").get(|_| async { Ok("bar") });
Expand All @@ -11,12 +11,13 @@ async fn nested() {
// Nest the inner app on /foo
outer.at("/foo").nest(inner);

assert_eq!(outer.get_body("/foo/foo").await, "foo");
assert_eq!(outer.get_body("/foo/bar").await, "bar");
assert_eq!(outer.get("/foo/foo").recv_string().await?, "foo");
assert_eq!(outer.get("/foo/bar").recv_string().await?, "bar");
Ok(())
}

#[async_std::test]
async fn nested_middleware() {
async fn nested_middleware() -> tide::Result<()> {
let echo_path = |req: tide::Request<()>| async move { Ok(req.url().path().to_string()) };
let mut app = tide::new();
let mut inner_app = tide::new();
Expand All @@ -29,24 +30,25 @@ async fn nested_middleware() {
app.at("/foo").nest(inner_app);
app.at("/bar").get(echo_path);

let mut res = app.get("/foo/echo").await;
let mut res = app.get("/foo/echo").await?;
assert_eq!(res["X-Tide-Test"], "1");
assert_eq!(res.status(), 200);
assert_eq!(res.body_string().await.unwrap(), "/echo");
assert_eq!(res.body_string().await?, "/echo");

let mut res = app.get("/foo/x/bar").await;
let mut res = app.get("/foo/x/bar").await?;
assert_eq!(res["X-Tide-Test"], "1");
assert_eq!(res.status(), 200);
assert_eq!(res.body_string().await.unwrap(), "/");
assert_eq!(res.body_string().await?, "/");

let mut res = app.get("/bar").await;
let mut res = app.get("/bar").await?;
assert!(res.header("X-Tide-Test").is_none());
assert_eq!(res.status(), 200);
assert_eq!(res.body_string().await.unwrap(), "/bar");
assert_eq!(res.body_string().await?, "/bar");
Ok(())
}

#[async_std::test]
async fn nested_with_different_state() {
async fn nested_with_different_state() -> tide::Result<()> {
let mut outer = tide::new();
let mut inner = tide::with_state(42);
inner.at("/").get(|req: tide::Request<i32>| async move {
Expand All @@ -56,6 +58,7 @@ async fn nested_with_different_state() {
outer.at("/").get(|_| async { Ok("Hello, world!") });
outer.at("/foo").nest(inner);

assert_eq!(outer.get_body("/foo").await, "the number is 42");
assert_eq!(outer.get_body("/").await, "Hello, world!");
assert_eq!(outer.get("/foo").recv_string().await?, "the number is 42");
assert_eq!(outer.get("/").recv_string().await?, "Hello, world!");
Ok(())
}
6 changes: 4 additions & 2 deletions tests/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ async fn string_content_type() {
}

#[async_std::test]
async fn json_content_type() {
async fn json_content_type() -> tide::Result<()> {
use std::collections::BTreeMap;
use tide::Body;

Expand All @@ -51,7 +51,7 @@ async fn json_content_type() {
Ok(resp)
});

let mut resp = app.get("/json_content_type").await;
let mut resp = app.get("/json_content_type").await?;
assert_eq!(resp.status(), StatusCode::InternalServerError);
assert_eq!(resp.body_string().await.unwrap(), "");

Expand All @@ -68,6 +68,8 @@ async fn json_content_type() {
assert_eq!(resp.status(), StatusCode::Ok);
let body = resp.take_body().into_bytes().await.unwrap();
assert_eq!(body, br##"{"a":2,"b":4,"c":6}"##);

Ok(())
}

#[test]
Expand Down
30 changes: 17 additions & 13 deletions tests/route_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async fn echo_path<State>(req: tide::Request<State>) -> tide::Result<String> {
}

#[async_std::test]
async fn route_middleware() {
async fn route_middleware() -> tide::Result<()> {
let mut app = tide::new();
let mut foo_route = app.at("/foo");
foo_route // /foo
Expand All @@ -46,17 +46,18 @@ async fn route_middleware() {
.reset_middleware()
.put(echo_path);

assert_eq!(app.get("/foo").await["X-Foo"], "foo");
assert_eq!(app.post("/foo").await["X-Foo"], "foo");
assert!(app.put("/foo").await.header("X-Foo").is_none());
assert_eq!(app.get("/foo").await?["X-Foo"], "foo");
assert_eq!(app.post("/foo").await?["X-Foo"], "foo");
assert!(app.put("/foo").await?.header("X-Foo").is_none());

let res = app.get("/foo/bar").await;
let res = app.get("/foo/bar").await?;
assert_eq!(res["X-Foo"], "foo");
assert_eq!(res["x-bar"], "bar");
Ok(())
}

#[async_std::test]
async fn app_and_route_middleware() {
async fn app_and_route_middleware() -> tide::Result<()> {
let mut app = tide::new();
app.with(TestMiddleware::with_header_name("X-Root", "root"));
app.at("/foo")
Expand All @@ -66,19 +67,20 @@ async fn app_and_route_middleware() {
.with(TestMiddleware::with_header_name("X-Bar", "bar"))
.get(echo_path);

let res = app.get("/foo").await;
let res = app.get("/foo").await?;
assert_eq!(res["X-Root"], "root");
assert_eq!(res["x-foo"], "foo");
assert!(res.header("x-bar").is_none());

let res = app.get("/bar").await;
let res = app.get("/bar").await?;
assert_eq!(res["X-Root"], "root");
assert!(res.header("x-foo").is_none());
assert_eq!(res["X-Bar"], "bar");
Ok(())
}

#[async_std::test]
async fn nested_app_with_route_middleware() {
async fn nested_app_with_route_middleware() -> tide::Result<()> {
let mut inner = tide::new();
inner.with(TestMiddleware::with_header_name("X-Inner", "inner"));
inner
Expand All @@ -95,23 +97,24 @@ async fn nested_app_with_route_middleware() {
.with(TestMiddleware::with_header_name("X-Bar", "bar"))
.nest(inner);

let res = app.get("/foo").await;
let res = app.get("/foo").await?;
assert_eq!(res["X-Root"], "root");
assert!(res.header("X-Inner").is_none());
assert_eq!(res["X-Foo"], "foo");
assert!(res.header("X-Bar").is_none());
assert!(res.header("X-Baz").is_none());

let res = app.get("/bar/baz").await;
let res = app.get("/bar/baz").await?;
assert_eq!(res["X-Root"], "root");
assert_eq!(res["X-Inner"], "inner");
assert!(res.header("X-Foo").is_none());
assert_eq!(res["X-Bar"], "bar");
assert_eq!(res["X-Baz"], "baz");
Ok(())
}

#[async_std::test]
async fn subroute_not_nested() {
async fn subroute_not_nested() -> tide::Result<()> {
let mut app = tide::new();
app.at("/parent") // /parent
.with(TestMiddleware::with_header_name("X-Parent", "Parent"))
Expand All @@ -120,7 +123,8 @@ async fn subroute_not_nested() {
.with(TestMiddleware::with_header_name("X-Child", "child"))
.get(echo_path);

let res = app.get("/parent/child").await;
let res = app.get("/parent/child").await?;
assert!(res.header("X-Parent").is_none());
assert_eq!(res["x-child"], "child");
Ok(())
}
10 changes: 5 additions & 5 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use tide::{Body, Request};

#[test]
fn hello_world() -> Result<(), http_types::Error> {
fn hello_world() -> tide::Result<()> {
task::block_on(async {
let port = test_utils::find_port().await;
let server = task::spawn(async move {
Expand All @@ -25,7 +25,7 @@ fn hello_world() -> Result<(), http_types::Error> {
let client = task::spawn(async move {
task::sleep(Duration::from_millis(100)).await;
let string = surf::get(format!("http://localhost:{}", port))
.body("nori".to_string())
.body(Body::from_string("nori".to_string()))
.recv_string()
.await
.unwrap();
Expand All @@ -38,7 +38,7 @@ fn hello_world() -> Result<(), http_types::Error> {
}

#[test]
fn echo_server() -> Result<(), http_types::Error> {
fn echo_server() -> tide::Result<()> {
task::block_on(async {
let port = test_utils::find_port().await;
let server = task::spawn(async move {
Expand All @@ -52,7 +52,7 @@ fn echo_server() -> Result<(), http_types::Error> {
let client = task::spawn(async move {
task::sleep(Duration::from_millis(100)).await;
let string = surf::get(format!("http://localhost:{}", port))
.body("chashu".to_string())
.body(Body::from_string("chashu".to_string()))
.recv_string()
.await
.unwrap();
Expand All @@ -65,7 +65,7 @@ fn echo_server() -> Result<(), http_types::Error> {
}

#[test]
fn json() -> Result<(), http_types::Error> {
fn json() -> tide::Result<()> {
#[derive(Deserialize, Serialize)]
struct Counter {
count: usize,
Expand Down
Loading