multistore-path-mapping 0.1.1

Hierarchical path mapping for the multistore S3 proxy gateway
Documentation
use multistore_path_mapping::PathMapping;

fn default_mapping() -> PathMapping {
    PathMapping {
        bucket_segments: 2,
        bucket_separator: "--".to_string(),
        display_bucket_segments: 1,
    }
}

#[test]
fn two_segment_mapping() {
    let mapping = default_mapping();
    let result = mapping.parse("/account/product/file.parquet").unwrap();

    assert_eq!(result.bucket, "account--product");
    assert_eq!(result.key, Some("file.parquet".to_string()));
    assert_eq!(result.display_bucket, "account");
    assert_eq!(result.key_prefix, "product/");
    assert_eq!(result.segments, vec!["account", "product"]);
}

#[test]
fn single_segment_not_enough() {
    let mapping = default_mapping();
    let result = mapping.parse("/account");

    assert!(result.is_none());
}

#[test]
fn nested_key() {
    let mapping = default_mapping();
    let result = mapping
        .parse("/account/product/dir/subdir/file.parquet")
        .unwrap();

    assert_eq!(result.bucket, "account--product");
    assert_eq!(result.key, Some("dir/subdir/file.parquet".to_string()));
    assert_eq!(result.display_bucket, "account");
    assert_eq!(result.key_prefix, "product/");
}

#[test]
fn just_bucket_segments_no_key() {
    let mapping = default_mapping();
    let result = mapping.parse("/account/product").unwrap();

    assert_eq!(result.bucket, "account--product");
    assert_eq!(result.key, None);
    assert_eq!(result.display_bucket, "account");
    assert_eq!(result.key_prefix, "product/");
}

#[test]
fn parse_bucket_name() {
    let mapping = default_mapping();
    let result = mapping.parse_bucket_name("account--product").unwrap();

    assert_eq!(result.bucket, "account--product");
    assert_eq!(result.key, None);
    assert_eq!(result.display_bucket, "account");
    assert_eq!(result.key_prefix, "product/");
    assert_eq!(result.segments, vec!["account", "product"]);
}

#[test]
fn empty_root_path() {
    let mapping = default_mapping();

    assert!(mapping.parse("/").is_none());
    assert!(mapping.parse("").is_none());
}

#[test]
fn custom_separator() {
    let mapping = PathMapping {
        bucket_segments: 2,
        bucket_separator: "-".to_string(),
        display_bucket_segments: 1,
    };

    let result = mapping.parse("/org/repo/data.csv").unwrap();

    assert_eq!(result.bucket, "org-repo");
    assert_eq!(result.key, Some("data.csv".to_string()));
    assert_eq!(result.display_bucket, "org");
    assert_eq!(result.key_prefix, "repo/");
}

#[test]
fn parse_bucket_name_wrong_segment_count() {
    let mapping = default_mapping();

    // Too few segments
    assert!(mapping.parse_bucket_name("account").is_none());
    // Too many segments
    assert!(mapping.parse_bucket_name("a--b--c").is_none());
}

#[test]
fn trailing_slash_on_bucket_segments() {
    let mapping = default_mapping();
    let result = mapping.parse("/account/product/").unwrap();

    // Trailing slash means key portion is empty, so key should be None
    assert_eq!(result.bucket, "account--product");
    assert_eq!(result.key, None);
}