unpoly 0.2.4

Helper for the Unpoly API, initially for usage in Axum handlers
Documentation
use crate::Unpoly;

use axum::{
    extract::FromRequestParts,
    http::{StatusCode, request::Parts},
};

impl<S> FromRequestParts<S> for Unpoly
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, &'static str);

    async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
        Ok(Unpoly::from_headers(&parts.headers))
    }
}

#[cfg(test)]
mod tests {
    extern crate axum;
    use axum::{body::Body, http::Request};

    use crate::LayerMode;

    use super::*;

    #[tokio::test]
    async fn test_no_unpoly_request() {
        let request = Request::builder()
            .method("GET")
            .uri("https://www.unpoly.com/")
            .header("X-Custom-Foo", "Bar")
            .body(Body::empty())
            .unwrap();
        let mut parts = request.into_parts();

        let mut unpoly = Unpoly::from_request_parts(&mut parts.0, &()).await.unwrap();

        assert_eq!(unpoly.request_version, None);
        assert_eq!(unpoly.request_context, None);
        assert_eq!(unpoly.request_fail_context, None);
        assert_eq!(unpoly.request_fail_mode, LayerMode::ROOT);
        assert_eq!(unpoly.request_mode, LayerMode::ROOT);
        assert_eq!(unpoly.request_target, None);

        assert!(!unpoly.is_up());

        assert!(!unpoly.get_headers().unwrap().contains_key("Vary"));
    }

    #[tokio::test]
    async fn test_unpoly_default() {
        let request = Request::builder()
            .method("GET")
            .uri("https://www.unpoly.com/")
            .header("X-Up-Version", "1.0.0")
            .body(Body::empty())
            .unwrap();
        let mut parts = request.into_parts();

        let mut unpoly = Unpoly::from_request_parts(&mut parts.0, &()).await.unwrap();

        assert_eq!(unpoly.request_version, Some("1.0.0".to_string()));
        assert_eq!(unpoly.request_context, None);
        assert_eq!(unpoly.request_fail_context, None);
        assert_eq!(unpoly.request_fail_mode, LayerMode::ROOT);
        assert_eq!(unpoly.request_mode, LayerMode::ROOT);
        assert_eq!(unpoly.request_target, None);

        unpoly.is_up();
        unpoly.set_success(true);
        unpoly.mode();

        assert_eq!(
            unpoly.get_headers().unwrap()["Vary"],
            "X-Up-Mode,X-Up-Target,X-Up-Version".to_string()
        );

        let mut unpoly = Unpoly::from_request_parts(&mut parts.0, &()).await.unwrap();
        unpoly.is_up();
        unpoly.set_success(false);
        unpoly.mode();

        assert_eq!(
            unpoly.get_headers().unwrap()["Vary"],
            "X-Up-Fail-Mode,X-Up-Fail-Target,X-Up-Version".to_string()
        );
    }

    #[tokio::test]
    async fn test_unpoly_success() {
        let request = Request::builder()
            .method("GET")
            .uri("https://www.unpoly.com/")
            .header("X-Up-Version", "1.0.0")
            .header("X-Up-Context", "{\"lives\": 42}")
            .header("X-Up-Fail-Context", "{\"lives\": 2}")
            .header("X-Up-Target", "main")
            .header("X-Up-Fail-Target", "root")
            .header("X-Up-Mode", "root")
            .header("X-Up-Fail-Mode", "cover")
            .header("X-Up-Validate", "name")
            .body(Body::empty())
            .unwrap();
        let mut parts = request.into_parts();

        let mut unpoly = Unpoly::from_request_parts(&mut parts.0, &()).await.unwrap();
        unpoly.set_success(true);

        unpoly.is_up();
        assert_eq!(unpoly.context(), Some(&serde_json::json!({"lives": 42})));
        assert_eq!(unpoly.target(), Some("main"));
        assert_eq!(*unpoly.mode(), LayerMode::ROOT);

        assert_eq!(
            unpoly.get_headers().unwrap()["Vary"],
            "X-Up-Context,X-Up-Mode,X-Up-Target,X-Up-Version".to_string()
        );
    }

    #[tokio::test]
    async fn test_unpoly_fail() {
        let request = Request::builder()
            .method("GET")
            .uri("https://www.unpoly.com/")
            .header("X-Up-Version", "1.0.0")
            .header("X-Up-Context", "{\"lives\": 42}")
            .header("X-Up-Fail-Context", "{\"lives\": 2}")
            .header("X-Up-Target", "main")
            .header("X-Up-Fail-Target", "root")
            .header("X-Up-Mode", "root")
            .header("X-Up-Fail-Mode", "cover")
            .header("X-Up-Validate", "name")
            .body(Body::empty())
            .unwrap();
        let mut parts = request.into_parts();

        let mut unpoly = Unpoly::from_request_parts(&mut parts.0, &()).await.unwrap();
        unpoly.set_success(false);

        unpoly.is_up();
        assert_eq!(unpoly.context(), Some(&serde_json::json!({"lives": 2})));
        assert_eq!(unpoly.target(), Some("root"));
        assert_eq!(*unpoly.mode(), LayerMode::COVER);

        assert_eq!(
            unpoly.get_headers().unwrap()["Vary"],
            "X-Up-Fail-Context,X-Up-Fail-Mode,X-Up-Fail-Target,X-Up-Version".to_string()
        );
    }

    #[tokio::test]
    async fn test_unpoly_set_responses() {
        let request = Request::builder()
            .method("GET")
            .uri("https://www.unpoly.com/")
            .header("X-Up-Version", "1.0.0")
            .header("X-Up-Context", "{\"lives\": 42}")
            .header("X-Up-Fail-Context", "{\"lives\": 2}")
            .header("X-Up-Target", "main")
            .header("X-Up-Fail-Target", "root")
            .header("X-Up-Mode", "root")
            .header("X-Up-Fail-Mode", "cover")
            .header("X-Up-Validate", "name")
            .body(Body::empty())
            .unwrap();
        let mut parts = request.into_parts();

        let mut unpoly = Unpoly::from_request_parts(&mut parts.0, &()).await.unwrap();

        unpoly.set_context(serde_json::json!({"lives": 43}));

        unpoly.set_title("Hello");
        unpoly.set_location("https://unpoly.com/");
        unpoly.set_method("PUT");
        unpoly.set_target("main");
        unpoly.set_evict_cache("main".to_string());
        unpoly.set_expire_cache("main".to_string());

        assert_eq!(unpoly.get_headers().unwrap()["X-Up-Title"], "Hello");
        assert_eq!(
            unpoly.get_headers().unwrap()["X-Up-Location"],
            "https://unpoly.com/"
        );
        assert_eq!(unpoly.get_headers().unwrap()["X-Up-Method"], "PUT");
        assert_eq!(unpoly.get_headers().unwrap()["X-Up-Evict-Cache"], "main");
        assert_eq!(unpoly.get_headers().unwrap()["X-Up-Expire-Cache"], "main");
    }
}