1use std::collections::HashMap;
21use std::str::FromStr;
22use std::sync::Arc;
23
24use async_trait::async_trait;
25use futures::lock::{Mutex, MutexGuard};
26use iceberg_property_macro::Properties;
27use itertools::Itertools;
28
29use super::namespace_state::NamespaceState;
30use crate::encryption::kms::{KeyManagementClient, KmsClientFactory};
31use crate::io::{FileIO, FileIOBuilder, MemoryStorageFactory, StorageFactory};
32use crate::runtime::Runtime;
33use crate::spec::{TableMetadata, TableMetadataBuilder};
34use crate::table::Table;
35use crate::{
36 Catalog, CatalogBuilder, Error, ErrorKind, MetadataLocation, Namespace, NamespaceIdent, Result,
37 TableCommit, TableCreation, TableIdent,
38};
39
40pub const MEMORY_CATALOG_WAREHOUSE: &str = "warehouse";
42
43const LOCATION: &str = "location";
45
46#[derive(Debug, Default)]
48pub struct MemoryCatalogBuilder {
49 storage_factory: Option<Arc<dyn StorageFactory>>,
50 kms_client_factory: Option<Arc<dyn KmsClientFactory>>,
51 runtime: Option<Runtime>,
52}
53
54impl CatalogBuilder for MemoryCatalogBuilder {
55 type C = MemoryCatalog;
56
57 fn with_storage_factory(mut self, storage_factory: Arc<dyn StorageFactory>) -> Self {
58 self.storage_factory = Some(storage_factory);
59 self
60 }
61
62 fn with_kms_client_factory(mut self, kms_client_factory: Arc<dyn KmsClientFactory>) -> Self {
63 self.kms_client_factory = Some(kms_client_factory);
64 self
65 }
66
67 fn with_runtime(mut self, runtime: Runtime) -> Self {
68 self.runtime = Some(runtime);
69 self
70 }
71
72 fn load(
73 self,
74 name: impl Into<String>,
75 props: HashMap<String, String>,
76 ) -> impl Future<Output = Result<Self::C>> + Send {
77 let name = name.into();
78
79 async move {
80 let catalog_properties = MemoryCatalogProperties::from_properties(&props)?;
81 if catalog_properties.warehouse.is_empty() {
82 return Err(Error::new(
83 ErrorKind::DataInvalid,
84 "Catalog warehouse is required",
85 ));
86 }
87
88 let runtime = self.runtime.unwrap_or_else(Runtime::current);
89 let kms_client = match self.kms_client_factory {
90 Some(factory) => Some(factory.create_kms_client(&props).await?),
91 None => None,
92 };
93 MemoryCatalog::new(
94 name,
95 catalog_properties,
96 props,
97 self.storage_factory,
98 runtime,
99 kms_client,
100 )
101 }
102 }
103}
104
105#[derive(Debug, Properties)]
107pub(crate) struct MemoryCatalogProperties {
108 #[property(key = MEMORY_CATALOG_WAREHOUSE, default = "")]
109 warehouse: String,
110}
111
112pub struct MemoryCatalog {
114 name: String,
115 properties: MemoryCatalogProperties,
116 root_namespace_state: Mutex<NamespaceState>,
117 file_io: FileIO,
118 runtime: Runtime,
119 kms_client: Option<Arc<dyn KeyManagementClient>>,
120}
121
122impl std::fmt::Debug for MemoryCatalog {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 f.debug_struct("MemoryCatalog")
125 .field("name", &self.name)
126 .field("properties", &self.properties)
127 .finish_non_exhaustive()
128 }
129}
130
131impl MemoryCatalog {
132 fn new(
134 name: String,
135 properties: MemoryCatalogProperties,
136 props: HashMap<String, String>,
137 storage_factory: Option<Arc<dyn StorageFactory>>,
138 runtime: Runtime,
139 kms_client: Option<Arc<dyn KeyManagementClient>>,
140 ) -> Result<Self> {
141 let factory = storage_factory.unwrap_or_else(|| Arc::new(MemoryStorageFactory));
143
144 Ok(Self {
145 name,
146 properties,
147 file_io: FileIOBuilder::new(factory).with_props(props).build(),
148 root_namespace_state: Mutex::new(NamespaceState::default()),
149 runtime,
150 kms_client,
151 })
152 }
153
154 async fn load_table_from_locked_state(
156 &self,
157 table_ident: &TableIdent,
158 root_namespace_state: &MutexGuard<'_, NamespaceState>,
159 ) -> Result<Table> {
160 let metadata_location = root_namespace_state.get_existing_table_location(table_ident)?;
161 let metadata = TableMetadata::read_from(&self.file_io, metadata_location).await?;
162
163 let mut builder = Table::builder()
164 .identifier(table_ident.clone())
165 .metadata(metadata)
166 .metadata_location(metadata_location.to_string())
167 .file_io(self.file_io.clone())
168 .runtime(self.runtime.clone());
169 if let Some(kms_client) = self.kms_client.clone() {
170 builder = builder.kms_client(kms_client);
171 }
172 builder.build()
173 }
174}
175
176#[async_trait]
177impl Catalog for MemoryCatalog {
178 async fn list_namespaces(
180 &self,
181 maybe_parent: Option<&NamespaceIdent>,
182 ) -> Result<Vec<NamespaceIdent>> {
183 let root_namespace_state = self.root_namespace_state.lock().await;
184
185 match maybe_parent {
186 None => {
187 let namespaces = root_namespace_state
188 .list_top_level_namespaces()
189 .into_iter()
190 .map(|str| NamespaceIdent::new(str.to_string()))
191 .collect_vec();
192
193 Ok(namespaces)
194 }
195 Some(parent_namespace_ident) => {
196 let namespaces = root_namespace_state
197 .list_namespaces_under(parent_namespace_ident)?
198 .into_iter()
199 .map(|name| {
200 let mut names = parent_namespace_ident.iter().cloned().collect::<Vec<_>>();
201 names.push(name.to_string());
202 NamespaceIdent::from_vec(names)
203 })
204 .collect::<Result<Vec<_>>>()?;
205
206 Ok(namespaces)
207 }
208 }
209 }
210
211 async fn create_namespace(
213 &self,
214 namespace_ident: &NamespaceIdent,
215 properties: HashMap<String, String>,
216 ) -> Result<Namespace> {
217 let mut root_namespace_state = self.root_namespace_state.lock().await;
218
219 root_namespace_state.insert_new_namespace(namespace_ident, properties.clone())?;
220 let namespace = Namespace::with_properties(namespace_ident.clone(), properties);
221
222 Ok(namespace)
223 }
224
225 async fn get_namespace(&self, namespace_ident: &NamespaceIdent) -> Result<Namespace> {
227 let root_namespace_state = self.root_namespace_state.lock().await;
228
229 let namespace = Namespace::with_properties(
230 namespace_ident.clone(),
231 root_namespace_state
232 .get_properties(namespace_ident)?
233 .clone(),
234 );
235
236 Ok(namespace)
237 }
238
239 async fn namespace_exists(&self, namespace_ident: &NamespaceIdent) -> Result<bool> {
241 let guarded_namespaces = self.root_namespace_state.lock().await;
242
243 Ok(guarded_namespaces.namespace_exists(namespace_ident))
244 }
245
246 async fn update_namespace(
252 &self,
253 namespace_ident: &NamespaceIdent,
254 properties: HashMap<String, String>,
255 ) -> Result<()> {
256 let mut root_namespace_state = self.root_namespace_state.lock().await;
257
258 root_namespace_state.replace_properties(namespace_ident, properties)
259 }
260
261 async fn drop_namespace(&self, namespace_ident: &NamespaceIdent) -> Result<()> {
263 let mut root_namespace_state = self.root_namespace_state.lock().await;
264
265 root_namespace_state.remove_existing_namespace(namespace_ident)
266 }
267
268 async fn list_tables(&self, namespace_ident: &NamespaceIdent) -> Result<Vec<TableIdent>> {
270 let root_namespace_state = self.root_namespace_state.lock().await;
271
272 let table_names = root_namespace_state.list_tables(namespace_ident)?;
273 let table_idents = table_names
274 .into_iter()
275 .map(|table_name| TableIdent::new(namespace_ident.clone(), table_name.clone()))
276 .collect_vec();
277
278 Ok(table_idents)
279 }
280
281 async fn create_table(
283 &self,
284 namespace_ident: &NamespaceIdent,
285 table_creation: TableCreation,
286 ) -> Result<Table> {
287 let mut root_namespace_state = self.root_namespace_state.lock().await;
288
289 let table_name = table_creation.name.clone();
290 let table_ident = TableIdent::new(namespace_ident.clone(), table_name);
291
292 let table_creation = if table_creation.location.is_some() {
293 table_creation
294 } else {
295 let namespace_properties = root_namespace_state.get_properties(namespace_ident)?;
296 let location_prefix = match namespace_properties.get(LOCATION) {
297 Some(namespace_location) => namespace_location.clone(),
298 None => format!(
299 "{}/{}",
300 self.properties.warehouse,
301 namespace_ident.join("/")
302 ),
303 };
304
305 let location = format!("{}/{}", location_prefix, table_ident.name());
306
307 TableCreation {
308 location: Some(location),
309 ..table_creation
310 }
311 };
312
313 let metadata = TableMetadataBuilder::from_table_creation(table_creation)?
314 .build()?
315 .metadata;
316 let metadata_location = MetadataLocation::try_new_with_metadata(&metadata)?;
317
318 metadata.write_to(&self.file_io, &metadata_location).await?;
319
320 root_namespace_state.insert_new_table(&table_ident, metadata_location.to_string())?;
321
322 let mut builder = Table::builder()
323 .file_io(self.file_io.clone())
324 .metadata_location(metadata_location.to_string())
325 .metadata(metadata)
326 .identifier(table_ident)
327 .runtime(self.runtime.clone());
328 if let Some(kms_client) = self.kms_client.clone() {
329 builder = builder.kms_client(kms_client);
330 }
331 builder.build()
332 }
333
334 async fn load_table(&self, table_ident: &TableIdent) -> Result<Table> {
336 let root_namespace_state = self.root_namespace_state.lock().await;
337
338 self.load_table_from_locked_state(table_ident, &root_namespace_state)
339 .await
340 }
341
342 async fn drop_table(&self, table_ident: &TableIdent) -> Result<()> {
344 let mut root_namespace_state = self.root_namespace_state.lock().await;
345
346 root_namespace_state.remove_existing_table(table_ident)?;
347 Ok(())
348 }
349
350 async fn purge_table(&self, table_ident: &TableIdent) -> Result<()> {
351 let table_info = self.load_table(table_ident).await?;
352 self.drop_table(table_ident).await?;
353 crate::catalog::utils::drop_table_data(&table_info).await
354 }
355
356 async fn table_exists(&self, table_ident: &TableIdent) -> Result<bool> {
358 let root_namespace_state = self.root_namespace_state.lock().await;
359
360 root_namespace_state.table_exists(table_ident)
361 }
362
363 async fn rename_table(
365 &self,
366 src_table_ident: &TableIdent,
367 dst_table_ident: &TableIdent,
368 ) -> Result<()> {
369 let mut root_namespace_state = self.root_namespace_state.lock().await;
370
371 let mut new_root_namespace_state = root_namespace_state.clone();
372 let metadata_location = new_root_namespace_state
373 .get_existing_table_location(src_table_ident)?
374 .clone();
375 new_root_namespace_state.remove_existing_table(src_table_ident)?;
376 new_root_namespace_state.insert_new_table(dst_table_ident, metadata_location)?;
377 *root_namespace_state = new_root_namespace_state;
378
379 Ok(())
380 }
381
382 async fn register_table(
383 &self,
384 table_ident: &TableIdent,
385 metadata_location: String,
386 ) -> Result<Table> {
387 let mut root_namespace_state = self.root_namespace_state.lock().await;
388 root_namespace_state.insert_new_table(&table_ident.clone(), metadata_location.clone())?;
389
390 let metadata = TableMetadata::read_from(&self.file_io, &metadata_location).await?;
391
392 let mut builder = Table::builder()
393 .file_io(self.file_io.clone())
394 .metadata_location(metadata_location)
395 .metadata(metadata)
396 .identifier(table_ident.clone())
397 .runtime(self.runtime.clone());
398 if let Some(kms_client) = self.kms_client.clone() {
399 builder = builder.kms_client(kms_client);
400 }
401 builder.build()
402 }
403
404 async fn update_table(&self, commit: TableCommit) -> Result<Table> {
406 let mut root_namespace_state = self.root_namespace_state.lock().await;
407
408 let current_table = self
409 .load_table_from_locked_state(commit.identifier(), &root_namespace_state)
410 .await?;
411
412 let staged_table = commit.apply(current_table)?;
414
415 let metadata_location =
417 MetadataLocation::from_str(staged_table.metadata_location_result()?)?;
418 staged_table
419 .metadata()
420 .write_to(staged_table.file_io(), &metadata_location)
421 .await?;
422
423 let updated_table = root_namespace_state.commit_table_update(staged_table)?;
425
426 Ok(updated_table)
427 }
428}
429
430#[cfg(test)]
431pub(crate) mod tests {
432 use std::collections::HashSet;
433 use std::hash::Hash;
434 use std::iter::FromIterator;
435 use std::vec;
436
437 use regex::Regex;
438 use tempfile::TempDir;
439
440 use super::*;
441 use crate::encryption::kms::MemoryKmsClientFactory;
442 use crate::io::{FileIO, LocalFsStorageFactory};
443 use crate::spec::{NestedField, PartitionSpec, PrimitiveType, Schema, SortOrder, Type};
444 use crate::test_utils::test_runtime;
445 use crate::transaction::{ApplyTransactionAction, Transaction};
446
447 fn temp_path() -> String {
448 let temp_dir = TempDir::new().unwrap();
449 temp_dir.path().to_str().unwrap().to_string()
450 }
451
452 #[test]
453 fn test_catalog_properties() {
454 let properties = MemoryCatalogProperties::from_properties(&HashMap::from([(
455 MEMORY_CATALOG_WAREHOUSE.to_string(),
456 "memory:///warehouse".to_string(),
457 )]))
458 .unwrap();
459
460 assert_eq!(properties.warehouse, "memory:///warehouse");
461 }
462
463 #[test]
464 fn test_catalog_properties_warehouse_defaults_to_empty() {
465 let missing = MemoryCatalogProperties::from_properties(&HashMap::new()).unwrap();
466 let explicitly_empty = MemoryCatalogProperties::from_properties(&HashMap::from([(
467 MEMORY_CATALOG_WAREHOUSE.to_string(),
468 String::new(),
469 )]))
470 .unwrap();
471
472 assert_eq!(missing.warehouse, "");
473 assert_eq!(explicitly_empty.warehouse, "");
474 }
475
476 #[tokio::test]
477 async fn test_catalog_forwards_properties_to_file_io() {
478 let catalog = MemoryCatalogBuilder::default()
479 .load(
480 "memory",
481 HashMap::from([
482 (
483 MEMORY_CATALOG_WAREHOUSE.to_string(),
484 "memory:///warehouse".to_string(),
485 ),
486 ("custom.property".to_string(), "value".to_string()),
487 ]),
488 )
489 .await
490 .unwrap();
491 let file_io_props = catalog.file_io.config().props();
492
493 assert_eq!(
494 file_io_props.get("custom.property"),
495 Some(&"value".to_string())
496 );
497 assert_eq!(
498 file_io_props.get(MEMORY_CATALOG_WAREHOUSE),
499 Some(&"memory:///warehouse".to_string())
500 );
501 }
502
503 pub(crate) async fn new_memory_catalog() -> impl Catalog {
504 let warehouse_location = temp_path();
505 MemoryCatalogBuilder::default()
506 .load(
507 "memory",
508 HashMap::from([(MEMORY_CATALOG_WAREHOUSE.to_string(), warehouse_location)]),
509 )
510 .await
511 .unwrap()
512 }
513
514 async fn create_namespace<C: Catalog>(catalog: &C, namespace_ident: &NamespaceIdent) {
515 let _ = catalog
516 .create_namespace(namespace_ident, HashMap::new())
517 .await
518 .unwrap();
519 }
520
521 async fn create_namespaces<C: Catalog>(catalog: &C, namespace_idents: &Vec<&NamespaceIdent>) {
522 for namespace_ident in namespace_idents {
523 let _ = create_namespace(catalog, namespace_ident).await;
524 }
525 }
526
527 fn to_set<T: Eq + Hash>(vec: Vec<T>) -> HashSet<T> {
528 HashSet::from_iter(vec)
529 }
530
531 fn simple_table_schema() -> Schema {
532 Schema::builder()
533 .with_fields(vec![
534 NestedField::required(1, "foo", Type::Primitive(PrimitiveType::Int)).into(),
535 ])
536 .build()
537 .unwrap()
538 }
539
540 async fn create_table<C: Catalog>(catalog: &C, table_ident: &TableIdent) -> Table {
541 catalog
542 .create_table(
543 &table_ident.namespace,
544 TableCreation::builder()
545 .name(table_ident.name().into())
546 .schema(simple_table_schema())
547 .build(),
548 )
549 .await
550 .unwrap()
551 }
552
553 async fn create_tables<C: Catalog>(catalog: &C, table_idents: Vec<&TableIdent>) {
554 for table_ident in table_idents {
555 create_table(catalog, table_ident).await;
556 }
557 }
558
559 async fn create_table_with_namespace<C: Catalog>(catalog: &C) -> Table {
560 let namespace_ident = NamespaceIdent::new("abc".into());
561 create_namespace(catalog, &namespace_ident).await;
562
563 let table_ident = TableIdent::new(namespace_ident, "test".to_string());
564 create_table(catalog, &table_ident).await
565 }
566
567 fn assert_table_eq(table: &Table, expected_table_ident: &TableIdent, expected_schema: &Schema) {
568 assert_eq!(table.identifier(), expected_table_ident);
569
570 let metadata = table.metadata();
571
572 assert_eq!(metadata.current_schema().as_ref(), expected_schema);
573
574 let expected_partition_spec = PartitionSpec::builder((*expected_schema).clone())
575 .with_spec_id(0)
576 .build()
577 .unwrap();
578
579 assert_eq!(
580 metadata
581 .partition_specs_iter()
582 .map(|p| p.as_ref())
583 .collect_vec(),
584 vec![&expected_partition_spec]
585 );
586
587 let expected_sorted_order = SortOrder::builder()
588 .with_order_id(0)
589 .with_fields(vec![])
590 .build(expected_schema)
591 .unwrap();
592
593 assert_eq!(
594 metadata
595 .sort_orders_iter()
596 .map(|s| s.as_ref())
597 .collect_vec(),
598 vec![&expected_sorted_order]
599 );
600
601 assert_eq!(metadata.properties(), &HashMap::new());
602
603 assert!(!table.readonly());
604 }
605
606 const UUID_REGEX_STR: &str = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
607
608 fn assert_table_metadata_location_matches(table: &Table, regex_str: &str) {
609 let actual = table.metadata_location().unwrap().to_string();
610 let regex = Regex::new(regex_str).unwrap();
611 assert!(
612 regex.is_match(&actual),
613 "Expected metadata location to match regex, but got location: {actual} and regex: {regex}"
614 )
615 }
616
617 #[tokio::test]
618 async fn test_list_namespaces_returns_empty_vector() {
619 let catalog = new_memory_catalog().await;
620
621 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![]);
622 }
623
624 #[tokio::test]
625 async fn test_list_namespaces_returns_single_namespace() {
626 let catalog = new_memory_catalog().await;
627 let namespace_ident = NamespaceIdent::new("abc".into());
628 create_namespace(&catalog, &namespace_ident).await;
629
630 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![
631 namespace_ident
632 ]);
633 }
634
635 #[tokio::test]
636 async fn test_list_namespaces_returns_multiple_namespaces() {
637 let catalog = new_memory_catalog().await;
638 let namespace_ident_1 = NamespaceIdent::new("a".into());
639 let namespace_ident_2 = NamespaceIdent::new("b".into());
640 create_namespaces(&catalog, &vec![&namespace_ident_1, &namespace_ident_2]).await;
641
642 assert_eq!(
643 to_set(catalog.list_namespaces(None).await.unwrap()),
644 to_set(vec![namespace_ident_1, namespace_ident_2])
645 );
646 }
647
648 #[tokio::test]
649 async fn test_list_namespaces_returns_only_top_level_namespaces() {
650 let catalog = new_memory_catalog().await;
651 let namespace_ident_1 = NamespaceIdent::new("a".into());
652 let namespace_ident_2 = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
653 let namespace_ident_3 = NamespaceIdent::new("b".into());
654 create_namespaces(&catalog, &vec![
655 &namespace_ident_1,
656 &namespace_ident_2,
657 &namespace_ident_3,
658 ])
659 .await;
660
661 assert_eq!(
662 to_set(catalog.list_namespaces(None).await.unwrap()),
663 to_set(vec![namespace_ident_1, namespace_ident_3])
664 );
665 }
666
667 #[tokio::test]
668 async fn test_list_namespaces_returns_no_namespaces_under_parent() {
669 let catalog = new_memory_catalog().await;
670 let namespace_ident_1 = NamespaceIdent::new("a".into());
671 let namespace_ident_2 = NamespaceIdent::new("b".into());
672 create_namespaces(&catalog, &vec![&namespace_ident_1, &namespace_ident_2]).await;
673
674 assert_eq!(
675 catalog
676 .list_namespaces(Some(&namespace_ident_1))
677 .await
678 .unwrap(),
679 vec![]
680 );
681 }
682
683 #[tokio::test]
684 async fn test_list_namespaces_returns_namespace_under_parent() {
685 let catalog = new_memory_catalog().await;
686 let namespace_ident_1 = NamespaceIdent::new("a".into());
687 let namespace_ident_2 = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
688 let namespace_ident_3 = NamespaceIdent::new("c".into());
689 create_namespaces(&catalog, &vec![
690 &namespace_ident_1,
691 &namespace_ident_2,
692 &namespace_ident_3,
693 ])
694 .await;
695
696 assert_eq!(
697 to_set(catalog.list_namespaces(None).await.unwrap()),
698 to_set(vec![namespace_ident_1.clone(), namespace_ident_3])
699 );
700
701 assert_eq!(
702 catalog
703 .list_namespaces(Some(&namespace_ident_1))
704 .await
705 .unwrap(),
706 vec![namespace_ident_2]
707 );
708 }
709
710 #[tokio::test]
711 async fn test_list_namespaces_returns_multiple_namespaces_under_parent() {
712 let catalog = new_memory_catalog().await;
713 let namespace_ident_1 = NamespaceIdent::new("a".to_string());
714 let namespace_ident_2 = NamespaceIdent::from_strs(vec!["a", "a"]).unwrap();
715 let namespace_ident_3 = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
716 let namespace_ident_4 = NamespaceIdent::from_strs(vec!["a", "c"]).unwrap();
717 let namespace_ident_5 = NamespaceIdent::new("b".into());
718 create_namespaces(&catalog, &vec![
719 &namespace_ident_1,
720 &namespace_ident_2,
721 &namespace_ident_3,
722 &namespace_ident_4,
723 &namespace_ident_5,
724 ])
725 .await;
726
727 assert_eq!(
728 to_set(
729 catalog
730 .list_namespaces(Some(&namespace_ident_1))
731 .await
732 .unwrap()
733 ),
734 to_set(vec![
735 namespace_ident_2,
736 namespace_ident_3,
737 namespace_ident_4,
738 ])
739 );
740 }
741
742 #[tokio::test]
743 async fn test_namespace_exists_returns_false() {
744 let catalog = new_memory_catalog().await;
745 let namespace_ident = NamespaceIdent::new("a".into());
746 create_namespace(&catalog, &namespace_ident).await;
747
748 assert!(
749 !catalog
750 .namespace_exists(&NamespaceIdent::new("b".into()))
751 .await
752 .unwrap()
753 );
754 }
755
756 #[tokio::test]
757 async fn test_namespace_exists_returns_true() {
758 let catalog = new_memory_catalog().await;
759 let namespace_ident = NamespaceIdent::new("a".into());
760 create_namespace(&catalog, &namespace_ident).await;
761
762 assert!(catalog.namespace_exists(&namespace_ident).await.unwrap());
763 }
764
765 #[tokio::test]
766 async fn test_create_namespace_with_empty_properties() {
767 let catalog = new_memory_catalog().await;
768 let namespace_ident = NamespaceIdent::new("a".into());
769
770 assert_eq!(
771 catalog
772 .create_namespace(&namespace_ident, HashMap::new())
773 .await
774 .unwrap(),
775 Namespace::new(namespace_ident.clone())
776 );
777
778 assert_eq!(
779 catalog.get_namespace(&namespace_ident).await.unwrap(),
780 Namespace::with_properties(namespace_ident, HashMap::new())
781 );
782 }
783
784 #[tokio::test]
785 async fn test_create_namespace_with_properties() {
786 let catalog = new_memory_catalog().await;
787 let namespace_ident = NamespaceIdent::new("abc".into());
788
789 let mut properties: HashMap<String, String> = HashMap::new();
790 properties.insert("k".into(), "v".into());
791
792 assert_eq!(
793 catalog
794 .create_namespace(&namespace_ident, properties.clone())
795 .await
796 .unwrap(),
797 Namespace::with_properties(namespace_ident.clone(), properties.clone())
798 );
799
800 assert_eq!(
801 catalog.get_namespace(&namespace_ident).await.unwrap(),
802 Namespace::with_properties(namespace_ident, properties)
803 );
804 }
805
806 #[tokio::test]
807 async fn test_create_namespace_throws_error_if_namespace_already_exists() {
808 let catalog = new_memory_catalog().await;
809 let namespace_ident = NamespaceIdent::new("a".into());
810 create_namespace(&catalog, &namespace_ident).await;
811
812 assert_eq!(
813 catalog
814 .create_namespace(&namespace_ident, HashMap::new())
815 .await
816 .unwrap_err()
817 .to_string(),
818 format!(
819 "NamespaceAlreadyExists => Cannot create namespace {:?}. Namespace already exists.",
820 &namespace_ident
821 )
822 );
823
824 assert_eq!(
825 catalog.get_namespace(&namespace_ident).await.unwrap(),
826 Namespace::with_properties(namespace_ident, HashMap::new())
827 );
828 }
829
830 #[tokio::test]
831 async fn test_create_nested_namespace() {
832 let catalog = new_memory_catalog().await;
833 let parent_namespace_ident = NamespaceIdent::new("a".into());
834 create_namespace(&catalog, &parent_namespace_ident).await;
835
836 let child_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
837
838 assert_eq!(
839 catalog
840 .create_namespace(&child_namespace_ident, HashMap::new())
841 .await
842 .unwrap(),
843 Namespace::new(child_namespace_ident.clone())
844 );
845
846 assert_eq!(
847 catalog.get_namespace(&child_namespace_ident).await.unwrap(),
848 Namespace::with_properties(child_namespace_ident, HashMap::new())
849 );
850 }
851
852 #[tokio::test]
853 async fn test_create_deeply_nested_namespace() {
854 let catalog = new_memory_catalog().await;
855 let namespace_ident_a = NamespaceIdent::new("a".into());
856 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
857 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
858
859 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
860
861 assert_eq!(
862 catalog
863 .create_namespace(&namespace_ident_a_b_c, HashMap::new())
864 .await
865 .unwrap(),
866 Namespace::new(namespace_ident_a_b_c.clone())
867 );
868
869 assert_eq!(
870 catalog.get_namespace(&namespace_ident_a_b_c).await.unwrap(),
871 Namespace::with_properties(namespace_ident_a_b_c, HashMap::new())
872 );
873 }
874
875 #[tokio::test]
876 async fn test_create_nested_namespace_throws_error_if_top_level_namespace_doesnt_exist() {
877 let catalog = new_memory_catalog().await;
878
879 let nested_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
880
881 assert_eq!(
882 catalog
883 .create_namespace(&nested_namespace_ident, HashMap::new())
884 .await
885 .unwrap_err()
886 .to_string(),
887 format!(
888 "NamespaceNotFound => No such namespace: {:?}",
889 NamespaceIdent::new("a".into())
890 )
891 );
892
893 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![]);
894 }
895
896 #[tokio::test]
897 async fn test_create_deeply_nested_namespace_throws_error_if_intermediate_namespace_doesnt_exist()
898 {
899 let catalog = new_memory_catalog().await;
900
901 let namespace_ident_a = NamespaceIdent::new("a".into());
902 create_namespace(&catalog, &namespace_ident_a).await;
903
904 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
905
906 assert_eq!(
907 catalog
908 .create_namespace(&namespace_ident_a_b_c, HashMap::new())
909 .await
910 .unwrap_err()
911 .to_string(),
912 format!(
913 "NamespaceNotFound => No such namespace: {:?}",
914 NamespaceIdent::from_strs(vec!["a", "b"]).unwrap()
915 )
916 );
917
918 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![
919 namespace_ident_a.clone()
920 ]);
921
922 assert_eq!(
923 catalog
924 .list_namespaces(Some(&namespace_ident_a))
925 .await
926 .unwrap(),
927 vec![]
928 );
929 }
930
931 #[tokio::test]
932 async fn test_get_namespace() {
933 let catalog = new_memory_catalog().await;
934 let namespace_ident = NamespaceIdent::new("abc".into());
935
936 let mut properties: HashMap<String, String> = HashMap::new();
937 properties.insert("k".into(), "v".into());
938 let _ = catalog
939 .create_namespace(&namespace_ident, properties.clone())
940 .await
941 .unwrap();
942
943 assert_eq!(
944 catalog.get_namespace(&namespace_ident).await.unwrap(),
945 Namespace::with_properties(namespace_ident, properties)
946 )
947 }
948
949 #[tokio::test]
950 async fn test_get_nested_namespace() {
951 let catalog = new_memory_catalog().await;
952 let namespace_ident_a = NamespaceIdent::new("a".into());
953 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
954 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
955
956 assert_eq!(
957 catalog.get_namespace(&namespace_ident_a_b).await.unwrap(),
958 Namespace::with_properties(namespace_ident_a_b, HashMap::new())
959 );
960 }
961
962 #[tokio::test]
963 async fn test_get_deeply_nested_namespace() {
964 let catalog = new_memory_catalog().await;
965 let namespace_ident_a = NamespaceIdent::new("a".into());
966 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
967 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
968 create_namespaces(&catalog, &vec![
969 &namespace_ident_a,
970 &namespace_ident_a_b,
971 &namespace_ident_a_b_c,
972 ])
973 .await;
974
975 assert_eq!(
976 catalog.get_namespace(&namespace_ident_a_b_c).await.unwrap(),
977 Namespace::with_properties(namespace_ident_a_b_c, HashMap::new())
978 );
979 }
980
981 #[tokio::test]
982 async fn test_get_namespace_throws_error_if_namespace_doesnt_exist() {
983 let catalog = new_memory_catalog().await;
984 create_namespace(&catalog, &NamespaceIdent::new("a".into())).await;
985
986 let non_existent_namespace_ident = NamespaceIdent::new("b".into());
987 assert_eq!(
988 catalog
989 .get_namespace(&non_existent_namespace_ident)
990 .await
991 .unwrap_err()
992 .to_string(),
993 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
994 )
995 }
996
997 #[tokio::test]
998 async fn test_update_namespace() {
999 let catalog = new_memory_catalog().await;
1000 let namespace_ident = NamespaceIdent::new("abc".into());
1001 create_namespace(&catalog, &namespace_ident).await;
1002
1003 let mut new_properties: HashMap<String, String> = HashMap::new();
1004 new_properties.insert("k".into(), "v".into());
1005
1006 catalog
1007 .update_namespace(&namespace_ident, new_properties.clone())
1008 .await
1009 .unwrap();
1010
1011 assert_eq!(
1012 catalog.get_namespace(&namespace_ident).await.unwrap(),
1013 Namespace::with_properties(namespace_ident, new_properties)
1014 )
1015 }
1016
1017 #[tokio::test]
1018 async fn test_update_nested_namespace() {
1019 let catalog = new_memory_catalog().await;
1020 let namespace_ident_a = NamespaceIdent::new("a".into());
1021 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1022 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1023
1024 let mut new_properties = HashMap::new();
1025 new_properties.insert("k".into(), "v".into());
1026
1027 catalog
1028 .update_namespace(&namespace_ident_a_b, new_properties.clone())
1029 .await
1030 .unwrap();
1031
1032 assert_eq!(
1033 catalog.get_namespace(&namespace_ident_a_b).await.unwrap(),
1034 Namespace::with_properties(namespace_ident_a_b, new_properties)
1035 );
1036 }
1037
1038 #[tokio::test]
1039 async fn test_update_deeply_nested_namespace() {
1040 let catalog = new_memory_catalog().await;
1041 let namespace_ident_a = NamespaceIdent::new("a".into());
1042 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1043 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
1044 create_namespaces(&catalog, &vec![
1045 &namespace_ident_a,
1046 &namespace_ident_a_b,
1047 &namespace_ident_a_b_c,
1048 ])
1049 .await;
1050
1051 let mut new_properties = HashMap::new();
1052 new_properties.insert("k".into(), "v".into());
1053
1054 catalog
1055 .update_namespace(&namespace_ident_a_b_c, new_properties.clone())
1056 .await
1057 .unwrap();
1058
1059 assert_eq!(
1060 catalog.get_namespace(&namespace_ident_a_b_c).await.unwrap(),
1061 Namespace::with_properties(namespace_ident_a_b_c, new_properties)
1062 );
1063 }
1064
1065 #[tokio::test]
1066 async fn test_update_namespace_throws_error_if_namespace_doesnt_exist() {
1067 let catalog = new_memory_catalog().await;
1068 create_namespace(&catalog, &NamespaceIdent::new("abc".into())).await;
1069
1070 let non_existent_namespace_ident = NamespaceIdent::new("def".into());
1071 assert_eq!(
1072 catalog
1073 .update_namespace(&non_existent_namespace_ident, HashMap::new())
1074 .await
1075 .unwrap_err()
1076 .to_string(),
1077 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
1078 )
1079 }
1080
1081 #[tokio::test]
1082 async fn test_drop_namespace() {
1083 let catalog = new_memory_catalog().await;
1084 let namespace_ident = NamespaceIdent::new("abc".into());
1085 create_namespace(&catalog, &namespace_ident).await;
1086
1087 catalog.drop_namespace(&namespace_ident).await.unwrap();
1088
1089 assert!(!catalog.namespace_exists(&namespace_ident).await.unwrap())
1090 }
1091
1092 #[tokio::test]
1093 async fn test_drop_nested_namespace() {
1094 let catalog = new_memory_catalog().await;
1095 let namespace_ident_a = NamespaceIdent::new("a".into());
1096 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1097 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1098
1099 catalog.drop_namespace(&namespace_ident_a_b).await.unwrap();
1100
1101 assert!(
1102 !catalog
1103 .namespace_exists(&namespace_ident_a_b)
1104 .await
1105 .unwrap()
1106 );
1107
1108 assert!(catalog.namespace_exists(&namespace_ident_a).await.unwrap());
1109 }
1110
1111 #[tokio::test]
1112 async fn test_drop_deeply_nested_namespace() {
1113 let catalog = new_memory_catalog().await;
1114 let namespace_ident_a = NamespaceIdent::new("a".into());
1115 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1116 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
1117 create_namespaces(&catalog, &vec![
1118 &namespace_ident_a,
1119 &namespace_ident_a_b,
1120 &namespace_ident_a_b_c,
1121 ])
1122 .await;
1123
1124 catalog
1125 .drop_namespace(&namespace_ident_a_b_c)
1126 .await
1127 .unwrap();
1128
1129 assert!(
1130 !catalog
1131 .namespace_exists(&namespace_ident_a_b_c)
1132 .await
1133 .unwrap()
1134 );
1135
1136 assert!(
1137 catalog
1138 .namespace_exists(&namespace_ident_a_b)
1139 .await
1140 .unwrap()
1141 );
1142
1143 assert!(catalog.namespace_exists(&namespace_ident_a).await.unwrap());
1144 }
1145
1146 #[tokio::test]
1147 async fn test_drop_namespace_throws_error_if_namespace_doesnt_exist() {
1148 let catalog = new_memory_catalog().await;
1149
1150 let non_existent_namespace_ident = NamespaceIdent::new("abc".into());
1151 assert_eq!(
1152 catalog
1153 .drop_namespace(&non_existent_namespace_ident)
1154 .await
1155 .unwrap_err()
1156 .to_string(),
1157 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
1158 )
1159 }
1160
1161 #[tokio::test]
1162 async fn test_drop_namespace_throws_error_if_nested_namespace_doesnt_exist() {
1163 let catalog = new_memory_catalog().await;
1164 create_namespace(&catalog, &NamespaceIdent::new("a".into())).await;
1165
1166 let non_existent_namespace_ident =
1167 NamespaceIdent::from_vec(vec!["a".into(), "b".into()]).unwrap();
1168 assert_eq!(
1169 catalog
1170 .drop_namespace(&non_existent_namespace_ident)
1171 .await
1172 .unwrap_err()
1173 .to_string(),
1174 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
1175 )
1176 }
1177
1178 #[tokio::test]
1179 async fn test_dropping_a_namespace_also_drops_namespaces_nested_under_that_one() {
1180 let catalog = new_memory_catalog().await;
1181 let namespace_ident_a = NamespaceIdent::new("a".into());
1182 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1183 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1184
1185 catalog.drop_namespace(&namespace_ident_a).await.unwrap();
1186
1187 assert!(!catalog.namespace_exists(&namespace_ident_a).await.unwrap());
1188
1189 assert!(
1190 !catalog
1191 .namespace_exists(&namespace_ident_a_b)
1192 .await
1193 .unwrap()
1194 );
1195 }
1196
1197 #[tokio::test]
1198 async fn test_create_table_with_location() {
1199 let tmp_dir = TempDir::new().unwrap();
1200 let catalog = new_memory_catalog().await;
1201 let namespace_ident = NamespaceIdent::new("a".into());
1202 create_namespace(&catalog, &namespace_ident).await;
1203
1204 let table_name = "abc";
1205 let location = tmp_dir.path().to_str().unwrap().to_string();
1206 let table_creation = TableCreation::builder()
1207 .name(table_name.into())
1208 .location(location.clone())
1209 .schema(simple_table_schema())
1210 .build();
1211
1212 let expected_table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1213
1214 assert_table_eq(
1215 &catalog
1216 .create_table(&namespace_ident, table_creation)
1217 .await
1218 .unwrap(),
1219 &expected_table_ident,
1220 &simple_table_schema(),
1221 );
1222
1223 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1224
1225 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1226
1227 assert!(
1228 table
1229 .metadata_location()
1230 .unwrap()
1231 .to_string()
1232 .starts_with(&location)
1233 )
1234 }
1235
1236 #[tokio::test]
1237 async fn test_create_table_falls_back_to_namespace_location_if_table_location_is_missing() {
1238 let warehouse_location = temp_path();
1239 let catalog = MemoryCatalogBuilder::default()
1240 .load(
1241 "memory",
1242 HashMap::from([(
1243 MEMORY_CATALOG_WAREHOUSE.to_string(),
1244 warehouse_location.clone(),
1245 )]),
1246 )
1247 .await
1248 .unwrap();
1249
1250 let namespace_ident = NamespaceIdent::new("a".into());
1251 let mut namespace_properties = HashMap::new();
1252 let namespace_location = temp_path();
1253 namespace_properties.insert(LOCATION.to_string(), namespace_location.to_string());
1254 catalog
1255 .create_namespace(&namespace_ident, namespace_properties)
1256 .await
1257 .unwrap();
1258
1259 let table_name = "tbl1";
1260 let expected_table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1261 let expected_table_metadata_location_regex =
1262 format!("^{namespace_location}/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$",);
1263
1264 let table = catalog
1265 .create_table(
1266 &namespace_ident,
1267 TableCreation::builder()
1268 .name(table_name.into())
1269 .schema(simple_table_schema())
1270 .build(),
1272 )
1273 .await
1274 .unwrap();
1275 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1276 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1277
1278 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1279 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1280 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1281 }
1282
1283 #[tokio::test]
1284 async fn test_create_table_in_nested_namespace_falls_back_to_nested_namespace_location_if_table_location_is_missing()
1285 {
1286 let warehouse_location = temp_path();
1287 let catalog = MemoryCatalogBuilder::default()
1288 .load(
1289 "memory",
1290 HashMap::from([(
1291 MEMORY_CATALOG_WAREHOUSE.to_string(),
1292 warehouse_location.clone(),
1293 )]),
1294 )
1295 .await
1296 .unwrap();
1297
1298 let namespace_ident = NamespaceIdent::new("a".into());
1299 let mut namespace_properties = HashMap::new();
1300 let namespace_location = temp_path();
1301 namespace_properties.insert(LOCATION.to_string(), namespace_location.to_string());
1302 catalog
1303 .create_namespace(&namespace_ident, namespace_properties)
1304 .await
1305 .unwrap();
1306
1307 let nested_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1308 let mut nested_namespace_properties = HashMap::new();
1309 let nested_namespace_location = temp_path();
1310 nested_namespace_properties
1311 .insert(LOCATION.to_string(), nested_namespace_location.to_string());
1312 catalog
1313 .create_namespace(&nested_namespace_ident, nested_namespace_properties)
1314 .await
1315 .unwrap();
1316
1317 let table_name = "tbl1";
1318 let expected_table_ident =
1319 TableIdent::new(nested_namespace_ident.clone(), table_name.into());
1320 let expected_table_metadata_location_regex = format!(
1321 "^{nested_namespace_location}/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$",
1322 );
1323
1324 let table = catalog
1325 .create_table(
1326 &nested_namespace_ident,
1327 TableCreation::builder()
1328 .name(table_name.into())
1329 .schema(simple_table_schema())
1330 .build(),
1332 )
1333 .await
1334 .unwrap();
1335 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1336 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1337
1338 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1339 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1340 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1341 }
1342
1343 #[tokio::test]
1344 async fn test_create_table_falls_back_to_warehouse_location_if_both_table_location_and_namespace_location_are_missing()
1345 {
1346 let warehouse_location = temp_path();
1347 let catalog = MemoryCatalogBuilder::default()
1348 .load(
1349 "memory",
1350 HashMap::from([(
1351 MEMORY_CATALOG_WAREHOUSE.to_string(),
1352 warehouse_location.clone(),
1353 )]),
1354 )
1355 .await
1356 .unwrap();
1357
1358 let namespace_ident = NamespaceIdent::new("a".into());
1359 let namespace_properties = HashMap::new();
1361 catalog
1362 .create_namespace(&namespace_ident, namespace_properties)
1363 .await
1364 .unwrap();
1365
1366 let table_name = "tbl1";
1367 let expected_table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1368 let expected_table_metadata_location_regex =
1369 format!("^{warehouse_location}/a/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$");
1370
1371 let table = catalog
1372 .create_table(
1373 &namespace_ident,
1374 TableCreation::builder()
1375 .name(table_name.into())
1376 .schema(simple_table_schema())
1377 .build(),
1379 )
1380 .await
1381 .unwrap();
1382 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1383 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1384
1385 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1386 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1387 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1388 }
1389
1390 #[tokio::test]
1391 async fn test_create_table_in_nested_namespace_falls_back_to_warehouse_location_if_both_table_location_and_namespace_location_are_missing()
1392 {
1393 let warehouse_location = temp_path();
1394 let catalog = MemoryCatalogBuilder::default()
1395 .load(
1396 "memory",
1397 HashMap::from([(
1398 MEMORY_CATALOG_WAREHOUSE.to_string(),
1399 warehouse_location.clone(),
1400 )]),
1401 )
1402 .await
1403 .unwrap();
1404
1405 let namespace_ident = NamespaceIdent::new("a".into());
1406 catalog
1407 .create_namespace(&namespace_ident, HashMap::new())
1409 .await
1410 .unwrap();
1411
1412 let nested_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1413 catalog
1414 .create_namespace(&nested_namespace_ident, HashMap::new())
1416 .await
1417 .unwrap();
1418
1419 let table_name = "tbl1";
1420 let expected_table_ident =
1421 TableIdent::new(nested_namespace_ident.clone(), table_name.into());
1422 let expected_table_metadata_location_regex = format!(
1423 "^{warehouse_location}/a/b/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$"
1424 );
1425
1426 let table = catalog
1427 .create_table(
1428 &nested_namespace_ident,
1429 TableCreation::builder()
1430 .name(table_name.into())
1431 .schema(simple_table_schema())
1432 .build(),
1434 )
1435 .await
1436 .unwrap();
1437 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1438 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1439
1440 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1441 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1442 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1443 }
1444
1445 #[tokio::test]
1446 async fn test_load_throws_error_if_warehouse_is_missing() {
1447 let error = MemoryCatalogBuilder::default()
1448 .load("memory", HashMap::from([]))
1449 .await
1450 .unwrap_err();
1451
1452 assert_eq!(error.kind(), ErrorKind::DataInvalid);
1453 assert_eq!(error.message(), "Catalog warehouse is required");
1454 }
1455
1456 #[tokio::test]
1457 async fn test_load_throws_error_if_warehouse_is_empty() {
1458 let error = MemoryCatalogBuilder::default()
1459 .load(
1460 "memory",
1461 HashMap::from([(MEMORY_CATALOG_WAREHOUSE.to_string(), String::new())]),
1462 )
1463 .await
1464 .unwrap_err();
1465
1466 assert_eq!(error.kind(), ErrorKind::DataInvalid);
1467 assert_eq!(error.message(), "Catalog warehouse is required");
1468 }
1469
1470 #[tokio::test]
1471 async fn test_create_table_throws_error_if_table_with_same_name_already_exists() {
1472 let catalog = new_memory_catalog().await;
1473 let namespace_ident = NamespaceIdent::new("a".into());
1474 create_namespace(&catalog, &namespace_ident).await;
1475 let table_name = "tbl1";
1476 let table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1477 create_table(&catalog, &table_ident).await;
1478
1479 let tmp_dir = TempDir::new().unwrap();
1480 let location = tmp_dir.path().to_str().unwrap().to_string();
1481
1482 assert_eq!(
1483 catalog
1484 .create_table(
1485 &namespace_ident,
1486 TableCreation::builder()
1487 .name(table_name.into())
1488 .schema(simple_table_schema())
1489 .location(location)
1490 .build()
1491 )
1492 .await
1493 .unwrap_err()
1494 .to_string(),
1495 format!(
1496 "TableAlreadyExists => Cannot create table {:?}. Table already exists.",
1497 &table_ident
1498 )
1499 );
1500 }
1501
1502 #[tokio::test]
1503 async fn test_list_tables_returns_empty_vector() {
1504 let catalog = new_memory_catalog().await;
1505 let namespace_ident = NamespaceIdent::new("a".into());
1506 create_namespace(&catalog, &namespace_ident).await;
1507
1508 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![]);
1509 }
1510
1511 #[tokio::test]
1512 async fn test_list_tables_returns_a_single_table() {
1513 let catalog = new_memory_catalog().await;
1514 let namespace_ident = NamespaceIdent::new("n1".into());
1515 create_namespace(&catalog, &namespace_ident).await;
1516
1517 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1518 create_table(&catalog, &table_ident).await;
1519
1520 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![
1521 table_ident
1522 ]);
1523 }
1524
1525 #[tokio::test]
1526 async fn test_list_tables_returns_multiple_tables() {
1527 let catalog = new_memory_catalog().await;
1528 let namespace_ident = NamespaceIdent::new("n1".into());
1529 create_namespace(&catalog, &namespace_ident).await;
1530
1531 let table_ident_1 = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1532 let table_ident_2 = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1533 let _ = create_tables(&catalog, vec![&table_ident_1, &table_ident_2]).await;
1534
1535 assert_eq!(
1536 to_set(catalog.list_tables(&namespace_ident).await.unwrap()),
1537 to_set(vec![table_ident_1, table_ident_2])
1538 );
1539 }
1540
1541 #[tokio::test]
1542 async fn test_list_tables_returns_tables_from_correct_namespace() {
1543 let catalog = new_memory_catalog().await;
1544 let namespace_ident_1 = NamespaceIdent::new("n1".into());
1545 let namespace_ident_2 = NamespaceIdent::new("n2".into());
1546 create_namespaces(&catalog, &vec![&namespace_ident_1, &namespace_ident_2]).await;
1547
1548 let table_ident_1 = TableIdent::new(namespace_ident_1.clone(), "tbl1".into());
1549 let table_ident_2 = TableIdent::new(namespace_ident_1.clone(), "tbl2".into());
1550 let table_ident_3 = TableIdent::new(namespace_ident_2.clone(), "tbl1".into());
1551 let _ = create_tables(&catalog, vec![
1552 &table_ident_1,
1553 &table_ident_2,
1554 &table_ident_3,
1555 ])
1556 .await;
1557
1558 assert_eq!(
1559 to_set(catalog.list_tables(&namespace_ident_1).await.unwrap()),
1560 to_set(vec![table_ident_1, table_ident_2])
1561 );
1562
1563 assert_eq!(
1564 to_set(catalog.list_tables(&namespace_ident_2).await.unwrap()),
1565 to_set(vec![table_ident_3])
1566 );
1567 }
1568
1569 #[tokio::test]
1570 async fn test_list_tables_returns_table_under_nested_namespace() {
1571 let catalog = new_memory_catalog().await;
1572 let namespace_ident_a = NamespaceIdent::new("a".into());
1573 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1574 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1575
1576 let table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1577 create_table(&catalog, &table_ident).await;
1578
1579 assert_eq!(
1580 catalog.list_tables(&namespace_ident_a_b).await.unwrap(),
1581 vec![table_ident]
1582 );
1583 }
1584
1585 #[tokio::test]
1586 async fn test_list_tables_throws_error_if_namespace_doesnt_exist() {
1587 let catalog = new_memory_catalog().await;
1588
1589 let non_existent_namespace_ident = NamespaceIdent::new("n1".into());
1590
1591 assert_eq!(
1592 catalog
1593 .list_tables(&non_existent_namespace_ident)
1594 .await
1595 .unwrap_err()
1596 .to_string(),
1597 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}"),
1598 );
1599 }
1600
1601 #[tokio::test]
1602 async fn test_drop_table() {
1603 let catalog = new_memory_catalog().await;
1604 let namespace_ident = NamespaceIdent::new("n1".into());
1605 create_namespace(&catalog, &namespace_ident).await;
1606 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1607 create_table(&catalog, &table_ident).await;
1608
1609 catalog.drop_table(&table_ident).await.unwrap();
1610 }
1611
1612 #[tokio::test]
1613 async fn test_drop_table_drops_table_under_nested_namespace() {
1614 let catalog = new_memory_catalog().await;
1615 let namespace_ident_a = NamespaceIdent::new("a".into());
1616 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1617 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1618
1619 let table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1620 create_table(&catalog, &table_ident).await;
1621
1622 catalog.drop_table(&table_ident).await.unwrap();
1623
1624 assert_eq!(
1625 catalog.list_tables(&namespace_ident_a_b).await.unwrap(),
1626 vec![]
1627 );
1628 }
1629
1630 #[tokio::test]
1631 async fn test_drop_table_throws_error_if_namespace_doesnt_exist() {
1632 let catalog = new_memory_catalog().await;
1633
1634 let non_existent_namespace_ident = NamespaceIdent::new("n1".into());
1635 let non_existent_table_ident =
1636 TableIdent::new(non_existent_namespace_ident.clone(), "tbl1".into());
1637
1638 assert_eq!(
1639 catalog
1640 .drop_table(&non_existent_table_ident)
1641 .await
1642 .unwrap_err()
1643 .to_string(),
1644 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}"),
1645 );
1646 }
1647
1648 #[tokio::test]
1649 async fn test_drop_table_throws_error_if_table_doesnt_exist() {
1650 let catalog = new_memory_catalog().await;
1651 let namespace_ident = NamespaceIdent::new("n1".into());
1652 create_namespace(&catalog, &namespace_ident).await;
1653
1654 let non_existent_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1655
1656 assert_eq!(
1657 catalog
1658 .drop_table(&non_existent_table_ident)
1659 .await
1660 .unwrap_err()
1661 .to_string(),
1662 format!("TableNotFound => No such table: {non_existent_table_ident:?}"),
1663 );
1664 }
1665
1666 #[tokio::test]
1667 async fn test_table_exists_returns_true() {
1668 let catalog = new_memory_catalog().await;
1669 let namespace_ident = NamespaceIdent::new("n1".into());
1670 create_namespace(&catalog, &namespace_ident).await;
1671 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1672 create_table(&catalog, &table_ident).await;
1673
1674 assert!(catalog.table_exists(&table_ident).await.unwrap());
1675 }
1676
1677 #[tokio::test]
1678 async fn test_table_exists_returns_false() {
1679 let catalog = new_memory_catalog().await;
1680 let namespace_ident = NamespaceIdent::new("n1".into());
1681 create_namespace(&catalog, &namespace_ident).await;
1682 let non_existent_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1683
1684 assert!(
1685 !catalog
1686 .table_exists(&non_existent_table_ident)
1687 .await
1688 .unwrap()
1689 );
1690 }
1691
1692 #[tokio::test]
1693 async fn test_table_exists_under_nested_namespace() {
1694 let catalog = new_memory_catalog().await;
1695 let namespace_ident_a = NamespaceIdent::new("a".into());
1696 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1697 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1698
1699 let table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1700 create_table(&catalog, &table_ident).await;
1701
1702 assert!(catalog.table_exists(&table_ident).await.unwrap());
1703
1704 let non_existent_table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl2".into());
1705 assert!(
1706 !catalog
1707 .table_exists(&non_existent_table_ident)
1708 .await
1709 .unwrap()
1710 );
1711 }
1712
1713 #[tokio::test]
1714 async fn test_table_exists_throws_error_if_namespace_doesnt_exist() {
1715 let catalog = new_memory_catalog().await;
1716
1717 let non_existent_namespace_ident = NamespaceIdent::new("n1".into());
1718 let non_existent_table_ident =
1719 TableIdent::new(non_existent_namespace_ident.clone(), "tbl1".into());
1720
1721 assert_eq!(
1722 catalog
1723 .table_exists(&non_existent_table_ident)
1724 .await
1725 .unwrap_err()
1726 .to_string(),
1727 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}"),
1728 );
1729 }
1730
1731 #[tokio::test]
1732 async fn test_rename_table_in_same_namespace() {
1733 let catalog = new_memory_catalog().await;
1734 let namespace_ident = NamespaceIdent::new("n1".into());
1735 create_namespace(&catalog, &namespace_ident).await;
1736 let src_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1737 let dst_table_ident = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1738 create_table(&catalog, &src_table_ident).await;
1739
1740 catalog
1741 .rename_table(&src_table_ident, &dst_table_ident)
1742 .await
1743 .unwrap();
1744
1745 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![
1746 dst_table_ident
1747 ],);
1748 }
1749
1750 #[tokio::test]
1751 async fn test_rename_table_across_namespaces() {
1752 let catalog = new_memory_catalog().await;
1753 let src_namespace_ident = NamespaceIdent::new("a".into());
1754 let dst_namespace_ident = NamespaceIdent::new("b".into());
1755 create_namespaces(&catalog, &vec![&src_namespace_ident, &dst_namespace_ident]).await;
1756 let src_table_ident = TableIdent::new(src_namespace_ident.clone(), "tbl1".into());
1757 let dst_table_ident = TableIdent::new(dst_namespace_ident.clone(), "tbl2".into());
1758 create_table(&catalog, &src_table_ident).await;
1759
1760 catalog
1761 .rename_table(&src_table_ident, &dst_table_ident)
1762 .await
1763 .unwrap();
1764
1765 assert_eq!(
1766 catalog.list_tables(&src_namespace_ident).await.unwrap(),
1767 vec![],
1768 );
1769
1770 assert_eq!(
1771 catalog.list_tables(&dst_namespace_ident).await.unwrap(),
1772 vec![dst_table_ident],
1773 );
1774 }
1775
1776 #[tokio::test]
1777 async fn test_rename_table_src_table_is_same_as_dst_table() {
1778 let catalog = new_memory_catalog().await;
1779 let namespace_ident = NamespaceIdent::new("n1".into());
1780 create_namespace(&catalog, &namespace_ident).await;
1781 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl".into());
1782 create_table(&catalog, &table_ident).await;
1783
1784 catalog
1785 .rename_table(&table_ident, &table_ident)
1786 .await
1787 .unwrap();
1788
1789 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![
1790 table_ident
1791 ],);
1792 }
1793
1794 #[tokio::test]
1795 async fn test_rename_table_across_nested_namespaces() {
1796 let catalog = new_memory_catalog().await;
1797 let namespace_ident_a = NamespaceIdent::new("a".into());
1798 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1799 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
1800 create_namespaces(&catalog, &vec![
1801 &namespace_ident_a,
1802 &namespace_ident_a_b,
1803 &namespace_ident_a_b_c,
1804 ])
1805 .await;
1806
1807 let src_table_ident = TableIdent::new(namespace_ident_a_b_c.clone(), "tbl1".into());
1808 create_tables(&catalog, vec![&src_table_ident]).await;
1809
1810 let dst_table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1811 catalog
1812 .rename_table(&src_table_ident, &dst_table_ident)
1813 .await
1814 .unwrap();
1815
1816 assert!(!catalog.table_exists(&src_table_ident).await.unwrap());
1817
1818 assert!(catalog.table_exists(&dst_table_ident).await.unwrap());
1819 }
1820
1821 #[tokio::test]
1822 async fn test_rename_table_throws_error_if_src_namespace_doesnt_exist() {
1823 let catalog = new_memory_catalog().await;
1824
1825 let non_existent_src_namespace_ident = NamespaceIdent::new("n1".into());
1826 let src_table_ident =
1827 TableIdent::new(non_existent_src_namespace_ident.clone(), "tbl1".into());
1828
1829 let dst_namespace_ident = NamespaceIdent::new("n2".into());
1830 create_namespace(&catalog, &dst_namespace_ident).await;
1831 let dst_table_ident = TableIdent::new(dst_namespace_ident.clone(), "tbl1".into());
1832
1833 assert_eq!(
1834 catalog
1835 .rename_table(&src_table_ident, &dst_table_ident)
1836 .await
1837 .unwrap_err()
1838 .to_string(),
1839 format!("NamespaceNotFound => No such namespace: {non_existent_src_namespace_ident:?}"),
1840 );
1841 }
1842
1843 #[tokio::test]
1844 async fn test_rename_table_throws_error_if_dst_namespace_doesnt_exist() {
1845 let catalog = new_memory_catalog().await;
1846 let src_namespace_ident = NamespaceIdent::new("n1".into());
1847 let src_table_ident = TableIdent::new(src_namespace_ident.clone(), "tbl1".into());
1848 create_namespace(&catalog, &src_namespace_ident).await;
1849 create_table(&catalog, &src_table_ident).await;
1850
1851 let non_existent_dst_namespace_ident = NamespaceIdent::new("n2".into());
1852 let dst_table_ident =
1853 TableIdent::new(non_existent_dst_namespace_ident.clone(), "tbl1".into());
1854 assert_eq!(
1855 catalog
1856 .rename_table(&src_table_ident, &dst_table_ident)
1857 .await
1858 .unwrap_err()
1859 .to_string(),
1860 format!("NamespaceNotFound => No such namespace: {non_existent_dst_namespace_ident:?}"),
1861 );
1862 }
1863
1864 #[tokio::test]
1865 async fn test_rename_table_throws_error_if_src_table_doesnt_exist() {
1866 let catalog = new_memory_catalog().await;
1867 let namespace_ident = NamespaceIdent::new("n1".into());
1868 create_namespace(&catalog, &namespace_ident).await;
1869 let src_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1870 let dst_table_ident = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1871
1872 assert_eq!(
1873 catalog
1874 .rename_table(&src_table_ident, &dst_table_ident)
1875 .await
1876 .unwrap_err()
1877 .to_string(),
1878 format!("TableNotFound => No such table: {src_table_ident:?}"),
1879 );
1880 }
1881
1882 #[tokio::test]
1883 async fn test_rename_table_throws_error_if_dst_table_already_exists() {
1884 let catalog = new_memory_catalog().await;
1885 let namespace_ident = NamespaceIdent::new("n1".into());
1886 create_namespace(&catalog, &namespace_ident).await;
1887 let src_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1888 let dst_table_ident = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1889 create_tables(&catalog, vec![&src_table_ident, &dst_table_ident]).await;
1890
1891 assert_eq!(
1892 catalog
1893 .rename_table(&src_table_ident, &dst_table_ident)
1894 .await
1895 .unwrap_err()
1896 .to_string(),
1897 format!(
1898 "TableAlreadyExists => Cannot create table {:?}. Table already exists.",
1899 &dst_table_ident
1900 ),
1901 );
1902 }
1903
1904 #[tokio::test]
1905 async fn test_register_table() {
1906 let catalog = new_memory_catalog().await;
1908 let namespace_ident = NamespaceIdent::new("test_namespace".into());
1909 create_namespace(&catalog, &namespace_ident).await;
1910
1911 let source_table_ident = TableIdent::new(namespace_ident.clone(), "source_table".into());
1913 create_table(&catalog, &source_table_ident).await;
1914
1915 let source_table = catalog.load_table(&source_table_ident).await.unwrap();
1917 let metadata_location = source_table.metadata_location().unwrap().to_string();
1918
1919 let register_table_ident =
1921 TableIdent::new(namespace_ident.clone(), "register_table".into());
1922 let registered_table = catalog
1923 .register_table(®ister_table_ident, metadata_location.clone())
1924 .await
1925 .unwrap();
1926
1927 assert_eq!(registered_table.identifier(), ®ister_table_ident);
1929
1930 assert_eq!(
1932 registered_table.metadata_location().unwrap().to_string(),
1933 metadata_location
1934 );
1935
1936 assert!(catalog.table_exists(®ister_table_ident).await.unwrap());
1938
1939 let loaded_table = catalog.load_table(®ister_table_ident).await.unwrap();
1941 assert_eq!(loaded_table.identifier(), ®ister_table_ident);
1942 assert_eq!(
1943 loaded_table.metadata_location().unwrap().to_string(),
1944 metadata_location
1945 );
1946 }
1947
1948 #[tokio::test]
1949 async fn test_update_table() {
1950 let catalog = new_memory_catalog().await;
1951
1952 let table = create_table_with_namespace(&catalog).await;
1953
1954 assert!(!table.metadata().properties().contains_key("key"));
1956
1957 tokio::time::sleep(std::time::Duration::from_millis(2)).await;
1961
1962 let tx = Transaction::new(&table);
1964 let updated_table = tx
1965 .update_table_properties()
1966 .set("key".to_string(), "value".to_string())
1967 .apply(tx)
1968 .unwrap()
1969 .commit(&catalog)
1970 .await
1971 .unwrap();
1972
1973 assert_eq!(
1974 updated_table.metadata().properties().get("key").unwrap(),
1975 "value"
1976 );
1977
1978 assert_eq!(table.identifier(), updated_table.identifier());
1979 assert_eq!(table.metadata().uuid(), updated_table.metadata().uuid());
1980 assert_ne!(table.metadata_location(), updated_table.metadata_location());
1981
1982 assert!(
1983 table.metadata().metadata_log().len() < updated_table.metadata().metadata_log().len()
1984 );
1985 }
1986
1987 #[tokio::test]
1988 async fn test_update_table_fails_if_table_doesnt_exist() {
1989 let catalog = new_memory_catalog().await;
1990
1991 let namespace_ident = NamespaceIdent::new("a".into());
1992 create_namespace(&catalog, &namespace_ident).await;
1993
1994 let table_ident = TableIdent::new(namespace_ident, "test".to_string());
1996 let table = build_table(table_ident);
1997
1998 let tx = Transaction::new(&table);
1999 let err = tx
2000 .update_table_properties()
2001 .set("key".to_string(), "value".to_string())
2002 .apply(tx)
2003 .unwrap()
2004 .commit(&catalog)
2005 .await
2006 .unwrap_err();
2007 assert_eq!(err.kind(), ErrorKind::TableNotFound);
2008 }
2009
2010 const FIXTURE_MASTER_KEY_ID: &str = "master-1";
2013 const FIXTURE_MASTER_KEY_BYTES: [u8; 16] = [
2014 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
2015 0x0f,
2016 ];
2017
2018 fn fixture_kms_factory() -> MemoryKmsClientFactory {
2020 use crate::encryption::SensitiveBytes;
2021
2022 let factory = MemoryKmsClientFactory::new();
2023 factory
2024 .add_master_key_bytes(
2025 FIXTURE_MASTER_KEY_ID,
2026 SensitiveBytes::new(FIXTURE_MASTER_KEY_BYTES),
2027 )
2028 .unwrap();
2029 factory
2030 }
2031
2032 fn load_encrypted_fixture_metadata() -> TableMetadata {
2035 let manifest_dir = env!("CARGO_MANIFEST_DIR");
2036 let metadata_json = std::fs::read_to_string(format!(
2037 "{manifest_dir}/testdata/table_metadata/TableMetadataV3ValidEncryption.json"
2038 ))
2039 .unwrap();
2040 let mut metadata: TableMetadata = serde_json::from_str(&metadata_json).unwrap();
2041
2042 let manifest_list_path =
2043 format!("{manifest_dir}/testdata/manifests_lists/manifest-list-v3-encrypted.avro");
2044 let snapshot = metadata.snapshots.get_mut(&1).unwrap();
2045 let mut patched = snapshot.as_ref().clone();
2046 patched.manifest_list = manifest_list_path;
2047 *snapshot = Arc::new(patched);
2048
2049 metadata
2050 }
2051
2052 #[tokio::test]
2053 async fn catalog_kms_factory_client_reaches_table_encryption_manager() {
2054 let warehouse = temp_path();
2055 let catalog = MemoryCatalogBuilder::default()
2056 .with_storage_factory(Arc::new(LocalFsStorageFactory))
2057 .with_kms_client_factory(Arc::new(fixture_kms_factory()))
2058 .load(
2059 "memory",
2060 HashMap::from([(MEMORY_CATALOG_WAREHOUSE.to_string(), warehouse)]),
2061 )
2062 .await
2063 .unwrap();
2064
2065 let namespace_ident = NamespaceIdent::new("enc_ns".into());
2066 create_namespace(&catalog, &namespace_ident).await;
2067
2068 let metadata = load_encrypted_fixture_metadata();
2069 let metadata_dir = TempDir::new().unwrap();
2070 let metadata_location =
2071 format!("{}/v1.metadata.json", metadata_dir.path().to_str().unwrap());
2072 std::fs::write(&metadata_location, serde_json::to_vec(&metadata).unwrap()).unwrap();
2073
2074 let table_ident = TableIdent::new(namespace_ident, "enc".to_string());
2075 catalog
2076 .register_table(&table_ident, metadata_location)
2077 .await
2078 .unwrap();
2079
2080 let table = catalog.load_table(&table_ident).await.unwrap();
2081 assert!(
2082 table.encryption_manager().is_some(),
2083 "factory-built KMS client should have reached the table's EncryptionManager"
2084 );
2085
2086 let snapshot_ref = table.metadata().current_snapshot().unwrap();
2087 let manifest_list = table
2088 .object_cache()
2089 .get_manifest_list(snapshot_ref, &table.metadata_ref())
2090 .await
2091 .unwrap();
2092 assert_eq!(manifest_list.entries().len(), 0);
2093 }
2094
2095 fn build_table(ident: TableIdent) -> Table {
2096 let file_io = FileIO::new_with_fs();
2097
2098 let temp_dir = TempDir::new().unwrap();
2099 let location = temp_dir.path().to_str().unwrap().to_string();
2100
2101 let table_creation = TableCreation::builder()
2102 .name(ident.name().to_string())
2103 .schema(simple_table_schema())
2104 .location(location)
2105 .build();
2106 let metadata = TableMetadataBuilder::from_table_creation(table_creation)
2107 .unwrap()
2108 .build()
2109 .unwrap()
2110 .metadata;
2111
2112 Table::builder()
2113 .identifier(ident)
2114 .metadata(metadata)
2115 .file_io(file_io)
2116 .runtime(test_runtime())
2117 .build()
2118 .unwrap()
2119 }
2120}