stemedb/crates/stemedb-query/src/engine/tests/alias_resolution.rs
jordan d3a88585fe feat: Phase 6 UAT - Admission control, HLC recency, cluster coordination
This commit includes comprehensive work on Phase 6 features:

## Admission Control (Phase 6 admission middleware)
- AdmissionStore implementation backed by TrustRankStore
- PoW verification with tier-based difficulty computation
- Trust tier progression (Newcomer → Established → Trusted → Authority)
- API integration with admission status endpoints

## HLC Recency Lens (Phase 6C)
- HlcRecencyLens for distributed system ordering
- Hybrid logical clock integration with causality preservation

## Cluster Coordination (Phase 6C)
- Multi-node cluster tests (availability, partition tolerance)
- CRDT convergence tests for anti-entropy sync
- Gateway handler improvements

## Aphoria Code Linter (Phase 2A)
- RFC/OWASP corpus builders with network fetching and caching
- Concept hierarchy with auto-alias creation on conflict detection
- Multiple security extractors (TLS, JWT, CORS, secrets, rate limiting)

## Code Organization
- Split large files into modules to comply with 500-line limit
- Improved test organization with separate test modules
- Fixed rkyv serialization for EigenTrustState (AgentScore struct)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 00:43:37 -07:00

255 lines
9.2 KiB
Rust

