liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
use super::*;

#[test]
fn present_non_empty_auth_token_passes_validation() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = sample_config()?;
    config.auth = Some(AuthConfig {
        pass: None,
        token: "s3cr3t".to_owned(),
        require_verified_worker: false,
        lys: None,
    });

    validate(&mut config, None)?;

    Ok(())
}

#[test]
fn empty_auth_token_is_rejected() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = sample_config()?;
    config.auth = Some(AuthConfig {
        pass: None,
        token: String::new(),
        require_verified_worker: false,
        lys: None,
    });

    let message = config_validation_message(validate(&mut config, None));

    assert!(message.contains("auth.token"));
    assert!(message.contains("must not be empty"));

    Ok(())
}

/// ACCESS-004 R3, red at main: requiring a verified holder with no
/// `[auth.pass]` would refuse every worker, so it is refused by name.
#[test]
fn requiring_a_verified_worker_without_a_pass_verifier_is_rejected()
-> Result<(), Box<dyn std::error::Error>> {
    let mut config = sample_config()?;
    config.auth = Some(AuthConfig {
        pass: None,
        token: "s3cr3t".to_owned(),
        require_verified_worker: true,
        lys: None,
    });

    let message = config_validation_message(validate(&mut config, None));

    assert!(
        message.contains("auth.require_verified_worker") && message.contains("auth.pass"),
        "the refusal must name the flag and the missing section: {message}"
    );
    Ok(())
}

#[test]
fn auth_token_longer_than_a_connect_can_carry_is_rejected() -> Result<(), Box<dyn std::error::Error>>
{
    let max = crate::server::connection::pre_admission::MAX_CONNECT_AUTH_TOKEN_BYTES;
    let mut config = sample_config()?;
    config.auth = Some(AuthConfig {
        pass: None,
        token: "t".repeat(max),
        require_verified_worker: false,
        lys: None,
    });
    validate(&mut config, None)?;

    config.auth = Some(AuthConfig {
        pass: None,
        token: "t".repeat(max + 1),
        require_verified_worker: false,
        lys: None,
    });
    let message = config_validation_message(validate(&mut config, None));

    assert!(message.contains("auth.token"));
    assert!(message.contains(&format!("at most {max}")));
    Ok(())
}

#[test]
fn absent_auth_section_passes_validation() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = sample_config()?;
    config.auth = None;

    validate(&mut config, None)?;

    Ok(())
}

#[test]
fn default_profile_is_full_and_passes_validation() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = sample_config()?;

    // The default services config resolves to the full profile.
    assert_eq!(
        config.services.profile()?,
        crate::config::types::ServiceProfile::Full
    );
    validate(&mut config, None)?;

    Ok(())
}

#[test]
fn unknown_profile_is_a_validation_error() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = sample_config()?;
    config.services = ServicesConfig {
        profile: "banana".to_owned(),
        ..ServicesConfig::default()
    };

    let message = config_validation_message(validate(&mut config, None));

    assert!(message.contains("services.profile"));
    assert!(message.contains("banana"));
    assert!(message.contains("worker-front-door"));

    Ok(())
}

#[test]
fn worker_front_door_profile_with_empty_topology_passes() -> Result<(), Box<dyn std::error::Error>>
{
    let mut config = worker_front_door_config()?;

    assert_eq!(
        config.services.profile()?,
        crate::config::types::ServiceProfile::WorkerFrontDoor
    );
    validate(&mut config, None)?;

    Ok(())
}

#[test]
fn worker_front_door_profile_rejects_channels_persistence_and_cluster()
-> Result<(), Box<dyn std::error::Error>> {
    // Start from the full sample (channels + cluster present) but flip only the
    // profile: every full-mode-only knob must be rejected, not silently ignored.
    let mut config = sample_config()?;
    config.services = ServicesConfig {
        profile: "worker-front-door".to_owned(),
        ..ServicesConfig::default()
    };
    config.persistence_path = Some(PathBuf::from("/tmp"));

    let message = config_validation_message(validate(&mut config, None));

    assert!(message.contains("builds no channels"));
    assert!(message.contains("builds no durable store"));
    assert!(message.contains("builds no channel cluster"));

    Ok(())
}