entrenar/storage/cloud/
traits.rs1use crate::storage::cloud::error::Result;
4use crate::storage::cloud::metadata::ArtifactMetadata;
5use sha2::{Digest, Sha256};
6
7pub trait ArtifactBackend: Send + Sync {
9 fn put(&self, name: &str, data: &[u8]) -> Result<String>;
11
12 fn get(&self, hash: &str) -> Result<Vec<u8>>;
14
15 fn exists(&self, hash: &str) -> Result<bool>;
17
18 fn delete(&self, hash: &str) -> Result<()>;
20
21 fn get_metadata(&self, hash: &str) -> Result<ArtifactMetadata>;
23
24 fn list(&self) -> Result<Vec<ArtifactMetadata>>;
26
27 fn backend_type(&self) -> &'static str;
29}
30
31pub fn compute_hash(data: &[u8]) -> String {
33 let mut hasher = Sha256::new();
34 hasher.update(data);
35 let result = hasher.finalize();
36 hex::encode(result)
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn test_compute_hash() {
45 let data = b"hello world";
46 let hash = compute_hash(data);
47 assert_eq!(hash.len(), 64); assert_eq!(hash, "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
49 }
50
51 #[test]
52 fn test_compute_hash_deterministic() {
53 let data = b"test data";
54 let hash1 = compute_hash(data);
55 let hash2 = compute_hash(data);
56 assert_eq!(hash1, hash2);
57 }
58}
59
60#[cfg(test)]
61mod property_tests {
62 use super::*;
63 use proptest::prelude::*;
64
65 proptest! {
66 #![proptest_config(ProptestConfig::with_cases(200))]
67
68 #[test]
69 fn prop_hash_deterministic(data in prop::collection::vec(any::<u8>(), 0..1000)) {
70 let hash1 = compute_hash(&data);
71 let hash2 = compute_hash(&data);
72 prop_assert_eq!(hash1, hash2);
73 }
74
75 #[test]
76 fn prop_hash_length_constant(data in prop::collection::vec(any::<u8>(), 0..1000)) {
77 let hash = compute_hash(&data);
78 prop_assert_eq!(hash.len(), 64);
79 }
80 }
81}