lenso-web-ingress-plugin 0.4.12

General-purpose linked Rust HTTP Ingress Plugin for Lenso backends.
Documentation
use super::*;

#[test]
fn public_bind_addresses_are_valid_plan_configuration() {
    let config = WebIngressConfig::default()
        .with_bind_address(SocketAddr::from(([0, 0, 0, 0], 8080)))
        .expect("public bind should be valid");
    let encoded = serde_json::to_string(&config).expect("configuration should encode");
    assert_eq!(
        serde_json::from_str::<WebIngressConfig>(&encoded).unwrap(),
        config
    );
}

#[test]
fn zero_and_excessive_limits_are_rejected() {
    assert!(
        WebIngressConfig::default()
            .with_max_concurrent_requests(0)
            .is_err()
    );
    assert!(
        WebIngressConfig::default()
            .with_request_limits(MAX_TRANSFER_BYTES + 1, 1024)
            .is_err()
    );
    assert!(
        WebIngressConfig::default()
            .with_request_timeout(Duration::from_millis(MAX_TIMEOUT_MILLIS + 1))
            .is_err()
    );
    assert!(
        WebIngressConfig::default()
            .with_connection_limits(0, Duration::from_secs(1))
            .is_err()
    );
    assert!(
        WebIngressConfig::default()
            .with_request_read_timeouts(Duration::ZERO, Duration::from_secs(1))
            .is_err()
    );
    assert!(
        WebIngressConfig::default()
            .with_shutdown_grace_timeout(Duration::ZERO)
            .is_err()
    );
}

#[test]
fn endpoint_admission_tracks_the_ingress_execution_ceiling() {
    let config = WebIngressConfig::default()
        .with_max_concurrent_requests(17)
        .unwrap();
    assert_eq!(config.endpoint_admission_limits(), (0, 17));
}

#[test]
fn session_cookie_policy_is_strict_and_round_trips() {
    assert!(
        !serde_json::to_string(&WebIngressConfig::default())
            .unwrap()
            .contains("session_cookie")
    );
    let policy =
        SessionCookieConfig::new("__Host-lenso-session", "__Host-lenso-csrf", "x-csrf-token")
            .unwrap();
    let config = WebIngressConfig::default()
        .with_session_cookie(policy)
        .unwrap();
    let encoded = serde_json::to_string(&config).unwrap();
    assert_eq!(
        serde_json::from_str::<WebIngressConfig>(&encoded).unwrap(),
        config
    );

    assert!(SessionCookieConfig::new("__Host-session", "__Host-session", "x-csrf-token").is_err());
    assert!(SessionCookieConfig::new("session", "csrf", "x-csrf-token").is_err());
    assert!(SessionCookieConfig::new("__Host-bad name", "__Host-csrf", "x-csrf-token").is_err());
    assert!(SessionCookieConfig::new("__Host-session", "__Host-csrf", "authorization").is_err());
}

#[test]
fn route_session_cookie_table_is_explicit_and_validated() {
    let policy =
        SessionCookieConfig::new("__Host-accounts", "__Host-accounts-csrf", "x-accounts-csrf")
            .unwrap();
    let config = WebIngressConfig::default()
        .with_route_session_cookie("accounts.exchange", policy.clone())
        .unwrap();
    assert_eq!(
        serde_json::from_str::<WebIngressConfig>(&serde_json::to_string(&config).unwrap()).unwrap(),
        config
    );
    assert!(
        config
            .clone()
            .with_route_session_cookie("accounts.exchange", policy.clone())
            .is_err()
    );
    assert!(
        WebIngressConfig::default()
            .with_route_session_cookie(" ", policy)
            .is_err()
    );
    let manifest = crate::WebIngressRouteManifest::new(vec![crate::WebIngressRoute::new(
        "POST",
        "/exchange",
        "accounts.exchange",
    )]);
    assert!(config.resolved_route_session_cookies(&manifest).is_ok());
    assert!(
        config
            .resolved_route_session_cookies(&crate::WebIngressRouteManifest::new(vec![]))
            .is_err()
    );
    let schema: serde_json::Value = serde_json::from_str(crate::CONFIGURATION_SCHEMA_JSON).unwrap();
    assert_eq!(
        schema["properties"]["route_session_cookies"]["additionalProperties"],
        schema["properties"]["session_cookie"]
    );
}

