117 lines
3.2 KiB
Rust
117 lines
3.2 KiB
Rust
use api::s3_docs::{DocsConfig, DocsStore};
|
|
use uuid::Uuid;
|
|
|
|
fn s3_env_ready() -> bool {
|
|
// Gate integration tests without requiring `-- --ignored`.
|
|
// If CI/local wants these tests to run, it must provide S3 env vars.
|
|
let required = [
|
|
"CONTROL_S3_ENDPOINT",
|
|
"CONTROL_S3_ACCESS_KEY_ID",
|
|
"CONTROL_S3_SECRET_ACCESS_KEY",
|
|
"CONTROL_S3_BUCKET_DOCS",
|
|
];
|
|
required
|
|
.iter()
|
|
.all(|k| std::env::var(k).ok().is_some_and(|v| !v.trim().is_empty()))
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn s3_docs_roundtrip_put_get_list_delete() {
|
|
if !s3_env_ready() {
|
|
eprintln!("skipping: missing S3 env (see S3_PLAN.md)");
|
|
return;
|
|
}
|
|
let cfg = DocsConfig::from_env().expect("missing S3 env (see S3_PLAN.md)");
|
|
let store = DocsStore::new(cfg)
|
|
.await
|
|
.expect("failed to init docs store");
|
|
|
|
let tenant_id = Uuid::new_v4().to_string();
|
|
let doc_type = "test";
|
|
let doc_id = Uuid::new_v4().to_string();
|
|
let filename = "hello.txt";
|
|
let key = store
|
|
.key_for(&tenant_id, doc_type, &doc_id, filename)
|
|
.expect("invalid key");
|
|
|
|
store
|
|
.put_for_tenant(
|
|
&tenant_id,
|
|
&key,
|
|
b"hello".to_vec(),
|
|
Some("text/plain".to_string()),
|
|
)
|
|
.await
|
|
.expect("put failed");
|
|
|
|
let (bytes, _ct) = store
|
|
.get_bytes_for_tenant(&tenant_id, &key)
|
|
.await
|
|
.expect("get failed");
|
|
assert_eq!(bytes, b"hello");
|
|
|
|
let prefix = format!("{}{}", store.prefix(), tenant_id);
|
|
let objects = store
|
|
.list_for_tenant(&tenant_id, &format!("{prefix}/"))
|
|
.await
|
|
.expect("list failed");
|
|
assert!(objects.iter().any(|o| o.key == key));
|
|
|
|
store
|
|
.delete_for_tenant(&tenant_id, &key)
|
|
.await
|
|
.expect("delete failed");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn s3_docs_tenant_prefix_isolation() {
|
|
if !s3_env_ready() {
|
|
eprintln!("skipping: missing S3 env (see S3_PLAN.md)");
|
|
return;
|
|
}
|
|
let cfg = DocsConfig::from_env().expect("missing S3 env (see S3_PLAN.md)");
|
|
let store = DocsStore::new(cfg)
|
|
.await
|
|
.expect("failed to init docs store");
|
|
|
|
let tenant_a = Uuid::new_v4().to_string();
|
|
let tenant_b = Uuid::new_v4().to_string();
|
|
|
|
let doc_type = "test";
|
|
let doc_id = Uuid::new_v4().to_string();
|
|
let filename = "hello.txt";
|
|
|
|
let key_a = store
|
|
.key_for(&tenant_a, doc_type, &doc_id, filename)
|
|
.expect("invalid key");
|
|
store
|
|
.put_for_tenant(
|
|
&tenant_a,
|
|
&key_a,
|
|
b"hello-a".to_vec(),
|
|
Some("text/plain".to_string()),
|
|
)
|
|
.await
|
|
.expect("put failed");
|
|
|
|
let prefix_a = format!("{}{tenant_a}/", store.prefix());
|
|
let prefix_b = format!("{}{tenant_b}/", store.prefix());
|
|
|
|
let objects_a = store
|
|
.list_for_tenant(&tenant_a, &prefix_a)
|
|
.await
|
|
.expect("list a failed");
|
|
let objects_b = store
|
|
.list_for_tenant(&tenant_b, &prefix_b)
|
|
.await
|
|
.expect("list b failed");
|
|
|
|
assert!(objects_a.iter().any(|o| o.key == key_a));
|
|
assert!(!objects_b.iter().any(|o| o.key == key_a));
|
|
|
|
store
|
|
.delete_for_tenant(&tenant_a, &key_a)
|
|
.await
|
|
.expect("delete failed");
|
|
}
|