1use std::sync::{Arc, OnceLock};
23
24use arrow_array::RecordBatch;
25use expect_test::Expect;
26use itertools::Itertools;
27
28use crate::TableIdent;
29use crate::encryption::SensitiveBytes;
30use crate::encryption::kms::{KeyManagementClient, MemoryKeyManagementClient};
31use crate::io::FileIO;
32use crate::runtime::Runtime;
33use crate::spec::TableMetadata;
34use crate::table::Table;
35
36pub fn test_runtime() -> Runtime {
44 static TOKIO_RT: OnceLock<tokio::runtime::Runtime> = OnceLock::new();
45 let tokio_rt = TOKIO_RT.get_or_init(|| {
46 tokio::runtime::Builder::new_multi_thread()
47 .enable_all()
48 .build()
49 .expect("failed to build test tokio runtime")
50 });
51 Runtime::new(tokio_rt)
52}
53
54pub fn check_record_batches(
63 record_batches: Vec<RecordBatch>,
64 expected_schema: Expect,
65 expected_data: Expect,
66 ignore_check_columns: &[&str],
67 sort_column: Option<&str>,
68) {
69 assert!(!record_batches.is_empty(), "Empty record batches");
70
71 let first_batch = record_batches.first().unwrap();
73 let record_batch =
74 arrow_select::concat::concat_batches(&first_batch.schema(), &record_batches).unwrap();
75
76 let mut columns = record_batch.columns().to_vec();
77 if let Some(sort_column) = sort_column {
78 let column = record_batch.column_by_name(sort_column).unwrap();
79 let indices = arrow_ord::sort::sort_to_indices(column, None, None).unwrap();
80 columns = columns
81 .iter()
82 .map(|column| arrow_select::take::take(column.as_ref(), &indices, None).unwrap())
83 .collect_vec();
84 }
85
86 expected_schema.assert_eq(&format!(
87 "{}",
88 record_batch.schema().fields().iter().format(",\n")
89 ));
90 expected_data.assert_eq(&format!(
91 "{}",
92 record_batch
93 .schema()
94 .fields()
95 .iter()
96 .zip_eq(columns)
97 .map(|(field, column)| {
98 if ignore_check_columns.contains(&field.name().as_str()) {
99 format!("{}: (skipped)", field.name())
100 } else {
101 format!("{}: {:?}", field.name(), column)
102 }
103 })
104 .format(",\n")
105 ));
106}
107
108pub async fn make_encrypted_table() -> Table {
116 let metadata_json = std::fs::read_to_string(format!(
117 "{}/testdata/table_metadata/TableMetadataV3ValidEncryption.json",
118 env!("CARGO_MANIFEST_DIR"),
119 ))
120 .unwrap();
121 let metadata: TableMetadata = serde_json::from_str(&metadata_json).unwrap();
122
123 let kms: Arc<dyn KeyManagementClient> = {
124 let k = MemoryKeyManagementClient::new();
125 k.add_master_key_bytes(
126 "master-1",
127 SensitiveBytes::new([
128 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
129 0x0e, 0x0f,
130 ]),
131 )
132 .unwrap();
133 Arc::new(k)
134 };
135
136 let file_io = FileIO::new_with_memory();
137
138 let manifest_list_bytes = std::fs::read(format!(
140 "{}/testdata/manifests_lists/manifest-list-v3-encrypted.avro",
141 env!("CARGO_MANIFEST_DIR"),
142 ))
143 .unwrap();
144 file_io
145 .new_output(metadata.current_snapshot().unwrap().manifest_list())
146 .unwrap()
147 .write(manifest_list_bytes.into())
148 .await
149 .unwrap();
150
151 Table::builder()
152 .metadata(metadata)
153 .metadata_location("memory:///table/metadata/v1.json")
154 .identifier(TableIdent::from_strs(["ns1", "test1"]).unwrap())
155 .file_io(file_io)
156 .kms_client(kms)
157 .runtime(test_runtime())
158 .build()
159 .unwrap()
160}