unitycatalog_storage_proxy/
testing.rs1use std::sync::Arc;
12
13use object_store::DynObjectStore;
14use object_store::memory::InMemory;
15use object_store::prefix::PrefixStore;
16
17use crate::backend::{
18 ProxyCapabilities, ProxyReq, Securable, StorageProxyBackend, reject_key_traversal,
19};
20use crate::error::{ProxyError, ProxyResult};
21
22#[derive(Clone)]
24pub struct InMemoryStorageProxyBackend {
25 store: Arc<InMemory>,
26 allowed: Securable,
28 prefix: String,
31 allow_write: bool,
33}
34
35impl InMemoryStorageProxyBackend {
36 pub fn table(full_name: impl Into<String>) -> Self {
39 Self {
40 store: Arc::new(InMemory::new()),
41 allowed: Securable::Table {
42 full_name: full_name.into(),
43 },
44 prefix: String::new(),
45 allow_write: true,
46 }
47 }
48
49 pub fn volume(full_name: impl Into<String>) -> Self {
51 Self {
52 store: Arc::new(InMemory::new()),
53 allowed: Securable::Volume {
54 full_name: full_name.into(),
55 },
56 prefix: String::new(),
57 allow_write: true,
58 }
59 }
60
61 pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
63 self.prefix = prefix.into();
64 self
65 }
66
67 pub fn read_only(mut self) -> Self {
69 self.allow_write = false;
70 self
71 }
72
73 pub fn store(&self) -> Arc<InMemory> {
75 self.store.clone()
76 }
77}
78
79#[async_trait::async_trait]
80impl<Cx: Send + Sync + 'static> StorageProxyBackend<Cx> for InMemoryStorageProxyBackend {
81 fn capabilities(&self) -> ProxyCapabilities {
82 ProxyCapabilities { enabled: true }
83 }
84
85 async fn authorize(&self, req: &ProxyReq, _cx: &Cx) -> ProxyResult<()> {
86 reject_key_traversal(&req.key)?;
87 if req.securable != self.allowed {
88 return Err(ProxyError::PermissionDenied(format!(
89 "securable {:?} is not authorized",
90 req.securable
91 )));
92 }
93 if !self.prefix.is_empty() && !req.key.starts_with(&self.prefix) {
94 return Err(ProxyError::OutOfScope(format!(
95 "key `{}` is outside the authorized prefix `{}`",
96 req.key, self.prefix
97 )));
98 }
99 if req.verb.is_write() && !self.allow_write {
100 return Err(ProxyError::PermissionDenied(
101 "write not permitted for this scope".into(),
102 ));
103 }
104 Ok(())
105 }
106
107 async fn open(&self, _req: &ProxyReq, _cx: &Cx) -> ProxyResult<Arc<DynObjectStore>> {
108 Ok(self.store.clone())
112 }
113}
114
115pub fn prefixed(store: Arc<InMemory>, prefix: &str) -> Arc<DynObjectStore> {
119 Arc::new(PrefixStore::new(store, prefix))
120}