Skip to main content

entrenar/storage/cloud/
traits.rs

1//! Artifact backend trait and utilities
2
3use crate::storage::cloud::error::Result;
4use crate::storage::cloud::metadata::ArtifactMetadata;
5use sha2::{Digest, Sha256};
6
7/// Trait for artifact storage backends
8pub trait ArtifactBackend: Send + Sync {
9    /// Store an artifact and return its content-addressable hash
10    fn put(&self, name: &str, data: &[u8]) -> Result<String>;
11
12    /// Retrieve an artifact by hash
13    fn get(&self, hash: &str) -> Result<Vec<u8>>;
14
15    /// Check if an artifact exists
16    fn exists(&self, hash: &str) -> Result<bool>;
17
18    /// Delete an artifact by hash
19    fn delete(&self, hash: &str) -> Result<()>;
20
21    /// Get artifact metadata
22    fn get_metadata(&self, hash: &str) -> Result<ArtifactMetadata>;
23
24    /// List all artifacts
25    fn list(&self) -> Result<Vec<ArtifactMetadata>>;
26
27    /// Get backend type name
28    fn backend_type(&self) -> &'static str;
29}
30
31/// Compute SHA-256 hash of data
32pub 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); // SHA-256 = 32 bytes = 64 hex chars
48        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}