entrenar/storage/cloud/
config.rs1use crate::storage::cloud::azure::AzureConfig;
4use crate::storage::cloud::error::Result;
5use crate::storage::cloud::gcs::GCSConfig;
6use crate::storage::cloud::local::LocalBackend;
7use crate::storage::cloud::memory::InMemoryBackend;
8use crate::storage::cloud::s3::{MockS3Backend, S3Config};
9use crate::storage::cloud::traits::ArtifactBackend;
10use serde::{Deserialize, Serialize};
11use std::path::PathBuf;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub enum BackendConfig {
16 Local { path: PathBuf },
18 Memory,
20 S3(S3Config),
22 Azure(AzureConfig),
24 GCS(GCSConfig),
26}
27
28impl BackendConfig {
29 pub fn local(path: PathBuf) -> Self {
31 Self::Local { path }
32 }
33
34 pub fn memory() -> Self {
36 Self::Memory
37 }
38
39 pub fn s3(bucket: &str, prefix: &str) -> Self {
41 Self::S3(S3Config::new(bucket, prefix))
42 }
43
44 pub fn build(&self) -> Result<Box<dyn ArtifactBackend>> {
46 match self {
47 Self::Local { path } => Ok(Box::new(LocalBackend::new_and_init(path.clone())?)),
48 Self::Memory => Ok(Box::new(InMemoryBackend::new())),
49 Self::S3(config) => Ok(Box::new(MockS3Backend::new(config.clone()))),
50 Self::Azure(_config) => {
51 Ok(Box::new(InMemoryBackend::new()))
53 }
54 Self::GCS(_config) => {
55 Ok(Box::new(InMemoryBackend::new()))
57 }
58 }
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use tempfile::TempDir;
66
67 #[test]
68 fn test_backend_config_local() {
69 let config = BackendConfig::local(PathBuf::from("/tmp/artifacts"));
70 match config {
71 BackendConfig::Local { path } => {
72 assert_eq!(path, PathBuf::from("/tmp/artifacts"));
73 }
74 _ => panic!("Expected Local"),
75 }
76 }
77
78 #[test]
79 fn test_backend_config_memory() {
80 let config = BackendConfig::memory();
81 assert!(matches!(config, BackendConfig::Memory));
82 }
83
84 #[test]
85 fn test_backend_config_s3() {
86 let config = BackendConfig::s3("bucket", "prefix");
87 match config {
88 BackendConfig::S3(c) => {
89 assert_eq!(c.bucket, "bucket");
90 assert_eq!(c.prefix, "prefix");
91 }
92 _ => panic!("Expected S3"),
93 }
94 }
95
96 #[test]
97 fn test_backend_config_build_memory() {
98 let config = BackendConfig::memory();
99 let backend = config.build().expect("builder should produce valid result");
100 assert_eq!(backend.backend_type(), "memory");
101 }
102
103 #[test]
104 fn test_backend_config_build_s3() {
105 let config = BackendConfig::s3("bucket", "prefix");
106 let backend = config.build().expect("builder should produce valid result");
107 assert_eq!(backend.backend_type(), "s3");
108 }
109
110 #[test]
111 fn test_backend_config_build_local() {
112 let tmp = TempDir::new().expect("temp file creation should succeed");
113 let config = BackendConfig::local(tmp.path().to_path_buf());
114 let backend = config.build().expect("builder should produce valid result");
115 assert_eq!(backend.backend_type(), "local");
116 }
117
118 #[test]
119 fn test_backend_config_build_azure() {
120 let config = BackendConfig::Azure(AzureConfig::new("account", "container"));
121 let backend = config.build().expect("builder should produce valid result");
122 assert_eq!(backend.backend_type(), "memory");
124 }
125
126 #[test]
127 fn test_backend_config_build_gcs() {
128 let config = BackendConfig::GCS(GCSConfig::new("bucket"));
129 let backend = config.build().expect("builder should produce valid result");
130 assert_eq!(backend.backend_type(), "memory");
132 }
133
134 #[test]
135 fn test_backend_config_serde() {
136 let configs = vec![
137 BackendConfig::local(PathBuf::from("/tmp/test")),
138 BackendConfig::memory(),
139 BackendConfig::s3("bucket", "prefix"),
140 BackendConfig::Azure(AzureConfig::new("account", "container")),
141 BackendConfig::GCS(GCSConfig::new("bucket")),
142 ];
143
144 for config in configs {
145 let json = serde_json::to_string(&config).expect("JSON serialization should succeed");
146 let parsed: BackendConfig =
147 serde_json::from_str(&json).expect("JSON deserialization should succeed");
148 let _ = parsed;
150 }
151 }
152}
153
154#[cfg(test)]
155mod property_tests {
156 use proptest::prelude::*;
157
158 proptest! {
159 #![proptest_config(ProptestConfig::with_cases(200))]
160
161 #[test]
162 fn prop_metadata_size_matches(
163 name in "[a-zA-Z0-9_]{1,20}",
164 size in 0u64..1_000_000
165 ) {
166 use crate::storage::cloud::metadata::ArtifactMetadata;
167 let meta = ArtifactMetadata::new(&name, "hash", size);
168 prop_assert_eq!(meta.size, size);
169 }
170 }
171}