summaryrefslogtreecommitdiff
path: root/rola-bucket/src
diff options
context:
space:
mode:
Diffstat (limited to 'rola-bucket/src')
-rw-r--r--rola-bucket/src/bucket/config.rs83
-rw-r--r--rola-bucket/src/bucket/config/test.rs116
-rw-r--r--rola-bucket/src/bucket/init.rs8
-rw-r--r--rola-bucket/src/bucket/space.rs5
4 files changed, 199 insertions, 13 deletions
diff --git a/rola-bucket/src/bucket/config.rs b/rola-bucket/src/bucket/config.rs
index 559db15..2fd111c 100644
--- a/rola-bucket/src/bucket/config.rs
+++ b/rola-bucket/src/bucket/config.rs
@@ -1,9 +1,15 @@
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
+use space_system::{Space, SpaceError};
+
+use crate::{AsyncBucketTransferProtocol, Bucket};
+
+#[cfg(test)]
+mod test;
/// Configuration for a bucket.
///
/// This struct defines how a bucket should be configured, including its type.
-#[derive(Default, Deserialize)]
+#[derive(Default, Serialize, Deserialize)]
pub struct BucketConfig {
/// The type of the bucket, e.g., client bucket or normal bucket.
///
@@ -15,7 +21,7 @@ pub struct BucketConfig {
/// Enum for bucket types, used to distinguish different types of buckets.
///
/// When deserializing, field names are mapped to string values in TOML via `serde(rename)`.
-#[derive(Default, Deserialize)]
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub enum BucketType {
/// Client bucket
/// Uses local ID, mapped to remote ID via IDMAP
@@ -28,3 +34,74 @@ pub enum BucketType {
#[serde(rename = "bucket")]
Bucket,
}
+
+/// Reads the bucket configuration from a file path.
+///
+/// This function reads the bucket configuration file at the given `path`.
+/// If the file cannot be read or the content cannot be parsed as TOML,
+/// a default `BucketConfig` will be used instead of returning an error.
+///
+/// # Note
+///
+/// - If the configuration file cannot be read (e.g., file not found, permission denied),
+/// a default [`BucketConfig`] is returned.
+/// - If the file content is not valid TOML or does not match the expected structure,
+/// a default [`BucketConfig`] is returned as well.
+pub fn read_bucket_config_from_path(
+ path: impl AsRef<std::path::Path>,
+) -> Result<BucketConfig, SpaceError> {
+ let config_content = match std::fs::read_to_string(path) {
+ Ok(content) => content,
+ Err(_) => return Ok(BucketConfig::default()),
+ };
+ Ok(toml::from_str(&config_content).unwrap_or_default())
+}
+
+/// Writes the bucket configuration to a file path.
+///
+/// This function serializes the given bucket configuration as TOML and
+/// writes it to the specified `path`. If the serialization or write fails,
+/// the error is returned as a [`SpaceError`].
+pub fn write_bucket_config_to_path(
+ path: impl AsRef<std::path::Path>,
+ config: &BucketConfig,
+) -> Result<(), SpaceError> {
+ let config_content = toml::to_string(config).map_err(|e| {
+ SpaceError::Other(format!("Failed to serialize bucket config to TOML: {}", e))
+ })?;
+ std::fs::write(path, config_content.as_bytes())
+ .map_err(|e| SpaceError::Other(format!("Failed to write bucket config to file: {}", e)))?;
+ Ok(())
+}
+
+/// Reads the bucket configuration from the space, with shared with_path logic.
+///
+/// This function attempts to read the bucket configuration file (`FILE_BUCKET_ROOT_CONFIG`)
+/// from the given `space`. If the file cannot be read or the content cannot be parsed as TOML,
+/// a default `BucketConfig` will be used instead of returning an error.
+///
+/// # Note
+///
+/// - If the configuration file cannot be read (e.g., file not found, permission denied),
+/// a default [`BucketConfig`] is returned.
+/// - If the file content is not valid TOML or does not match the expected structure,
+/// a default [`BucketConfig`] is returned as well.
+pub fn read_bucket_config<Protocol: AsyncBucketTransferProtocol + Send + Sync>(
+ space: &Space<Bucket<Protocol>>,
+) -> Result<BucketConfig, SpaceError> {
+ let path = space.local_path(shared_constants::common::FILE_BUCKET_ROOT_CONFIG)?;
+ read_bucket_config_from_path(path)
+}
+
+/// Writes the bucket configuration to the space, with shared with_path logic.
+///
+/// This function attempts to write the bucket configuration file (`FILE_BUCKET_ROOT_CONFIG`)
+/// to the given `space` as a TOML string. If the serialization or write fails, the error
+/// is returned.
+pub fn write_bucket_config<Protocol: AsyncBucketTransferProtocol + Send + Sync>(
+ space: &Space<Bucket<Protocol>>,
+ config: &BucketConfig,
+) -> Result<(), SpaceError> {
+ let path = space.local_path(shared_constants::common::FILE_BUCKET_ROOT_CONFIG)?;
+ write_bucket_config_to_path(path, config)
+}
diff --git a/rola-bucket/src/bucket/config/test.rs b/rola-bucket/src/bucket/config/test.rs
new file mode 100644
index 0000000..d586045
--- /dev/null
+++ b/rola-bucket/src/bucket/config/test.rs
@@ -0,0 +1,116 @@
+use shared_functions::rola_test_sandbox;
+
+use crate::config::{
+ BucketConfig, BucketType, read_bucket_config_from_path, write_bucket_config_to_path,
+};
+
+#[test]
+fn test_read_bucket_config_from_path_file_not_found_returns_default() {
+ let sandbox = rola_test_sandbox("bucket_config_read_file_not_found");
+ let path = sandbox.path.join("nonexistent.toml");
+
+ let config = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(config.bucket_type, BucketType::Bucket);
+}
+
+#[test]
+fn test_read_bucket_config_from_path_invalid_toml_returns_default() {
+ let sandbox = rola_test_sandbox("bucket_config_read_invalid_toml");
+ let path = sandbox.path.join("config.toml");
+ std::fs::write(&path, "this is not valid TOML {{{").unwrap();
+
+ let config = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(config.bucket_type, BucketType::Bucket);
+}
+
+#[test]
+fn test_read_bucket_config_from_path_valid_client_bucket() {
+ let sandbox = rola_test_sandbox("bucket_config_read_valid_client");
+ let path = sandbox.path.join("config.toml");
+ std::fs::write(&path, r#"type = "client""#).unwrap();
+
+ let config = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(config.bucket_type, BucketType::ClientBucket);
+}
+
+#[test]
+fn test_read_bucket_config_from_path_valid_normal_bucket() {
+ let sandbox = rola_test_sandbox("bucket_config_read_valid_normal");
+ let path = sandbox.path.join("config.toml");
+ std::fs::write(&path, r#"type = "bucket""#).unwrap();
+
+ let config = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(config.bucket_type, BucketType::Bucket);
+}
+
+#[test]
+fn test_read_bucket_config_from_path_empty_file_returns_default() {
+ let sandbox = rola_test_sandbox("bucket_config_read_empty");
+ let path = sandbox.path.join("config.toml");
+ std::fs::write(&path, "").unwrap();
+
+ let config = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(config.bucket_type, BucketType::Bucket);
+}
+
+#[test]
+fn test_read_bucket_config_from_path_unknown_type_returns_default() {
+ let sandbox = rola_test_sandbox("bucket_config_read_unknown_type");
+ let path = sandbox.path.join("config.toml");
+ std::fs::write(&path, r#"type = "something_else""#).unwrap();
+
+ let config = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(config.bucket_type, BucketType::Bucket);
+}
+
+#[test]
+fn test_write_and_read_roundtrip_client_bucket() {
+ let sandbox = rola_test_sandbox("bucket_config_roundtrip_client");
+ let path = sandbox.path.join("config.toml");
+
+ let config = BucketConfig {
+ bucket_type: BucketType::ClientBucket,
+ };
+ write_bucket_config_to_path(&path, &config).unwrap();
+
+ let loaded = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(loaded.bucket_type, BucketType::ClientBucket);
+}
+
+#[test]
+fn test_write_and_read_roundtrip_normal_bucket() {
+ let sandbox = rola_test_sandbox("bucket_config_roundtrip_normal");
+ let path = sandbox.path.join("config.toml");
+
+ let config = BucketConfig {
+ bucket_type: BucketType::Bucket,
+ };
+ write_bucket_config_to_path(&path, &config).unwrap();
+
+ let loaded = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(loaded.bucket_type, BucketType::Bucket);
+}
+
+#[test]
+fn test_write_bucket_config_to_path_invalid_dir_fails() {
+ let path = "/nonexistent_directory_12345/config.toml";
+
+ let config = BucketConfig::default();
+ let result = write_bucket_config_to_path(&path, &config);
+ assert!(result.is_err());
+}
+
+#[test]
+fn test_write_bucket_config_overwrites_existing_file() {
+ let sandbox = rola_test_sandbox("bucket_config_overwrite");
+ let path = sandbox.path.join("config.toml");
+ std::fs::write(&path, r#"type = "client""#).unwrap();
+
+ let config = BucketConfig {
+ bucket_type: BucketType::Bucket,
+ };
+ write_bucket_config_to_path(&path, &config).unwrap();
+
+ let loaded = read_bucket_config_from_path(&path).unwrap();
+ assert_eq!(loaded.bucket_type, BucketType::Bucket);
+}
diff --git a/rola-bucket/src/bucket/init.rs b/rola-bucket/src/bucket/init.rs
index 6834009..d2dda24 100644
--- a/rola-bucket/src/bucket/init.rs
+++ b/rola-bucket/src/bucket/init.rs
@@ -12,6 +12,8 @@ use shared_constants::{
};
use space_system::SpaceError;
+use crate::config::{BucketConfig, write_bucket_config_to_path};
+
pub(crate) fn init_bucket_at(path: PathBuf) -> Result<(), SpaceError> {
let bucket_config_file = path.join(FILE_BUCKET_ROOT_CONFIG);
@@ -21,16 +23,12 @@ pub(crate) fn init_bucket_at(path: PathBuf) -> Result<(), SpaceError> {
return Err(SpaceError::RequireEmptyDirectory);
}
- write_config(&bucket_config_file)?;
+ write_bucket_config_to_path(&bucket_config_file, &BucketConfig::default())?;
create_dirs(&path)?;
Ok(())
}
-fn write_config(bucket_config_file: &Path) -> Result<(), SpaceError> {
- fs::write(bucket_config_file, include_str!("../../res/bucket.toml")).map_err(SpaceError::Io)
-}
-
fn create_dirs(bucket_dir: &Path) -> Result<(), SpaceError> {
let dirs = [
DIR_BUCKET_OBJ,
diff --git a/rola-bucket/src/bucket/space.rs b/rola-bucket/src/bucket/space.rs
index 353075d..1775914 100644
--- a/rola-bucket/src/bucket/space.rs
+++ b/rola-bucket/src/bucket/space.rs
@@ -1,6 +1,4 @@
-// use log::trace;
use shared_constants::common::FILE_BUCKET_ROOT_CONFIG;
-use shared_functions::trace;
use space_system::{SpaceRoot, SpaceRootFindPattern};
use crate::{AsyncBucketTransferProtocol, Bucket, bucket::init::init_bucket_at};
@@ -11,10 +9,7 @@ impl<Protocol: AsyncBucketTransferProtocol + Send + Sync> SpaceRoot for Bucket<P
}
fn create_space(path: &std::path::Path) -> Result<(), space_system::SpaceError> {
- let path_str = path.display().to_string();
- trace!("Creating bucket at: {}", &path_str);
init_bucket_at(path.into())?;
- trace!("Bucket created at: {}", &path_str);
Ok(())
}
}