#![allow(clippy::missing_panics_doc)]
use core::str::FromStr;
use bytes::Bytes;
use http::{HeaderName, HeaderValue, Request, Response, StatusCode, header::CONTENT_TYPE};
use http_body_util::{Empty, Full};
use mime::APPLICATION_JSON;
use serde::de::DeserializeOwned;
pub trait ResponseTestExt {
fn body<T: DeserializeOwned>(self) -> impl Future<Output = T> + Send;
#[track_caller]
fn expect_has_header<H: AsRef<str>>(self, header: H) -> Self;
#[track_caller]
fn expect_header<H: AsRef<str>>(self, header: H, value: &str) -> Self;
#[track_caller]
fn expect_status(self, status: StatusCode) -> Self;
#[track_caller]
fn get_header<H: AsRef<str>>(&self, header: H) -> Option<String>;
}
impl<B: http_body_util::BodyExt + Send> ResponseTestExt for Response<B>
where
<B as http_body::Body>::Data: Send,
{
async fn body<T: DeserializeOwned>(self) -> T {
let body = self
.into_body()
.collect()
.await
.unwrap_or_else(|_| panic!("failed to collect body"))
.to_bytes();
serde_json::from_slice(&body).expect("should be able to deserialize body")
}
#[track_caller]
fn expect_has_header<H: AsRef<str>>(self, header: H) -> Self {
self.headers()
.get(HeaderName::from_str(header.as_ref()).expect("headers hould be ok"))
.unwrap_or_else(|| {
panic!("expected response to have the `{}` header", header.as_ref())
});
self
}
#[track_caller]
fn expect_header<H: AsRef<str>>(self, header: H, value: &str) -> Self {
let real_value = self.get_header(&header).unwrap_or_else(|| {
panic!("expected response to have the `{}` header", header.as_ref())
});
assert_eq!(
real_value,
value,
"header `{}` did not have the expected value",
header.as_ref()
);
self
}
#[track_caller]
fn expect_status(self, status: StatusCode) -> Self {
assert_eq!(self.status(), status);
self
}
#[track_caller]
fn get_header<H: AsRef<str>>(&self, header: H) -> Option<String> {
let value = self
.headers()
.get(HeaderName::from_str(header.as_ref()).expect("headers hould be ok"))?;
let value = value
.to_str()
.unwrap_or_else(|_| panic!("expected header `{}` to be a string", header.as_ref()))
.to_string();
Some(value)
}
}
pub fn post(
uri: &str,
body: &serde_json::Value,
additional_headers: Vec<(&str, &str)>,
) -> Request<Full<Bytes>> {
let body = Full::new(Bytes::from_owner(
serde_json::to_vec(body).expect("body should be ok"),
));
let mut request = Request::builder()
.uri(uri)
.method("POST")
.header(CONTENT_TYPE, APPLICATION_JSON.as_ref());
let headers = request.headers_mut().expect("request should be ok");
for (name, value) in additional_headers {
headers.insert(
HeaderName::from_str(name).expect("header name should be ok"),
HeaderValue::from_str(value).expect("header value should be ok"),
);
}
request.body(body).expect("request should be ok")
}
pub fn put(
uri: &str,
body: &serde_json::Value,
additional_headers: Vec<(&str, &str)>,
) -> Request<Full<Bytes>> {
let body = Full::new(Bytes::from_owner(
serde_json::to_vec(body).expect("body should be ok"),
));
let mut request = Request::builder()
.uri(uri)
.method("PUT")
.header(CONTENT_TYPE, APPLICATION_JSON.as_ref());
let headers = request.headers_mut().expect("request should be ok");
for (name, value) in additional_headers {
headers.insert(
HeaderName::from_str(name).expect("header name should be ok"),
HeaderValue::from_str(value).expect("header value should be ok"),
);
}
request.body(body).expect("request should be ok")
}
pub fn get(uri: &str, additional_headers: Vec<(&str, &str)>) -> Request<Empty<Bytes>> {
let mut request = Request::builder().uri(uri).method("GET");
let headers = request.headers_mut().expect("request should be ok");
for (name, value) in additional_headers {
headers.insert(
HeaderName::from_str(name).expect("header name should be ok"),
HeaderValue::from_str(value).expect("header value should be ok"),
);
}
request.body(Empty::new()).expect("request should be ok")
}
pub fn delete(uri: &str, additional_headers: Vec<(&str, &str)>) -> Request<Empty<Bytes>> {
let mut request = Request::builder().uri(uri).method("DELETE");
let headers = request.headers_mut().expect("request should be ok");
for (name, value) in additional_headers {
headers.insert(
HeaderName::from_str(name).expect("header name should be ok"),
HeaderValue::from_str(value).expect("header value should be ok"),
);
}
request.body(Empty::new()).expect("request should be ok")
}