hyperlite 0.1.0

Lightweight HTTP framework built on hyper, tokio, and tower
Documentation
use std::str::FromStr;
use std::sync::{Arc, Mutex};

use bytes::Bytes;
use http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
use http_body_util::{BodyExt, Empty, Full};
use hyper::{Method, Request, Response, StatusCode, Uri};
use serde::Serialize;
use serde_json::Value;

use hyperlite::{BoxBody, ResponseBody};

#[allow(dead_code)]
pub fn json_body(value: impl Serialize) -> BoxBody {
    let bytes = serde_json::to_vec(&value).expect("failed to serialize JSON for test body");
    Full::from(Bytes::from(bytes))
        .map_err(|err| match err {})
        .boxed()
}

#[allow(dead_code)]
pub fn empty_body() -> BoxBody {
    Empty::<Bytes>::new().map_err(|err| match err {}).boxed()
}

#[allow(dead_code)]
pub fn bytes_body(bytes: Bytes) -> BoxBody {
    Full::from(bytes).map_err(|err| match err {}).boxed()
}

#[allow(dead_code)]
pub fn build_request(method: Method, uri: &str, body: BoxBody) -> Request<BoxBody> {
    Request::builder()
        .method(method)
        .uri(Uri::from_str(uri).expect("invalid URI in test"))
        .body(body)
        .expect("failed to build test request")
}

#[allow(dead_code)]
pub fn build_json_request(method: Method, uri: &str, json: impl Serialize) -> Request<BoxBody> {
    let mut request = build_request(method, uri, json_body(json));
    request
        .headers_mut()
        .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
    request
}

#[allow(dead_code)]
pub fn build_request_with_headers(
    method: Method,
    uri: &str,
    body: BoxBody,
    headers: Vec<(HeaderName, HeaderValue)>,
) -> Request<BoxBody> {
    let mut request = build_request(method, uri, body);
    for (name, value) in headers {
        request.headers_mut().insert(name, value);
    }
    request
}

#[allow(dead_code)]
pub async fn read_body_json(response: Response<ResponseBody>) -> Value {
    let bytes = response
        .into_body()
        .collect()
        .await
        .expect("failed to read response body")
        .to_bytes();
    serde_json::from_slice(&bytes).expect("response body is not valid JSON")
}

#[allow(dead_code)]
pub async fn read_body_bytes(response: Response<ResponseBody>) -> Bytes {
    response
        .into_body()
        .collect()
        .await
        .expect("failed to read response body")
        .to_bytes()
}

#[allow(dead_code)]
pub fn assert_json_envelope(json: &Value, success: bool) {
    assert_eq!(json["success"], success);
    assert!(json.get("meta").is_some(), "meta field missing");
    assert!(json["meta"].is_object(), "meta field should be object");
}

#[allow(dead_code)]
#[derive(Clone, Default)]
pub struct TestState {
    counter: Arc<Mutex<u64>>,
}

#[allow(dead_code)]
impl TestState {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn increment(&self) -> u64 {
        let mut guard = self.counter.lock().expect("counter poisoned");
        *guard += 1;
        *guard
    }

    pub fn get(&self) -> u64 {
        *self.counter.lock().expect("counter poisoned")
    }
}

#[allow(dead_code)]
pub fn assert_status(response: &Response<ResponseBody>, expected: StatusCode) {
    assert_eq!(response.status(), expected);
}

#[allow(dead_code)]
pub fn assert_header(response: &Response<ResponseBody>, name: &str, expected: &str) {
    let header = response
        .headers()
        .get(name)
        .unwrap_or_else(|| panic!("missing header: {}", name));
    let header_value = header.to_str().unwrap();
    assert_eq!(header_value, expected);
}

#[allow(dead_code)]
pub fn assert_content_type_json(response: &Response<ResponseBody>) {
    let header = response
        .headers()
        .get(CONTENT_TYPE)
        .expect("missing Content-Type header");
    assert_eq!(header, "application/json");
}