liminal-server 0.25.4

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

/// Writes `contents` to a fresh uniquely-named temp file and returns its path.
fn write_temp_schema(label: &str, contents: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
    let path = unique_temp_dir(label).with_extension("json");
    fs::write(&path, contents)?;
    Ok(path)
}

#[test]
fn absolute_schema_ref_is_loaded_and_parsed() -> Result<(), Box<dyn std::error::Error>> {
    let schema = r#"{"type":"object","properties":{"id":{"type":"integer"}}}"#;
    let schema_path = write_temp_schema("load-ok", schema)?;
    let mut config = sample_config()?;
    config.channels[0].schema_ref = Some(schema_path.clone());

    let result = validate(&mut config, None);
    fs::remove_file(&schema_path)?;
    result?;

    let loaded = config.channels[0]
        .loaded_schema
        .as_ref()
        .ok_or("schema should have been loaded onto the channel")?;
    assert_eq!(loaded.bytes, schema.as_bytes());
    assert_eq!(
        loaded.document.get("type").and_then(|t| t.as_str()),
        Some("object")
    );

    Ok(())
}

#[test]
fn relative_schema_ref_resolves_against_base_dir() -> Result<(), Box<dyn std::error::Error>> {
    let dir = unique_temp_dir("relative-base");
    fs::create_dir_all(&dir)?;
    let schema = r#"{"type":"object"}"#;
    fs::write(dir.join("orders.json"), schema)?;

    let mut config = sample_config()?;
    config.channels[0].schema_ref = Some(PathBuf::from("orders.json"));

    let result = validate(&mut config, Some(&dir));
    fs::remove_dir_all(&dir)?;
    result?;

    assert!(config.channels[0].loaded_schema.is_some());

    Ok(())
}

#[test]
fn missing_schema_ref_file_reports_validation_error() -> Result<(), Box<dyn std::error::Error>> {
    let missing = unique_temp_dir("missing-schema").with_extension("json");
    let mut config = sample_config()?;
    config.channels[0].schema_ref = Some(missing.clone());

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

    assert!(message.contains("schema_ref"));
    assert!(message.contains(&missing.display().to_string()));
    assert!(message.contains("unreadable"));

    Ok(())
}

#[test]
fn invalid_json_schema_ref_reports_validation_error() -> Result<(), Box<dyn std::error::Error>> {
    let schema_path = write_temp_schema("bad-json", "{ this is not json")?;
    let mut config = sample_config()?;
    config.channels[0].schema_ref = Some(schema_path.clone());

    let message = config_validation_message(validate(&mut config, None));
    fs::remove_file(&schema_path)?;

    assert!(message.contains("schema_ref"));
    assert!(message.contains("not valid JSON"));

    Ok(())
}

#[test]
fn valid_json_invalid_schema_ref_reports_validation_error() -> Result<(), Box<dyn std::error::Error>>
{
    // Valid JSON that is not a compilable JSON Schema: a schema document
    // must be an object, so a bare array parses but fails compilation.
    let schema_path = write_temp_schema("bad-schema", "[]")?;
    let mut config = sample_config()?;
    config.channels[0].schema_ref = Some(schema_path.clone());

    let message = config_validation_message(validate(&mut config, None));
    fs::remove_file(&schema_path)?;

    assert!(message.contains("schema_ref"));
    assert!(message.contains("not a valid JSON Schema"));

    Ok(())
}