pub mod compat;
pub mod graph;
pub mod manager;
pub mod schema;
pub mod types;
pub use compat::RbacCompatLayer;
pub use graph::RelationshipGraph;
pub use manager::{create_shared_rebac_manager, RebacManager, SharedRebacManager};
pub use schema::{PermissionSchema, RelationDefinition, RewriteRule, TypeDefinition};
pub use types::{Object, Relation, RelationTuple, Subject};
#[cfg(test)]
mod integration_tests {
use super::*;
#[test]
fn test_end_to_end_document_sharing() {
let rebac = RebacManager::new();
rebac
.grant("user:alice", "owner", "document:123")
.expect("grant should succeed");
rebac
.grant("user:bob", "editor", "document:123")
.expect("grant should succeed");
rebac
.grant("user:charlie", "viewer", "document:123")
.expect("grant should succeed");
assert!(rebac
.check_access("user:alice", "owner", "document:123")
.expect("check should succeed"));
assert!(rebac
.check_access("user:bob", "editor", "document:123")
.expect("check should succeed"));
assert!(rebac
.check_access("user:charlie", "viewer", "document:123")
.expect("check should succeed"));
assert!(!rebac
.check_access("user:dave", "viewer", "document:123")
.expect("check should succeed"));
}
#[test]
fn test_folder_hierarchy() {
let rebac = RebacManager::new();
rebac
.grant("document:123", "parent", "folder:456")
.expect("grant should succeed");
rebac
.grant("folder:456", "parent", "folder:789")
.expect("grant should succeed");
rebac
.grant("user:alice", "viewer", "folder:789")
.expect("grant should succeed");
assert!(rebac
.check_access("user:alice", "viewer", "folder:456")
.expect("check should succeed"));
}
#[test]
fn test_batch_operations_performance() {
let rebac = RebacManager::new();
let doc_ids: Vec<String> = (0..100).map(|i| format!("document:{}", i)).collect();
let grants: Vec<(&str, &str, &str)> = doc_ids
.iter()
.map(|doc_id| ("user:alice", "viewer", doc_id.as_str()))
.collect();
let start = std::time::Instant::now();
rebac
.grant_batch(grants)
.expect("batch grant should succeed");
let grant_duration = start.elapsed();
println!("Batch grant (100 items): {:?}", grant_duration);
let checks: Vec<(&str, &str, &str)> = doc_ids
.iter()
.map(|doc_id| ("user:alice", "viewer", doc_id.as_str()))
.collect();
let start = std::time::Instant::now();
let results = rebac
.check_batch(checks)
.expect("batch check should succeed");
let check_duration = start.elapsed();
println!("Batch check (100 items): {:?}", check_duration);
assert_eq!(results.len(), 100);
assert!(results.iter().all(|&r| r));
}
#[test]
fn test_list_accessible_resources() {
let rebac = RebacManager::new();
for i in 1..=5 {
rebac
.grant("user:alice", "owner", &format!("document:{}", i))
.expect("grant should succeed");
}
let docs = rebac
.list_accessible("user:alice", "owner", "document")
.expect("list should succeed");
assert_eq!(docs.len(), 5);
}
#[test]
fn test_expand_permissions() {
let rebac = RebacManager::new();
rebac
.grant("user:alice", "viewer", "document:123")
.expect("grant should succeed");
rebac
.grant("user:bob", "viewer", "document:123")
.expect("grant should succeed");
rebac
.grant("user:charlie", "viewer", "document:123")
.expect("grant should succeed");
let viewers = rebac
.expand("viewer", "document:123")
.expect("expand should succeed");
assert_eq!(viewers.len(), 3);
}
#[test]
fn test_cache_effectiveness() {
let rebac = RebacManager::with_cache_size(100);
rebac
.grant("user:alice", "owner", "document:123")
.expect("grant should succeed");
let start = std::time::Instant::now();
let result1 = rebac
.check_access("user:alice", "owner", "document:123")
.expect("check should succeed");
let duration1 = start.elapsed();
let start = std::time::Instant::now();
let result2 = rebac
.check_access("user:alice", "owner", "document:123")
.expect("check should succeed");
let duration2 = start.elapsed();
assert!(result1);
assert!(result2);
println!("First check (miss): {:?}", duration1);
println!("Second check (hit): {:?}", duration2);
let (cache_size, cache_capacity) = rebac.cache_stats().expect("stats should succeed");
assert_eq!(cache_size, 1);
assert_eq!(cache_capacity, 100);
}
}