diff --git a/crates/re_query_cache/tests/latest_at.rs b/crates/re_query_cache/tests/latest_at.rs index b090249349e6..4181d30cdd91 100644 --- a/crates/re_query_cache/tests/latest_at.rs +++ b/crates/re_query_cache/tests/latest_at.rs @@ -5,7 +5,7 @@ use itertools::Itertools as _; use re_data_store::{DataStore, LatestAtQuery}; -use re_log_types::{build_frame_nr, DataRow, EntityPath, RowId}; +use re_log_types::{build_frame_nr, DataRow, EntityPath, RowId, TimePoint}; use re_query_cache::query_archetype_pov1_comp1; use re_types::{ archetypes::Points2D, @@ -159,79 +159,170 @@ fn splatted_query() { } #[test] -// TODO(cmc): implement invalidation + in-depth invalidation tests + in-depth OOO tests -#[should_panic(expected = "assertion failed: `(left == right)`")] fn invalidation() { - let mut store = DataStore::new( - re_log_types::StoreId::random(re_log_types::StoreKind::Recording), - InstanceKey::name(), - Default::default(), - ); - let ent_path = "point"; - let timepoint = [build_frame_nr(123.into())]; - // Create some positions with implicit instances - let positions = vec![Position2D::new(1.0, 2.0), Position2D::new(3.0, 4.0)]; - let row = DataRow::from_cells1_sized(RowId::new(), ent_path, timepoint, 2, positions).unwrap(); - store.insert_row(&row).unwrap(); + let test_invalidation = |query: LatestAtQuery, + present_data_timepoint: TimePoint, + past_data_timepoint: TimePoint, + future_data_timepoint: TimePoint| { + let mut store = DataStore::new( + re_log_types::StoreId::random(re_log_types::StoreKind::Recording), + InstanceKey::name(), + Default::default(), + ); + + // Create some positions with implicit instances + let positions = vec![Position2D::new(1.0, 2.0), Position2D::new(3.0, 4.0)]; + let row = DataRow::from_cells1_sized( + RowId::new(), + ent_path, + present_data_timepoint.clone(), + 2, + positions, + ) + .unwrap(); + store.insert_row(&row).unwrap(); - // Assign one of them a color with an explicit instance - let color_instances = vec![InstanceKey(1)]; - let colors = vec![Color::from_rgb(255, 0, 0)]; - let row = DataRow::from_cells2_sized( - RowId::new(), - ent_path, - timepoint, - 1, - (color_instances, colors), - ) - .unwrap(); - store.insert_row(&row).unwrap(); + // Assign one of them a color with an explicit instance + let color_instances = vec![InstanceKey(1)]; + let colors = vec![Color::from_rgb(1, 2, 3)]; + let row = DataRow::from_cells2_sized( + RowId::new(), + ent_path, + present_data_timepoint.clone(), + 1, + (color_instances, colors), + ) + .unwrap(); + store.insert_row(&row).unwrap(); - let query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - query_and_compare(&store, &query, &ent_path.into()); + query_and_compare(&store, &query, &ent_path.into()); - // Invalidate the PoV component - let positions = vec![Position2D::new(10.0, 20.0), Position2D::new(30.0, 40.0)]; - let row = DataRow::from_cells1_sized(RowId::new(), ent_path, timepoint, 2, positions).unwrap(); - store.insert_row(&row).unwrap(); + // --- Modify present --- - let query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - query_and_compare(&store, &query, &ent_path.into()); + // Modify the PoV component + let positions = vec![Position2D::new(10.0, 20.0), Position2D::new(30.0, 40.0)]; + let row = DataRow::from_cells1_sized( + RowId::new(), + ent_path, + present_data_timepoint.clone(), + 2, + positions, + ) + .unwrap(); + store.insert_row(&row).unwrap(); - // Invalidate the optional component - let colors = vec![Color::from_rgb(255, 0, 0), Color::from_rgb(0, 255, 0)]; - let row = DataRow::from_cells1_sized(RowId::new(), ent_path, timepoint, 2, colors).unwrap(); - store.insert_row(&row).unwrap(); + query_and_compare(&store, &query, &ent_path.into()); - let query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - query_and_compare(&store, &query, &ent_path.into()); + // Modify the optional component + let colors = vec![Color::from_rgb(4, 5, 6), Color::from_rgb(7, 8, 9)]; + let row = + DataRow::from_cells1_sized(RowId::new(), ent_path, present_data_timepoint, 2, colors) + .unwrap(); + store.insert_row(&row).unwrap(); + + query_and_compare(&store, &query, &ent_path.into()); + + // --- Modify past --- + + // Modify the PoV component + let positions = vec![Position2D::new(100.0, 200.0), Position2D::new(300.0, 400.0)]; + let row = DataRow::from_cells1_sized( + RowId::new(), + ent_path, + past_data_timepoint.clone(), + 2, + positions, + ) + .unwrap(); + store.insert_row(&row).unwrap(); + + query_and_compare(&store, &query, &ent_path.into()); + + // Modify the optional component + let colors = vec![Color::from_rgb(10, 11, 12), Color::from_rgb(13, 14, 15)]; + let row = + DataRow::from_cells1_sized(RowId::new(), ent_path, past_data_timepoint, 2, colors) + .unwrap(); + store.insert_row(&row).unwrap(); + + query_and_compare(&store, &query, &ent_path.into()); + + // --- Modify future --- + + // Modify the PoV component + let positions = vec![ + Position2D::new(1000.0, 2000.0), + Position2D::new(3000.0, 4000.0), + ]; + let row = DataRow::from_cells1_sized( + RowId::new(), + ent_path, + future_data_timepoint.clone(), + 2, + positions, + ) + .unwrap(); + store.insert_row(&row).unwrap(); + + query_and_compare(&store, &query, &ent_path.into()); + + // Modify the optional component + let colors = vec![Color::from_rgb(16, 17, 18)]; + let row = + DataRow::from_cells1_sized(RowId::new(), ent_path, future_data_timepoint, 1, colors) + .unwrap(); + store.insert_row(&row).unwrap(); + + query_and_compare(&store, &query, &ent_path.into()); + }; + + let timeless = TimePoint::timeless(); + let frame_122 = build_frame_nr(123.into()); + let frame_123 = build_frame_nr(123.into()); + let frame_124 = build_frame_nr(123.into()); + + test_invalidation( + LatestAtQuery { + timeline: frame_123.0, + at: frame_123.1, + }, + [frame_123].into(), + [frame_122].into(), + [frame_124].into(), + ); + + test_invalidation( + LatestAtQuery { + timeline: frame_123.0, + at: frame_123.1, + }, + [frame_123].into(), + timeless, + [frame_124].into(), + ); } // Test the following scenario: // ```py -// rr.set_time(0) -// rr.log("points", rr.Points3D([1, 2, 3])) +// rr.log("points", rr.Points3D([1, 2, 3]), timeless=True) // // # Do first query here: LatestAt(+inf) // # Expected: points=[[1,2,3]] colors=[] // -// rr.set_time(1) +// rr.set_time(2) // rr.log_components("points", rr.components.Color(0xFF0000)) // // # Do second query here: LatestAt(+inf) // # Expected: points=[[1,2,3]] colors=[0xFF0000] // -// rr.set_time(2) +// rr.set_time(3) // rr.log_components("points", rr.components.Color(0x0000FF)) // // # Do third query here: LatestAt(+inf) // # Expected: points=[[1,2,3]] colors=[0x0000FF] // ``` -// -// TODO(cmc): this needs proper invalidation to pass -#[should_panic(expected = "assertion failed: `(left == right)`")] #[test] fn invalidation_of_future_optionals() { let mut store = DataStore::new( @@ -242,14 +333,14 @@ fn invalidation_of_future_optionals() { let ent_path = "points"; - let frame1 = [build_frame_nr(1.into())]; + let timeless = TimePoint::timeless(); let frame2 = [build_frame_nr(2.into())]; let frame3 = [build_frame_nr(3.into())]; let query_time = [build_frame_nr(9999.into())]; let positions = vec![Position2D::new(1.0, 2.0), Position2D::new(3.0, 4.0)]; - let row = DataRow::from_cells1_sized(RowId::new(), ent_path, frame1, 2, positions).unwrap(); + let row = DataRow::from_cells1_sized(RowId::new(), ent_path, timeless, 2, positions).unwrap(); store.insert_row(&row).unwrap(); let query = re_data_store::LatestAtQuery::new(query_time[0].0, query_time[0].1); @@ -280,25 +371,44 @@ fn invalidation_of_future_optionals() { fn query_and_compare(store: &DataStore, query: &LatestAtQuery, ent_path: &EntityPath) { for _ in 0..3 { - let mut got_instance_keys = Vec::new(); - let mut got_positions = Vec::new(); - let mut got_colors = Vec::new(); + let mut uncached_data_time = None; + let mut uncached_instance_keys = Vec::new(); + let mut uncached_positions = Vec::new(); + let mut uncached_colors = Vec::new(); + query_archetype_pov1_comp1::( + false, // cached? + store, + &query.clone().into(), + ent_path, + |((data_time, _), instance_keys, positions, colors)| { + uncached_data_time = data_time; + uncached_instance_keys.extend(instance_keys.iter().copied()); + uncached_positions.extend(positions.iter().copied()); + uncached_colors.extend(colors.iter().copied()); + }, + ) + .unwrap(); + let mut cached_data_time = None; + let mut cached_instance_keys = Vec::new(); + let mut cached_positions = Vec::new(); + let mut cached_colors = Vec::new(); query_archetype_pov1_comp1::( true, // cached? store, &query.clone().into(), ent_path, - |(_, instance_keys, positions, colors)| { - got_instance_keys.extend(instance_keys.iter().copied()); - got_positions.extend(positions.iter().copied()); - got_colors.extend(colors.iter().copied()); + |((data_time, _), instance_keys, positions, colors)| { + cached_data_time = data_time; + cached_instance_keys.extend(instance_keys.iter().copied()); + cached_positions.extend(positions.iter().copied()); + cached_colors.extend(colors.iter().copied()); }, ) .unwrap(); - let (_, expected) = re_query::query_archetype::(store, query, ent_path).unwrap(); - + let (expected_data_time, expected) = + re_query::query_archetype::(store, query, ent_path).unwrap(); let expected_instance_keys = expected.iter_instance_keys().collect_vec(); let expected_positions = expected .iter_required_component::() @@ -309,8 +419,17 @@ fn query_and_compare(store: &DataStore, query: &LatestAtQuery, ent_path: &Entity .unwrap() .collect_vec(); - similar_asserts::assert_eq!(expected_instance_keys, got_instance_keys); - similar_asserts::assert_eq!(expected_positions, got_positions); - similar_asserts::assert_eq!(expected_colors, got_colors); + // Keep this around for the next unlucky chap. + // eprintln!("(expected={expected_data_time:?}, uncached={uncached_data_time:?}, cached={cached_data_time:?})"); + + similar_asserts::assert_eq!(expected_data_time, uncached_data_time); + similar_asserts::assert_eq!(expected_instance_keys, uncached_instance_keys); + similar_asserts::assert_eq!(expected_positions, uncached_positions); + similar_asserts::assert_eq!(expected_colors, uncached_colors); + + similar_asserts::assert_eq!(expected_data_time, cached_data_time); + similar_asserts::assert_eq!(expected_instance_keys, cached_instance_keys); + similar_asserts::assert_eq!(expected_positions, cached_positions); + similar_asserts::assert_eq!(expected_colors, cached_colors); } }