crab-vault-engine 0.2.13

The engine of crab vault
Documentation
use crab_vault_engine::{DataEngine, fs::*};
use crab_vault_engine::error::EngineError;
use std::path::PathBuf;

const TEST_DATA_BASE_DIR: &str = "./data_test";

async fn setup(test_name: &str) -> (FsDataEngine, PathBuf) {
    let base_dir = PathBuf::from(TEST_DATA_BASE_DIR).join(test_name);

    if base_dir.exists() {
        tokio::fs::remove_dir_all(&base_dir).await.unwrap();
    }

    let storage = FsDataEngine::new(&base_dir).expect("无法创建根文件夹");

    (storage, base_dir)
}

#[tokio::test]
async fn test_new_creates_base_directory() {
    let test_name = "new_creates_dir";
    let base_dir = PathBuf::from(TEST_DATA_BASE_DIR).join(test_name);

    if base_dir.exists() {
        tokio::fs::remove_dir_all(&base_dir).await.unwrap();
    }

    assert!(!base_dir.exists());
    let _storage = FsDataEngine::new(&base_dir).unwrap();
    assert!(base_dir.exists());

    tokio::fs::remove_dir_all(&base_dir).await.unwrap();
}

#[tokio::test]
async fn test_create_bucket_success() {
    let (storage, base_dir) = setup("create_bucket_success").await;
    let bucket_name = "test-bucket";

    let result = storage.create_bucket(bucket_name).await;
    assert!(result.is_ok());

    let bucket_path = base_dir.join(bucket_name);
    assert!(bucket_path.exists());
    assert!(bucket_path.is_dir());
}

#[tokio::test]
async fn test_full_lifecycle() {
    let (storage, _base_dir) = setup("full_lifecycle").await;
    let bucket_name = "my-bucket";
    let object_name = "my-object";
    let data = b"hello world";

    storage.create_bucket(bucket_name).await.unwrap();

    storage
        .create_object(bucket_name, object_name, data)
        .await
        .unwrap();

    let read_data = storage.read_object(bucket_name, object_name).await.unwrap();
    assert_eq!(read_data, data);

    storage
        .delete_object(bucket_name, object_name)
        .await
        .unwrap();

    storage.delete_bucket(bucket_name).await.unwrap();

    let bucket_path = _base_dir.join(bucket_name);
    assert!(!bucket_path.exists());
}

#[tokio::test]
async fn test_delete_non_empty_bucket_fails() {
    let (storage, _base_dir) = setup("delete_non_empty_bucket").await;
    let bucket_name = "non-empty-bucket";
    let object_name = "some-file.txt";

    storage.create_bucket(bucket_name).await.unwrap();
    storage
        .create_object(bucket_name, object_name, b"some data")
        .await
        .unwrap();

    let result = storage.delete_bucket(bucket_name).await;
    assert!(result.is_err());
    assert!(matches!(
        result,
        Err(EngineError::BucketNotEmpty { bucket: _ })
    ));

    let bucket_path = _base_dir.join(bucket_name);
    assert!(bucket_path.exists());
}

#[tokio::test]
async fn test_create_object_in_nonexistent_bucket_fails() {
    let (storage, _base_dir) = setup("create_object_no_bucket").await;
    let bucket_name = "non-existent-bucket";
    let object_name = "some-object";

    let result = storage
        .create_object(bucket_name, object_name, b"data")
        .await;
    assert!(result.is_err());
    assert!(matches!(
        result,
        Err(EngineError::BucketNotFound { bucket: _ })
    ));
}

#[tokio::test]
async fn test_read_nonexistent_object_fails() {
    let (storage, _base_dir) = setup("read_nonexistent_object").await;
    let bucket_name = "bucket";
    storage.create_bucket(bucket_name).await.unwrap();

    let result = storage
        .read_object(bucket_name, "non-existent-object")
        .await;
    assert!(result.is_err());
    assert!(matches!(
        result,
        Err(EngineError::ObjectNotFound {
            bucket: _,
            object: _
        })
    ));
}

#[tokio::test]
async fn test_delete_nonexistent_object_is_ok() {
    let (storage, _base_dir) = setup("delete_nonexistent_object").await;
    let bucket_name = "bucket";
    storage.create_bucket(bucket_name).await.unwrap();

    let result = storage
        .delete_object(bucket_name, "non-existent-object")
        .await;
    assert!(result.is_ok());
}

#[tokio::test]
async fn test_overwrite_object() {
    let (storage, _base_dir) = setup("overwrite_object").await;
    let bucket_name = "bucket";
    let object_name = "file.txt";
    let initial_data = b"initial version";
    let new_data = b"new version of the data";

    storage.create_bucket(bucket_name).await.unwrap();
    storage
        .create_object(bucket_name, object_name, initial_data)
        .await
        .unwrap();

    let read_data1 = storage.read_object(bucket_name, object_name).await.unwrap();
    assert_eq!(read_data1, initial_data);

    storage
        .create_object(bucket_name, object_name, new_data)
        .await
        .unwrap();

    let read_data2 = storage.read_object(bucket_name, object_name).await.unwrap();
    assert_eq!(read_data2, new_data);
}