use llm_shield_cloud::{CloudStorage, PutObjectOptions};
use llm_shield_cloud_aws::AwsS3Storage;
use std::env;
fn test_bucket() -> String {
env::var("TEST_S3_BUCKET").unwrap_or_else(|_| {
panic!("TEST_S3_BUCKET environment variable not set");
})
}
fn test_object_key(prefix: &str) -> String {
format!("test/{}/{}", prefix, uuid::Uuid::new_v4())
}
#[tokio::test]
#[ignore] async fn test_put_and_get_object() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("put-get");
let data = b"Hello, S3!";
storage
.put_object(&key, data)
.await
.expect("Failed to put object");
let retrieved = storage.get_object(&key).await.expect("Failed to get object");
assert_eq!(retrieved, data);
let _ = storage.delete_object(&key).await;
}
#[tokio::test]
#[ignore]
async fn test_multipart_upload() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("multipart");
let data = vec![0u8; 10 * 1024 * 1024];
storage
.put_object(&key, &data)
.await
.expect("Failed to put large object");
let metadata = storage
.get_object_metadata(&key)
.await
.expect("Failed to get metadata");
assert_eq!(metadata.size, data.len() as u64);
let _ = storage.delete_object(&key).await;
}
#[tokio::test]
#[ignore]
async fn test_object_exists() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("exists");
let data = b"existence test";
let exists_before = storage
.object_exists(&key)
.await
.expect("Failed to check existence");
assert!(!exists_before);
storage
.put_object(&key, data)
.await
.expect("Failed to put object");
let exists_after = storage
.object_exists(&key)
.await
.expect("Failed to check existence");
assert!(exists_after);
let _ = storage.delete_object(&key).await;
}
#[tokio::test]
#[ignore]
async fn test_delete_object() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("delete");
let data = b"to be deleted";
storage
.put_object(&key, data)
.await
.expect("Failed to put object");
assert!(storage.object_exists(&key).await.unwrap());
storage
.delete_object(&key)
.await
.expect("Failed to delete object");
assert!(!storage.object_exists(&key).await.unwrap());
}
#[tokio::test]
#[ignore]
async fn test_list_objects() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let prefix = format!("test/list-{}/", uuid::Uuid::new_v4());
let key1 = format!("{}file1.txt", prefix);
let key2 = format!("{}file2.txt", prefix);
let key3 = format!("{}file3.txt", prefix);
storage
.put_object(&key1, b"content1")
.await
.expect("Failed to put object 1");
storage
.put_object(&key2, b"content2")
.await
.expect("Failed to put object 2");
storage
.put_object(&key3, b"content3")
.await
.expect("Failed to put object 3");
let objects = storage
.list_objects(&prefix)
.await
.expect("Failed to list objects");
assert_eq!(objects.len(), 3);
assert!(objects.contains(&key1));
assert!(objects.contains(&key2));
assert!(objects.contains(&key3));
let _ = storage.delete_object(&key1).await;
let _ = storage.delete_object(&key2).await;
let _ = storage.delete_object(&key3).await;
}
#[tokio::test]
#[ignore]
async fn test_get_object_metadata() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("metadata");
let data = b"metadata test content";
let options = PutObjectOptions {
content_type: Some("text/plain".to_string()),
storage_class: Some("STANDARD".to_string()),
..Default::default()
};
storage
.put_object_with_options(&key, data, &options)
.await
.expect("Failed to put object with options");
let metadata = storage
.get_object_metadata(&key)
.await
.expect("Failed to get metadata");
assert_eq!(metadata.size, data.len() as u64);
assert_eq!(metadata.content_type, Some("text/plain".to_string()));
assert!(metadata.etag.is_some());
let _ = storage.delete_object(&key).await;
}
#[tokio::test]
#[ignore]
async fn test_copy_object() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let source_key = test_object_key("copy-source");
let dest_key = test_object_key("copy-dest");
let data = b"content to copy";
storage
.put_object(&source_key, data)
.await
.expect("Failed to put source object");
storage
.copy_object(&source_key, &dest_key)
.await
.expect("Failed to copy object");
let retrieved = storage
.get_object(&dest_key)
.await
.expect("Failed to get copied object");
assert_eq!(retrieved, data);
let _ = storage.delete_object(&source_key).await;
let _ = storage.delete_object(&dest_key).await;
}
#[tokio::test]
#[ignore]
async fn test_put_object_with_options() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("options");
let data = b"content with options";
let mut metadata = vec![];
metadata.push(("purpose".to_string(), "integration-test".to_string()));
metadata.push(("environment".to_string(), "test".to_string()));
let options = PutObjectOptions {
content_type: Some("application/octet-stream".to_string()),
storage_class: Some("STANDARD".to_string()),
encryption: Some("AES256".to_string()),
metadata,
};
storage
.put_object_with_options(&key, data, &options)
.await
.expect("Failed to put object with options");
let object_metadata = storage
.get_object_metadata(&key)
.await
.expect("Failed to get metadata");
assert_eq!(
object_metadata.content_type,
Some("application/octet-stream".to_string())
);
let _ = storage.delete_object(&key).await;
}
#[tokio::test]
#[ignore]
async fn test_delete_objects_batch() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let prefix = format!("test/batch-delete-{}/", uuid::Uuid::new_v4());
let keys: Vec<String> = (0..10)
.map(|i| format!("{}file{}.txt", prefix, i))
.collect();
for key in &keys {
storage
.put_object(key, b"batch delete test")
.await
.expect("Failed to put object");
}
for key in &keys {
assert!(storage.object_exists(key).await.unwrap());
}
storage
.delete_objects(&keys)
.await
.expect("Failed to delete objects batch");
for key in &keys {
assert!(!storage.object_exists(key).await.unwrap());
}
}
#[tokio::test]
#[ignore]
async fn test_list_objects_with_metadata() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let prefix = format!("test/list-metadata-{}/", uuid::Uuid::new_v4());
let key1 = format!("{}small.txt", prefix);
let key2 = format!("{}large.txt", prefix);
storage
.put_object(&key1, b"small")
.await
.expect("Failed to put small object");
storage
.put_object(&key2, &vec![0u8; 1024 * 1024])
.await
.expect("Failed to put large object");
let objects_metadata = storage
.list_objects_with_metadata(&prefix)
.await
.expect("Failed to list objects with metadata");
assert_eq!(objects_metadata.len(), 2);
let small_metadata = objects_metadata.iter().find(|m| m.size == 5).unwrap();
let large_metadata = objects_metadata
.iter()
.find(|m| m.size == 1024 * 1024)
.unwrap();
assert_eq!(small_metadata.size, 5);
assert_eq!(large_metadata.size, 1024 * 1024);
let _ = storage.delete_object(&key1).await;
let _ = storage.delete_object(&key2).await;
}
#[tokio::test]
#[ignore]
async fn test_region_configuration() {
let storage = AwsS3Storage::new_with_region(&test_bucket(), "us-west-2")
.await
.expect("Failed to initialize AwsS3Storage with region");
assert_eq!(storage.region(), "us-west-2");
assert_eq!(storage.bucket(), test_bucket());
let key = test_object_key("region-test");
let data = b"region test content";
storage
.put_object(&key, data)
.await
.expect("Failed to put object in us-west-2");
let retrieved = storage
.get_object(&key)
.await
.expect("Failed to get object from us-west-2");
assert_eq!(retrieved, data);
let _ = storage.delete_object(&key).await;
}
#[tokio::test]
#[ignore]
async fn test_large_file_operations() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("large-file");
let size = 50 * 1024 * 1024;
let data = vec![0xAB; size];
let start = std::time::Instant::now();
storage
.put_object(&key, &data)
.await
.expect("Failed to upload large file");
let upload_duration = start.elapsed();
println!("Uploaded 50MB in {:?}", upload_duration);
let start = std::time::Instant::now();
let retrieved = storage
.get_object(&key)
.await
.expect("Failed to download large file");
let download_duration = start.elapsed();
println!("Downloaded 50MB in {:?}", download_duration);
assert_eq!(retrieved.len(), size);
assert_eq!(retrieved, data);
let _ = storage.delete_object(&key).await;
}
#[tokio::test]
#[ignore]
async fn test_storage_class() {
let storage = AwsS3Storage::new(&test_bucket())
.await
.expect("Failed to initialize AwsS3Storage");
let key = test_object_key("storage-class");
let data = b"storage class test";
let options = PutObjectOptions {
storage_class: Some("INTELLIGENT_TIERING".to_string()),
..Default::default()
};
storage
.put_object_with_options(&key, data, &options)
.await
.expect("Failed to put object with storage class");
let metadata = storage
.get_object_metadata(&key)
.await
.expect("Failed to get metadata");
println!("Storage class: {:?}", metadata.storage_class);
let _ = storage.delete_object(&key).await;
}