//! Tests for alias resolution in QueryEngine.
//!
//! Tests the `resolve_aliases` query flag and `alias_store` integration.
use std::sync::Arc;
use stemedb_core::testing::AssertionBuilder;
use stemedb_core::types::{AliasOrigin, ConceptAlias, ConceptPath, LifecycleStage};
use stemedb_storage::{AliasStore, GenericAliasStore, HybridStore};
use super::{store_assertion, QueryEngine};
use crate::query::Query;
/// Helper to create a test ConceptAlias.
fn create_alias(alias: &str, canonical: &str) -> ConceptAlias {
ConceptAlias::new(
ConceptPath::parse(alias).expect("valid alias path"),
ConceptPath::parse(canonical).expect("valid canonical path"),
[1u8; 32], // agent_id
1000, // timestamp
AliasOrigin::Manual,
)
}
/// Test that resolve_aliases: true expands subject to aliased paths.
#[tokio::test]
async fn test_resolve_aliases_expands_subjects() {
let store = Arc::new(HybridStore::open_temp().expect("store"));
// Create assertions for two different subjects (aliased paths)
let code_assertion = AssertionBuilder::new()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.object_text("enabled")
.confidence(0.8)
.lifecycle(LifecycleStage::Approved)
.build();
let rfc_assertion = AssertionBuilder::new()
.subject("rfc://5246/tls")
.predicate("cert_verification")
.object_text("required")
.confidence(0.95)
.lifecycle(LifecycleStage::Approved)
.build();
store_assertion(&store, &code_assertion).await;
store_assertion(&store, &rfc_assertion).await;
// Set up alias store with alias: code://rust/myapp/tls -> rfc://5246/tls
let alias_store = GenericAliasStore::new(store.clone());
let alias = create_alias("code://rust/myapp/tls", "rfc://5246/tls");
alias_store.set_alias(&alias).await.expect("set alias");
// Create query engine with alias store
let engine = QueryEngine::new(Arc::new(store.clone()))
.with_alias_store(Arc::new(alias_store) as Arc<dyn AliasStore>);
// Query with resolve_aliases: true should find BOTH assertions
let query = Query::builder()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.resolve_aliases(true)
.build();
let result = engine.execute(&query).await.expect("execute");
assert_eq!(result.assertions.len(), 2, "Should find assertions from both aliased subjects");
let subjects: Vec<&str> = result.assertions.iter().map(|a| a.subject.as_str()).collect();
assert!(subjects.contains(&"code://rust/myapp/tls"), "Should include code assertion");
assert!(subjects.contains(&"rfc://5246/tls"), "Should include rfc assertion");
}
/// Test that resolve_aliases: false queries exact subject only.
#[tokio::test]
async fn test_resolve_aliases_false_is_exact() {
let store = Arc::new(HybridStore::open_temp().expect("store"));
// Create assertions for two different subjects
let code_assertion = AssertionBuilder::new()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.object_text("enabled")
.confidence(0.8)
.lifecycle(LifecycleStage::Approved)
.build();
let rfc_assertion = AssertionBuilder::new()
.subject("rfc://5246/tls")
.predicate("cert_verification")
.object_text("required")
.confidence(0.95)
.lifecycle(LifecycleStage::Approved)
.build();
store_assertion(&store, &code_assertion).await;
store_assertion(&store, &rfc_assertion).await;
// Set up alias store with alias
let alias_store = GenericAliasStore::new(store.clone());
let alias = create_alias("code://rust/myapp/tls", "rfc://5246/tls");
alias_store.set_alias(&alias).await.expect("set alias");
let engine = QueryEngine::new(Arc::new(store.clone()))
.with_alias_store(Arc::new(alias_store) as Arc<dyn AliasStore>);
// Query with resolve_aliases: false (default) should find only the exact subject
let query = Query::builder()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.resolve_aliases(false)
.build();
let result = engine.execute(&query).await.expect("execute");
assert_eq!(result.assertions.len(), 1, "Should find only exact subject assertion");
assert_eq!(result.assertions[0].subject, "code://rust/myapp/tls");
}
/// Test that resolve_aliases: true without alias_store gracefully returns exact subject.
#[tokio::test]
async fn test_no_alias_store_graceful() {
let store = Arc::new(HybridStore::open_temp().expect("store"));
let assertion = AssertionBuilder::new()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.object_text("enabled")
.confidence(0.8)
.lifecycle(LifecycleStage::Approved)
.build();
store_assertion(&store, &assertion).await;
// Query engine WITHOUT alias store
let engine = QueryEngine::new(Arc::new(store));
// Query with resolve_aliases: true should still work (graceful degradation)
let query = Query::builder()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.resolve_aliases(true)
.build();
let result = engine.execute(&query).await.expect("execute");
assert_eq!(result.assertions.len(), 1, "Should find exact subject assertion");
assert_eq!(result.assertions[0].subject, "code://rust/myapp/tls");
}
/// Test that alias resolution deduplicates by assertion hash.
#[tokio::test]
async fn test_resolve_aliases_deduplicates() {
let store = Arc::new(HybridStore::open_temp().expect("store"));
// Create a single assertion
let assertion = AssertionBuilder::new()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.object_text("enabled")
.confidence(0.8)
.lifecycle(LifecycleStage::Approved)
.build();
store_assertion(&store, &assertion).await;
// Set up alias store where both paths lead to the same subject
// (In real use, this wouldn't happen, but tests the dedup logic)
let alias_store = GenericAliasStore::new(store.clone());
// No alias set - both code:// and the query subject are the same
let engine = QueryEngine::new(Arc::new(store.clone()))
.with_alias_store(Arc::new(alias_store) as Arc<dyn AliasStore>);
// Query with resolve_aliases: true
let query = Query::builder().subject("code://rust/myapp/tls").resolve_aliases(true).build();
let result = engine.execute(&query).await.expect("execute");
// Should have exactly 1 result (no duplicates)
assert_eq!(result.assertions.len(), 1);
}
/// Test subject-only query with alias resolution.
#[tokio::test]
async fn test_resolve_aliases_subject_only() {
let store = Arc::new(HybridStore::open_temp().expect("store"));
// Create assertions for two aliased subjects with different predicates
let code_assertion1 = AssertionBuilder::new()
.subject("code://rust/myapp/tls")
.predicate("cert_verification")
.object_text("enabled")
.confidence(0.8)
.lifecycle(LifecycleStage::Approved)
.build();
let code_assertion2 = AssertionBuilder::new()
.subject("code://rust/myapp/tls")
.predicate("timeout")
.object_text("30s")
.confidence(0.9)
.lifecycle(LifecycleStage::Approved)
.build();
let rfc_assertion = AssertionBuilder::new()
.subject("rfc://5246/tls")
.predicate("cert_verification")
.object_text("required")
.confidence(0.95)
.lifecycle(LifecycleStage::Approved)
.build();
store_assertion(&store, &code_assertion1).await;
store_assertion(&store, &code_assertion2).await;
store_assertion(&store, &rfc_assertion).await;
// Set up alias store
let alias_store = GenericAliasStore::new(store.clone());
let alias = create_alias("code://rust/myapp/tls", "rfc://5246/tls");
alias_store.set_alias(&alias).await.expect("set alias");
let engine = QueryEngine::new(Arc::new(store.clone()))
.with_alias_store(Arc::new(alias_store) as Arc<dyn AliasStore>);
// Query by subject only (no predicate filter) with resolve_aliases: true
let query = Query::builder().subject("code://rust/myapp/tls").resolve_aliases(true).build();
let result = engine.execute(&query).await.expect("execute");
// Should find all 3 assertions (2 from code://, 1 from rfc://)
assert_eq!(result.assertions.len(), 3, "Should find all assertions from aliased subjects");
}
/// Test default query (resolve_aliases not set) behaves like exact match.
#[tokio::test]
async fn test_resolve_aliases_default_is_false() {
let query = Query::builder().subject("test").predicate("pred").build();
assert!(!query.resolve_aliases, "Default should be false");
}
/// Test query builder sets resolve_aliases correctly.
#[tokio::test]
async fn test_query_builder_resolve_aliases() {
let query_true =
Query::builder().subject("test").predicate("pred").resolve_aliases(true).build();
let query_false =
Query::builder().subject("test").predicate("pred").resolve_aliases(false).build();
assert!(query_true.resolve_aliases, "Should be true when set to true");
assert!(!query_false.resolve_aliases, "Should be false when set to false");
}