//! In-memory storage backend for integration tests. use makenotwork::error::{AppError, Result}; use makenotwork::storage::StorageBackend; use std::collections::HashMap; use std::sync::Mutex; /// In-memory implementation of `StorageBackend` for tests. /// Files are stored in a `HashMap>` behind a `Mutex`. pub struct InMemoryStorage { objects: Mutex>>, bucket: String, } #[allow(dead_code)] impl InMemoryStorage { pub fn new() -> Self { InMemoryStorage { objects: Mutex::new(HashMap::new()), bucket: "test-bucket".to_string(), } } /// Pre-populate a file so that subsequent `object_exists` / `download_object` /// calls see it. Useful for testing confirm_upload flows. pub fn put(&self, key: &str, data: Vec) { self.objects.lock().unwrap().insert(key.to_string(), data); } /// Retrieve stored bytes for a key. Panics if not found. pub fn get(&self, key: &str) -> Vec { self.objects.lock().unwrap().get(key).cloned().expect("key not found in storage") } } #[async_trait::async_trait] impl StorageBackend for InMemoryStorage { async fn presign_upload(&self, s3_key: &str, _content_type: &str, _expiry_secs: Option, _cache_control: Option<&str>, _max_bytes: Option) -> Result { Ok(format!("http://test-storage/{}", s3_key)) } async fn presign_download(&self, s3_key: &str, _expiry_secs: Option) -> Result { if self.objects.lock().unwrap().contains_key(s3_key) { Ok(format!("http://test-storage/{}", s3_key)) } else { Err(AppError::Storage(format!("Object not found: {}", s3_key))) } } async fn object_exists(&self, s3_key: &str) -> Result { Ok(self.objects.lock().unwrap().contains_key(s3_key)) } async fn object_size(&self, s3_key: &str) -> Result> { Ok(self.objects.lock().unwrap().get(s3_key).map(|v| v.len() as i64)) } async fn download_object(&self, s3_key: &str) -> Result> { self.objects .lock() .unwrap() .get(s3_key) .cloned() .ok_or_else(|| AppError::Storage(format!("Object not found: {}", s3_key))) } async fn download_stream(&self, s3_key: &str) -> Result { let bytes = self .objects .lock() .unwrap() .get(s3_key) .cloned() .ok_or_else(|| AppError::Storage(format!("Object not found: {}", s3_key)))?; Ok(s3_storage::ByteStream::from(bytes)) } async fn upload_object(&self, s3_key: &str, _content_type: &str, data: Vec, _cache_control: Option<&str>) -> Result<()> { self.objects.lock().unwrap().insert(s3_key.to_string(), data); Ok(()) } async fn delete_object(&self, s3_key: &str) -> Result<()> { self.objects.lock().unwrap().remove(s3_key); Ok(()) } async fn check_connectivity(&self) -> std::result::Result<(), String> { Ok(()) } fn bucket(&self) -> &str { &self.bucket } }