tangle


git clone https://radroots.dev/git/tangle.git
Log | Files | Refs | README | LICENSE

commit f9d51012926547c75e098720207d9d768153936e
parent fd03907dd39b70160fbf1797512a3d5ae00ee465
Author: triesap <tyson@radroots.org>
Date:   Sat,  6 Jun 2026 17:15:35 -0700

tests: cover benchmark edge paths

- make deterministic benchmark datasets infallible
- add duplicate and ineligible workload coverage
- exercise query plan error and checksum helpers
- record remaining benchmark coverage gaps for closure

Diffstat:
Mcrates/tangle_bench/src/lib.rs | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 127 insertions(+), 17 deletions(-)

diff --git a/crates/tangle_bench/src/lib.rs b/crates/tangle_bench/src/lib.rs @@ -32,16 +32,16 @@ pub struct BenchDataset { } impl BenchDataset { - pub fn generate(config: BenchDatasetConfig) -> Result<Self, String> { + pub fn generate(config: BenchDatasetConfig) -> Self { let mut listings = Vec::with_capacity(config.listing_count); for index in 0..config.listing_count { - listings.push(bench_listing(index)?); + listings.push(bench_listing(index)); } let mut notes = Vec::with_capacity(config.note_count); for index in 0..config.note_count { - notes.push(bench_note(index)?); + notes.push(bench_note(index)); } - Ok(Self { listings, notes }) + Self { listings, notes } } pub fn listings(&self) -> &[Event] { @@ -257,7 +257,7 @@ pub struct IngestBenchmarkReport { pub async fn run_ingest_benchmark( config: BenchDatasetConfig, ) -> Result<IngestBenchmarkReport, String> { - let dataset = BenchDataset::generate(config)?; + let dataset = BenchDataset::generate(config); let started = Instant::now(); let report = run_generic_relay_workload(&dataset).await?; Ok(IngestBenchmarkReport { @@ -277,7 +277,7 @@ pub struct ListingQueryBenchmarkReport { pub async fn run_listing_query_benchmark( config: BenchDatasetConfig, ) -> Result<ListingQueryBenchmarkReport, String> { - let dataset = BenchDataset::generate(config)?; + let dataset = BenchDataset::generate(config); let materialized = materialize_listing_workload(&dataset).await?; let started = Instant::now(); let listing_rows = materialized @@ -314,7 +314,7 @@ pub struct SearchBenchmarkReport { pub async fn run_search_benchmark( config: BenchDatasetConfig, ) -> Result<SearchBenchmarkReport, String> { - let dataset = BenchDataset::generate(config)?; + let dataset = BenchDataset::generate(config); let materialized = materialize_listing_workload(&dataset).await?; let store = materialized.store(); let mut indexed = 0; @@ -368,7 +368,7 @@ pub struct QueryPlanCaptureReport { pub async fn capture_query_plans( config: BenchDatasetConfig, ) -> Result<QueryPlanCaptureReport, String> { - let dataset = BenchDataset::generate(config)?; + let dataset = BenchDataset::generate(config); let materialized = materialize_listing_workload(&dataset).await?; for event in dataset.listings() { materialized @@ -402,7 +402,7 @@ pub struct RebuildBenchmarkReport { pub async fn run_rebuild_benchmark( config: BenchDatasetConfig, ) -> Result<RebuildBenchmarkReport, String> { - let dataset = BenchDataset::generate(config)?; + let dataset = BenchDataset::generate(config); let materialized = materialize_listing_workload(&dataset).await?; clear_projection_tables(materialized.store()).await?; let started = Instant::now(); @@ -475,7 +475,7 @@ pub struct RestoreDrillSmokeReport { pub async fn run_restore_drill_smoke( config: BenchDatasetConfig, ) -> Result<RestoreDrillSmokeReport, String> { - let dataset = BenchDataset::generate(config)?; + let dataset = BenchDataset::generate(config); let source = materialize_listing_workload(&dataset).await?; let source_rows = source .store() @@ -623,7 +623,7 @@ async fn bench_memory_store(database: &str) -> Result<SurrealStore, String> { Ok(store) } -fn bench_listing(index: usize) -> Result<Event, String> { +fn bench_listing(index: usize) -> Event { let created_at = 1_714_200_000 + index as u64; let price_major = 10 + (index % 50); let price_minor = (index * 7) % 100; @@ -652,9 +652,10 @@ fn bench_listing(index: usize) -> Result<Event, String> { ], &content, ) + .expect("deterministic benchmark listing fixture builds") } -fn bench_note(index: usize) -> Result<Event, String> { +fn bench_note(index: usize) -> Event { build_fixture_event_from_parts( FixtureKey::Buyer, 1_714_300_000 + index as u64, @@ -662,6 +663,7 @@ fn bench_note(index: usize) -> Result<Event, String> { vec![vec!["t".to_owned(), "bench".to_owned()]], &format!("Deterministic generic relay note {index:04}"), ) + .expect("deterministic benchmark note fixture builds") } fn bench_category(index: usize) -> &'static str { @@ -686,11 +688,12 @@ mod tests { use super::{BenchDataset, BenchDatasetConfig}; use std::collections::BTreeSet; use tangle_nips::{ListingProjectionEvaluation, evaluate_listing_projection}; + use tangle_test_support::{build_fixture_event, projection_ineligible_listing_spec}; #[test] fn deterministic_dataset_generator_produces_stable_signed_events() { - let first = BenchDataset::generate(BenchDatasetConfig::new(4, 2)).expect("first"); - let second = BenchDataset::generate(BenchDatasetConfig::new(4, 2)).expect("second"); + let first = BenchDataset::generate(BenchDatasetConfig::new(4, 2)); + let second = BenchDataset::generate(BenchDatasetConfig::new(4, 2)); let listing_ids = first .listings() .iter() @@ -730,9 +733,22 @@ mod tests { ); } + #[test] + fn deterministic_dataset_generator_handles_empty_edges() { + let empty = BenchDataset::generate(BenchDatasetConfig::new(0, 0)); + let listings_only = BenchDataset::generate(BenchDatasetConfig::new(2, 0)); + let notes_only = BenchDataset::generate(BenchDatasetConfig::new(0, 3)); + + assert!(empty.events().is_empty()); + assert_eq!(listings_only.events().len(), 2); + assert_eq!(notes_only.events().len(), 3); + assert!(listings_only.notes().is_empty()); + assert!(notes_only.listings().is_empty()); + } + #[tokio::test] async fn listing_workload_materializes_projected_listing_rows() { - let dataset = BenchDataset::generate(BenchDatasetConfig::new(8, 3)).expect("dataset"); + let dataset = BenchDataset::generate(BenchDatasetConfig::new(8, 3)); let materialized = super::materialize_listing_workload(&dataset) .await .expect("listing workload"); @@ -763,8 +779,32 @@ mod tests { } #[tokio::test] + async fn listing_workload_counts_duplicates_and_ineligible_events() { + let listing = super::bench_listing(0); + let ineligible = + build_fixture_event(&projection_ineligible_listing_spec()).expect("ineligible listing"); + let dataset = BenchDataset { + listings: vec![listing.clone(), listing, ineligible], + notes: Vec::new(), + }; + let materialized = super::materialize_listing_workload(&dataset) + .await + .expect("listing workload"); + + assert_eq!( + materialized.report(), + super::ListingWorkloadReport { + attempted: 3, + inserted: 2, + projected: 2, + listing_rows: 1 + } + ); + } + + #[tokio::test] async fn search_workload_indexes_and_queries_listing_documents() { - let dataset = BenchDataset::generate(BenchDatasetConfig::new(12, 2)).expect("dataset"); + let dataset = BenchDataset::generate(BenchDatasetConfig::new(12, 2)); let report = super::run_search_workload(&dataset) .await .expect("search workload"); @@ -780,8 +820,31 @@ mod tests { } #[tokio::test] + async fn search_workload_ignores_ineligible_listing_documents() { + let listing = super::bench_listing(0); + let ineligible = + build_fixture_event(&projection_ineligible_listing_spec()).expect("ineligible listing"); + let dataset = BenchDataset { + listings: vec![listing, ineligible], + notes: Vec::new(), + }; + let report = super::run_search_workload(&dataset) + .await + .expect("search workload"); + + assert_eq!( + report, + super::SearchWorkloadReport { + indexed: 1, + carrot_results: 1, + browse_results: 1 + } + ); + } + + #[tokio::test] async fn generic_relay_workload_stores_and_queries_non_marketplace_events() { - let dataset = BenchDataset::generate(BenchDatasetConfig::new(5, 7)).expect("dataset"); + let dataset = BenchDataset::generate(BenchDatasetConfig::new(5, 7)); let report = super::run_generic_relay_workload(&dataset) .await .expect("generic workload"); @@ -798,6 +861,29 @@ mod tests { } #[tokio::test] + async fn generic_relay_workload_counts_duplicate_raw_events() { + let listing = super::bench_listing(0); + let note = super::bench_note(0); + let dataset = BenchDataset { + listings: vec![listing.clone(), listing], + notes: vec![note.clone(), note], + }; + let report = super::run_generic_relay_workload(&dataset) + .await + .expect("generic workload"); + + assert_eq!( + report, + super::GenericRelayWorkloadReport { + attempted: 4, + inserted: 2, + note_results: 1, + all_results: 2 + } + ); + } + + #[tokio::test] async fn ingest_benchmark_reports_deterministic_event_counts() { let report = super::run_ingest_benchmark(BenchDatasetConfig::new(6, 4)) .await @@ -844,6 +930,16 @@ mod tests { } #[tokio::test] + async fn query_plan_capture_reports_invalid_query_errors() { + let store = super::bench_memory_store("invalid_query_plan") + .await + .expect("store"); + let error = super::explain_query(&store, "SELECT * FROM").await; + + assert!(error.expect_err("query error").len() > 0); + } + + #[tokio::test] async fn rebuild_benchmark_replays_raw_events_into_projection_rows() { let first = super::run_rebuild_benchmark(BenchDatasetConfig::new(7, 0)) .await @@ -871,4 +967,18 @@ mod tests { assert_eq!(report.source_checksum, report.restored_checksum); assert!(report.checksum_matches); } + + #[test] + fn checksum_helpers_handle_empty_and_missing_fields() { + let empty = super::listing_rows_checksum(&[]); + let sparse = super::listing_rows_checksum(&[ + serde_json::json!({"listing_key": "b"}), + serde_json::json!({"event_id": "a"}), + ]); + + assert_eq!(empty.len(), 64); + assert_eq!(sparse.len(), 64); + assert_ne!(empty, sparse); + assert_eq!(super::lower_hex(&[0, 15, 16, 255]), "000f10ff"); + } }