Files
wifi-densepose/vendor/ruvector/examples/vibecast-7sense/tests/integration/mod.rs

220 lines
7.0 KiB
Rust

//! Integration tests for 7sense bioacoustics platform
//!
//! This module organizes integration tests across all six bounded contexts:
//! - Audio Ingestion Context
//! - Embedding Context
//! - Vector Space Context
//! - Learning Context (via Analysis)
//! - Analysis Context
//! - Interpretation Context
//!
//! Tests are organized by context and follow the domain-driven design boundaries.
//!
//! Note: Individual test files (audio_test.rs, etc.) are compiled as separate
//! test binaries via [[test]] entries in Cargo.toml.
// Re-export commonly used test utilities
pub use crate::fixtures::*;
pub use crate::mocks::*;
/// Common test configuration
#[derive(Debug, Clone)]
pub struct TestConfig {
/// Sample rate for audio (32kHz for Perch 2.0)
pub sample_rate: u32,
/// Embedding dimensions (1536 for Perch 2.0)
pub embedding_dims: usize,
/// Default segment duration in ms
pub segment_duration_ms: u64,
/// HNSW M parameter
pub hnsw_m: usize,
/// HNSW ef_construction
pub hnsw_ef_construction: usize,
/// HNSW ef_search
pub hnsw_ef_search: usize,
/// Minimum cluster size for HDBSCAN
pub min_cluster_size: usize,
/// Target recall@10 for vector search
pub target_recall_at_10: f32,
}
impl Default for TestConfig {
fn default() -> Self {
Self {
sample_rate: 32000,
embedding_dims: 1536,
segment_duration_ms: 5000,
hnsw_m: 16,
hnsw_ef_construction: 200,
hnsw_ef_search: 100,
min_cluster_size: 5,
target_recall_at_10: 0.95,
}
}
}
impl TestConfig {
/// Create config for fast tests (lower quality but faster)
pub fn fast() -> Self {
Self {
hnsw_m: 8,
hnsw_ef_construction: 50,
hnsw_ef_search: 20,
min_cluster_size: 3,
target_recall_at_10: 0.90,
..Default::default()
}
}
/// Create config for high-quality tests (slower but more accurate)
pub fn high_quality() -> Self {
Self {
hnsw_m: 32,
hnsw_ef_construction: 400,
hnsw_ef_search: 200,
min_cluster_size: 10,
target_recall_at_10: 0.99,
..Default::default()
}
}
}
/// Shared test context that can be used across integration tests
pub struct IntegrationTestContext {
pub config: TestConfig,
pub recording_repo: MockRecordingRepository,
pub segment_repo: MockSegmentRepository,
pub embedding_repo: MockEmbeddingRepository,
pub vector_index: MockVectorIndex,
pub clustering_service: MockClusteringService,
pub evidence_builder: MockEvidencePackBuilder,
pub interpretation_generator: MockInterpretationGenerator,
}
impl Default for IntegrationTestContext {
fn default() -> Self {
Self::new()
}
}
impl IntegrationTestContext {
pub fn new() -> Self {
let config = TestConfig::default();
Self {
config: config.clone(),
recording_repo: MockRecordingRepository::new(),
segment_repo: MockSegmentRepository::new(),
embedding_repo: MockEmbeddingRepository::new(),
vector_index: MockVectorIndex::with_config(HnswConfig {
m: config.hnsw_m,
ef_construction: config.hnsw_ef_construction,
ef_search: config.hnsw_ef_search,
max_layers: 6,
}),
clustering_service: MockClusteringService::with_params(config.min_cluster_size, 3),
evidence_builder: MockEvidencePackBuilder::new(),
interpretation_generator: MockInterpretationGenerator::new(),
}
}
pub fn with_config(config: TestConfig) -> Self {
Self {
config: config.clone(),
recording_repo: MockRecordingRepository::new(),
segment_repo: MockSegmentRepository::new(),
embedding_repo: MockEmbeddingRepository::new(),
vector_index: MockVectorIndex::with_config(HnswConfig {
m: config.hnsw_m,
ef_construction: config.hnsw_ef_construction,
ef_search: config.hnsw_ef_search,
max_layers: 6,
}),
clustering_service: MockClusteringService::with_params(config.min_cluster_size, 3),
evidence_builder: MockEvidencePackBuilder::new(),
interpretation_generator: MockInterpretationGenerator::new(),
}
}
/// Populate context with test data
pub fn with_test_data(self, num_recordings: usize, segments_per_recording: usize) -> Self {
for _ in 0..num_recordings {
let recording = create_test_recording();
let recording_id = recording.id;
self.recording_repo.save(recording).unwrap();
for i in 0..segments_per_recording {
let start_ms = i as u64 * 5500;
let segment = CallSegment {
id: SegmentId::new(),
recording_id,
start_ms,
end_ms: start_ms + 5000,
..Default::default()
};
let segment_id = segment.id;
self.segment_repo.save(segment).unwrap();
self.recording_repo
.add_segment_link(recording_id, segment_id);
let embedding = Embedding {
segment_id,
..Default::default()
};
let embedding_id = embedding.id;
let vector = embedding.vector.clone();
self.embedding_repo.save(embedding).unwrap();
self.vector_index.insert(embedding_id, vector).unwrap();
}
}
self
}
}
/// Helper macro for async test setup
#[macro_export]
macro_rules! setup_test {
() => {
IntegrationTestContext::new()
};
(fast) => {
IntegrationTestContext::with_config(TestConfig::fast())
};
(high_quality) => {
IntegrationTestContext::with_config(TestConfig::high_quality())
};
(populated) => {
IntegrationTestContext::new().with_test_data(5, 10)
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_integration_context_creation() {
let ctx = IntegrationTestContext::new();
assert_eq!(ctx.config.sample_rate, 32000);
assert_eq!(ctx.config.embedding_dims, 1536);
}
#[test]
fn test_context_with_test_data() {
let ctx = IntegrationTestContext::new().with_test_data(2, 5);
assert_eq!(ctx.recording_repo.count(), 2);
assert_eq!(ctx.segment_repo.count(), 10);
assert_eq!(ctx.embedding_repo.count(), 10);
assert_eq!(ctx.vector_index.count(), 10);
}
#[test]
fn test_config_variants() {
let fast = TestConfig::fast();
let hq = TestConfig::high_quality();
assert!(fast.hnsw_m < hq.hnsw_m);
assert!(fast.hnsw_ef_construction < hq.hnsw_ef_construction);
assert!(fast.target_recall_at_10 < hq.target_recall_at_10);
}
}