Skip to content

Commit 8c4f360

Browse files
committed
tests
Signed-off-by: Onur Satici <onur@spiraldb.com>
1 parent 6991c01 commit 8c4f360

1 file changed

Lines changed: 156 additions & 0 deletions

File tree

vortex-file/src/tests.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,3 +1984,159 @@ async fn test_segment_ordering_zonemaps_after_data() -> VortexResult<()> {
19841984

19851985
Ok(())
19861986
}
1987+
1988+
#[tokio::test]
1989+
#[cfg_attr(miri, ignore)]
1990+
async fn test_segment_ordering_array_trees_consolidated_and_after_data() -> VortexResult<()> {
1991+
// Multi-column struct with enough rows to produce chunked data, so each column will have
1992+
// many ArrayTreeFlat leaves. The collector should consolidate their compact trees into a
1993+
// single segment per ArrayTreeLayout.
1994+
let n = 100_000;
1995+
let values: Vec<&str> = (0..n).map(|i| ["alpha", "beta", "gamma"][i % 3]).collect();
1996+
let strings = VarBinArray::from(values).into_array();
1997+
let numbers = PrimitiveArray::from_iter(0..n as i32).into_array();
1998+
let floats = PrimitiveArray::from_iter((0..n).map(|i| i as f64 * 0.1)).into_array();
1999+
2000+
let st = StructArray::from_fields(&[
2001+
("strings", strings),
2002+
("numbers", numbers),
2003+
("floats", floats),
2004+
])
2005+
.unwrap();
2006+
2007+
let mut buf = ByteBufferMut::empty();
2008+
let summary = SESSION
2009+
.write_options()
2010+
.write(&mut buf, st.into_array().to_array_stream())
2011+
.await?;
2012+
2013+
let footer = summary.footer();
2014+
let segment_specs = footer.segment_map();
2015+
let root = footer.layout();
2016+
2017+
// Walk the layout tree and validate every ArrayTreeLayout we find.
2018+
//
2019+
// For each ArrayTreeLayout we assert two invariants:
2020+
// 1. **Consolidation:** the auxiliary `array_trees` child (child idx 1) writes exactly
2021+
// one segment — all compact flatbuffers from the leaves should land in a single
2022+
// contiguous payload, not be scattered across the file.
2023+
// 2. **Per-column ordering:** every data segment under child 0 appears before the
2024+
// array_trees segment under child 1.
2025+
fn check_array_tree_layouts(
2026+
layout: &dyn Layout,
2027+
segment_specs: &[SegmentSpec],
2028+
found_any: &mut bool,
2029+
) {
2030+
if layout.encoding_id().as_ref() == "vortex.array_tree" {
2031+
*found_any = true;
2032+
2033+
let data_child = layout.child(0).unwrap();
2034+
let array_trees_child = layout.child(1).unwrap();
2035+
2036+
let data_offsets = collect_segment_offsets(data_child.as_ref(), segment_specs);
2037+
let array_trees_offsets =
2038+
collect_segment_offsets(array_trees_child.as_ref(), segment_specs);
2039+
2040+
assert_eq!(
2041+
array_trees_offsets.len(),
2042+
1,
2043+
"array_tree: auxiliary child must consolidate to exactly 1 segment, got {} segments at offsets {:?}",
2044+
array_trees_offsets.len(),
2045+
array_trees_offsets,
2046+
);
2047+
2048+
assert!(
2049+
!data_offsets.is_empty(),
2050+
"array_tree: data child must have at least one segment"
2051+
);
2052+
2053+
assert_offsets_ordered(
2054+
&data_offsets,
2055+
&array_trees_offsets,
2056+
"array_tree: all data segments should come before the array_trees segment",
2057+
);
2058+
}
2059+
2060+
for child in layout.children().unwrap() {
2061+
check_array_tree_layouts(child.as_ref(), segment_specs, found_any);
2062+
}
2063+
}
2064+
2065+
let mut found_any = false;
2066+
check_array_tree_layouts(root.as_ref(), segment_specs, &mut found_any);
2067+
assert!(
2068+
found_any,
2069+
"test setup expected the default write strategy to produce at least one ArrayTreeLayout"
2070+
);
2071+
2072+
Ok(())
2073+
}
2074+
2075+
#[tokio::test]
2076+
#[cfg_attr(miri, ignore)]
2077+
async fn test_segment_ordering_array_trees_before_zones() -> VortexResult<()> {
2078+
// The default write strategy wraps every column in `ZonedStrategy { data: ArrayTree, zones }`.
2079+
// We assert per-Zoned-layout that the array_trees segment (sitting inside the data child)
2080+
// appears before every zone-map segment in the same column.
2081+
let n = 100_000;
2082+
let values: Vec<&str> = (0..n).map(|i| ["alpha", "beta", "gamma"][i % 3]).collect();
2083+
let strings = VarBinArray::from(values).into_array();
2084+
let numbers = PrimitiveArray::from_iter(0..n as i32).into_array();
2085+
let floats = PrimitiveArray::from_iter((0..n).map(|i| i as f64 * 0.1)).into_array();
2086+
2087+
let st = StructArray::from_fields(&[
2088+
("strings", strings),
2089+
("numbers", numbers),
2090+
("floats", floats),
2091+
])
2092+
.unwrap();
2093+
2094+
let mut buf = ByteBufferMut::empty();
2095+
let summary = SESSION
2096+
.write_options()
2097+
.write(&mut buf, st.into_array().to_array_stream())
2098+
.await?;
2099+
2100+
let footer = summary.footer();
2101+
let segment_specs = footer.segment_map();
2102+
let root = footer.layout();
2103+
2104+
fn check_zoned_with_array_tree(
2105+
layout: &dyn Layout,
2106+
segment_specs: &[SegmentSpec],
2107+
found_any: &mut bool,
2108+
) {
2109+
if layout.encoding_id().as_ref() == "vortex.stats" {
2110+
let data_child = layout.child(0).unwrap();
2111+
let zones_child = layout.child(1).unwrap();
2112+
2113+
if data_child.encoding_id().as_ref() == "vortex.array_tree" {
2114+
*found_any = true;
2115+
let array_trees_offsets = collect_segment_offsets(
2116+
data_child.child(1).unwrap().as_ref(),
2117+
segment_specs,
2118+
);
2119+
let zones_offsets = collect_segment_offsets(zones_child.as_ref(), segment_specs);
2120+
2121+
assert_offsets_ordered(
2122+
&array_trees_offsets,
2123+
&zones_offsets,
2124+
"zoned wrapping array_tree: the array_trees segment should come before zone-map segments",
2125+
);
2126+
}
2127+
}
2128+
2129+
for child in layout.children().unwrap() {
2130+
check_zoned_with_array_tree(child.as_ref(), segment_specs, found_any);
2131+
}
2132+
}
2133+
2134+
let mut found_any = false;
2135+
check_zoned_with_array_tree(root.as_ref(), segment_specs, &mut found_any);
2136+
assert!(
2137+
found_any,
2138+
"test setup expected the default write strategy to produce at least one Zoned wrapping an ArrayTree"
2139+
);
2140+
2141+
Ok(())
2142+
}

0 commit comments

Comments
 (0)