use ruvector_dag::*;
#[test]
fn test_mincut_engine_basic() {
let mut dag = QueryDag::new();
let scan = dag.add_node(OperatorNode::seq_scan(0, "users").with_estimates(1000.0, 100.0));
let filter = dag.add_node(OperatorNode::filter(0, "age > 18").with_estimates(500.0, 50.0));
let sort =
dag.add_node(OperatorNode::sort(0, vec!["name".to_string()]).with_estimates(500.0, 150.0));
dag.add_edge(scan, filter).unwrap();
dag.add_edge(filter, sort).unwrap();
let mut engine = DagMinCutEngine::new(MinCutConfig::default());
engine.build_from_dag(&dag);
assert_eq!(dag.node_count(), 3);
}
#[test]
fn test_bottleneck_analysis() {
let mut dag = QueryDag::new();
let scan = dag.add_node(
OperatorNode::seq_scan(0, "users").with_estimates(10000.0, 1000.0), );
let filter = dag.add_node(
OperatorNode::filter(0, "active = true").with_estimates(5000.0, 10.0), );
dag.add_edge(scan, filter).unwrap();
let mut engine = DagMinCutEngine::new(MinCutConfig::default());
engine.build_from_dag(&dag);
let criticality = engine.compute_criticality(&dag);
let analysis = BottleneckAnalysis::analyze(&dag, &criticality);
assert!(analysis.total_cost > 0.0);
assert!(analysis.critical_path_cost > 0.0);
}
#[test]
fn test_redundancy_suggestions() {
let mut dag = QueryDag::new();
let scan = dag
.add_node(OperatorNode::hnsw_scan(0, "embeddings_idx", 100).with_estimates(1000.0, 200.0));
let bottleneck = Bottleneck {
node_id: scan,
score: 0.8,
impact_estimate: 160.0,
suggested_action: "Test".to_string(),
};
let suggestions = RedundancySuggestion::generate(&dag, &[bottleneck]);
assert_eq!(suggestions.len(), 1);
assert!(matches!(
suggestions[0].strategy,
RedundancyStrategy::Prefetch
));
}
#[test]
fn test_local_kcut_computation() {
let mut dag = QueryDag::new();
let n0 = dag.add_node(OperatorNode::seq_scan(0, "t0").with_estimates(100.0, 10.0));
let n1 = dag.add_node(OperatorNode::filter(0, "f1").with_estimates(50.0, 20.0));
let n2 = dag.add_node(OperatorNode::sort(0, vec!["c1".to_string()]).with_estimates(50.0, 30.0));
dag.add_edge(n0, n1).unwrap();
dag.add_edge(n1, n2).unwrap();
let mut engine = DagMinCutEngine::new(MinCutConfig {
epsilon: 0.1,
local_search_depth: 5,
cache_cuts: true,
});
engine.build_from_dag(&dag);
let result = engine.compute_mincut(n0, n2);
assert!(result.cut_value >= 0.0);
}
#[test]
fn test_dynamic_edge_update() {
let mut dag = QueryDag::new();
let n0 = dag.add_node(OperatorNode::seq_scan(0, "t0").with_estimates(100.0, 10.0));
let n1 = dag.add_node(OperatorNode::filter(0, "f1").with_estimates(50.0, 20.0));
let n2 = dag.add_node(OperatorNode::sort(0, vec!["c1".to_string()]).with_estimates(50.0, 30.0));
dag.add_edge(n0, n1).unwrap();
dag.add_edge(n1, n2).unwrap();
let mut engine = DagMinCutEngine::new(MinCutConfig::default());
engine.build_from_dag(&dag);
engine.update_edge(n0, n1, 15.0);
let result = engine.compute_mincut(n0, n2);
assert!(result.cut_value >= 0.0);
}
#[test]
fn test_mincut_config() {
let config = MinCutConfig {
epsilon: 0.05,
local_search_depth: 10,
cache_cuts: false,
};
assert_eq!(config.epsilon, 0.05);
assert_eq!(config.local_search_depth, 10);
assert!(!config.cache_cuts);
}