use oxirouter::core::source::SourceCapabilities;
use oxirouter::prelude::*;
#[test]
fn test_routing_respects_capabilities() {
let mut router = Router::new();
let basic = DataSource::new("basic", "http://basic.example.com/sparql")
.with_capabilities(SourceCapabilities::basic());
router.add_source(basic);
let full = DataSource::new("full", "http://full.example.com/sparql")
.with_capabilities(SourceCapabilities::full());
router.add_source(full);
let query = Query::parse(
r"
SELECT (COUNT(?s) AS ?count) WHERE {
?s ?p ?o
}
",
)
.unwrap();
let ranking = router.route(&query).unwrap();
if let Some(basic_selection) = ranking.sources.iter().find(|s| s.source_id == "basic") {
if let Some(full_selection) = ranking.sources.iter().find(|s| s.source_id == "full") {
assert!(full_selection.confidence >= basic_selection.confidence);
}
}
}
#[test]
fn test_vocabulary_routing() {
let mut router = Router::new();
router.add_source(
DataSource::new("dbpedia", "http://dbpedia.example.com/sparql")
.with_vocabulary("http://dbpedia.org/ontology/")
.with_vocabulary("http://dbpedia.org/property/"),
);
router.add_source(
DataSource::new("schema", "http://schema.example.com/sparql")
.with_vocabulary("http://schema.org/"),
);
let dbpedia_query = Query::parse(
r"
PREFIX dbo: <http://dbpedia.org/ontology/>
SELECT ?name WHERE { ?s dbo:name ?name }
",
)
.unwrap();
let ranking = router.route(&dbpedia_query).unwrap();
assert!(ranking.best().is_some());
}
#[test]
fn test_priority_routing() {
let mut router = Router::new();
router.add_source(DataSource::new("low", "http://low.example.com/sparql").with_priority(0.1));
router
.add_source(DataSource::new("high", "http://high.example.com/sparql").with_priority(10.0));
let query = Query::parse("SELECT ?s WHERE { ?s ?p ?o }").unwrap();
let ranking = router.route(&query).unwrap();
assert_eq!(ranking.best().unwrap().source_id, "high");
}
#[test]
fn test_historical_performance_routing() {
let mut router = Router::new();
router.add_source(DataSource::new("fast", "http://fast.example.com/sparql"));
router.add_source(DataSource::new("slow", "http://slow.example.com/sparql"));
for _ in 0..10 {
router.update_source_stats("fast", 50, true, 100).unwrap();
router.update_source_stats("slow", 5000, true, 10).unwrap();
}
let query = Query::parse("SELECT ?s WHERE { ?s ?p ?o }").unwrap();
let ranking = router.route(&query).unwrap();
let fast_idx = ranking.sources.iter().position(|s| s.source_id == "fast");
let slow_idx = ranking.sources.iter().position(|s| s.source_id == "slow");
if let (Some(fast), Some(slow)) = (fast_idx, slow_idx) {
assert!(
fast < slow,
"Fast source should rank higher than slow source"
);
}
}
#[test]
fn test_unavailable_sources_excluded() {
let mut router = Router::new();
router.add_source(DataSource::new(
"available",
"http://available.example.com/sparql",
));
router.add_source(DataSource::new(
"unavailable",
"http://unavailable.example.com/sparql",
));
router.mark_unavailable("unavailable").unwrap();
let query = Query::parse("SELECT ?s WHERE { ?s ?p ?o }").unwrap();
let ranking = router.route(&query).unwrap();
let source_ids: Vec<&str> = ranking
.sources
.iter()
.map(|s| s.source_id.as_str())
.collect();
assert!(source_ids.contains(&"available"));
assert!(!source_ids.contains(&"unavailable"));
}
#[test]
fn test_max_sources_config() {
let config = oxirouter::core::router::RouterConfig {
max_sources: 2,
..Default::default()
};
let mut router = Router::with_config(config, oxirouter::context::DefaultContextProvider);
for i in 0..10 {
router.add_source(DataSource::new(
format!("src{}", i),
format!("http://src{}.example.com/sparql", i),
));
}
let query = Query::parse("SELECT ?s WHERE { ?s ?p ?o }").unwrap();
let ranking = router.route(&query).unwrap();
assert!(ranking.len() <= 2);
}
#[test]
fn test_min_confidence_filter() {
let config = oxirouter::core::router::RouterConfig {
min_confidence: 0.9, ..Default::default()
};
let mut router = Router::with_config(config, oxirouter::context::DefaultContextProvider);
router.add_source(DataSource::new("test", "http://test.example.com/sparql"));
let query = Query::parse("SELECT ?s WHERE { ?s ?p ?o }").unwrap();
let ranking = router.route(&query).unwrap();
for selection in &ranking.sources {
assert!(selection.confidence >= 0.9);
}
}
#[test]
fn test_query_type_routing() {
let mut router = Router::new();
let no_construct = DataSource::new("no_construct", "http://nocon.example.com/sparql")
.with_capabilities(SourceCapabilities {
construct: false,
..SourceCapabilities::basic()
});
router.add_source(no_construct);
router.add_source(
DataSource::new("with_construct", "http://withcon.example.com/sparql")
.with_capabilities(SourceCapabilities::full()),
);
let query = Query::parse("CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }").unwrap();
let ranking = router.route(&query).unwrap();
assert!(!ranking.is_empty());
}
#[test]
fn test_empty_sources() {
let router = Router::new();
let query = Query::parse("SELECT ?s WHERE { ?s ?p ?o }").unwrap();
let result = router.route(&query);
assert!(result.is_err());
}
#[test]
fn test_multiple_vocabularies() {
let mut router = Router::new();
router.add_source(
DataSource::new("multi", "http://multi.example.com/sparql")
.with_vocabulary("http://schema.org/")
.with_vocabulary("http://xmlns.com/foaf/0.1/")
.with_vocabulary("http://purl.org/dc/terms/"),
);
router.add_source(
DataSource::new("single", "http://single.example.com/sparql")
.with_vocabulary("http://schema.org/"),
);
let query = Query::parse(
r"
PREFIX schema: <http://schema.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name WHERE {
?s schema:name ?name .
?s foaf:knows ?friend .
}
",
)
.unwrap();
let ranking = router.route(&query).unwrap();
assert!(!ranking.is_empty());
}
#[test]
fn test_complex_query_routing() {
let mut router = Router::new();
router.add_source(
DataSource::new("full", "http://full.example.com/sparql")
.with_capabilities(SourceCapabilities::full()),
);
let query = Query::parse(
r"
SELECT ?person (COUNT(?paper) AS ?paperCount) WHERE {
{
SELECT ?person WHERE {
?person a <http://example.org/Researcher>
}
}
OPTIONAL {
?person <http://example.org/authored> ?paper
}
}
GROUP BY ?person
HAVING (COUNT(?paper) > 5)
",
)
.unwrap();
assert!(query.requires_sparql_1_1());
assert!(query.has_optional);
assert!(query.has_aggregation);
assert!(query.has_subquery);
let ranking = router.route(&query).unwrap();
assert!(!ranking.is_empty());
}