#[test]
fn route_cookie_schema_uses_the_existing_resolver_dialect() {
    use lenso_app_plan::authoring::{
        HostCatalog, HostDefaultPlugin, HostPluginRelease, HostSlot, PluginDescriptor,
        PluginRootSnapshot, resolve_plugin_root,
    };
    let resolve = |configuration| {
        let descriptor = PluginDescriptor::new("fixture.ingress.schema", "0.0.0", "http-ingress")
            .with_configuration_defaults(serde_json::to_value(WebIngressConfig::default()).unwrap())
            .with_configuration_schema(
                serde_json::from_str(crate::CONFIGURATION_SCHEMA_JSON).unwrap(),
            );
        resolve_plugin_root(
            &HostCatalog::new(
                [HostSlot::one("http-ingress")],
                [HostPluginRelease::new(descriptor)],
                [HostDefaultPlugin::new("fixture.ingress.schema", "default")
                    .with_configuration(configuration)],
            ),
            &PluginRootSnapshot::default(),
        )
    };
    let policy = SessionCookieConfig::new("__Host-session", "__Host-csrf", "x-csrf").unwrap();
    for config in [
        WebIngressConfig::default(),
        WebIngressConfig::default()
            .with_route_session_cookie("exchange", policy.clone())
            .unwrap(),
        WebIngressConfig::default()
            .with_selected_route_session_cookie(
                crate::WebIngressRoute::new("POST", "/accounts/logout", "logout"),
                policy,
            )
            .unwrap(),
    ] {
        assert!(resolve(serde_json::to_value(config).unwrap()).is_ok());
    }
    for field in ["route_session_cookies", "selected_route_session_cookies"] {
        let invalid = if field == "route_session_cookies" {
            serde_json::json!({field:{"exchange":{"name":"__Host-session"}}})
        } else {
            serde_json::json!({field:[{
                "route":{"method":"POST","path":"/accounts/logout","route_id":"logout"},
                "policy":{"name":"__Host-session"}
            }]})
        };
        assert!(resolve(invalid).is_err());
    }
}

#[test]
fn exact_cookie_selectors_reject_ambiguity_duplicates_and_overlap() {
    let accounts = crate::WebIngressRoute::new("POST", "/accounts/logout", "logout");
    let operators = crate::WebIngressRoute::new("POST", "/operators/logout", "logout");
    let policy = SessionCookieConfig::new("__Host-session", "__Host-csrf", "x-csrf").unwrap();
    let manifest = crate::WebIngressRouteManifest::new(vec![accounts.clone(), operators.clone()]);
    let shorthand = WebIngressConfig::default()
        .with_route_session_cookie("logout", policy.clone())
        .unwrap();
    assert!(shorthand.resolved_route_session_cookies(&manifest).is_err());
    let exact = WebIngressConfig::default()
        .with_selected_route_session_cookie(accounts.clone(), policy.clone())
        .unwrap();
    assert!(exact.resolved_route_session_cookies(&manifest).is_ok());
    assert!(
        exact
            .clone()
            .with_selected_route_session_cookie(accounts.clone(), policy.clone())
            .is_err()
    );
    let encoded = serde_json::to_string(&exact).unwrap();
    assert_eq!(
        serde_json::from_str::<WebIngressConfig>(&encoded).unwrap(),
        exact
    );
    let unique_manifest = crate::WebIngressRouteManifest::new(vec![accounts.clone()]);
    let overlapping = shorthand
        .with_selected_route_session_cookie(accounts, policy)
        .unwrap();
    assert!(
        overlapping
            .resolved_route_session_cookies(&unique_manifest)
            .is_err()
    );
}