Files
wifi-densepose/vendor/ruvector/tests/graph_integration.rs

387 lines
11 KiB
Rust

//! Integration tests for RuVector graph database
//!
//! End-to-end tests that verify all components work together correctly.
use ruvector_graph::{GraphDB, Node, Edge, Label, RelationType, Properties, PropertyValue};
// ============================================================================
// Full Workflow Integration Tests
// ============================================================================
#[test]
fn test_complete_graph_workflow() {
let db = GraphDB::new();
// 1. Create nodes
let mut alice_props = Properties::new();
alice_props.insert("name".to_string(), PropertyValue::String("Alice".to_string()));
alice_props.insert("age".to_string(), PropertyValue::Integer(30));
let mut bob_props = Properties::new();
bob_props.insert("name".to_string(), PropertyValue::String("Bob".to_string()));
bob_props.insert("age".to_string(), PropertyValue::Integer(35));
db.create_node(Node::new(
"alice".to_string(),
vec![Label { name: "Person".to_string() }],
alice_props,
)).unwrap();
db.create_node(Node::new(
"bob".to_string(),
vec![Label { name: "Person".to_string() }],
bob_props,
)).unwrap();
// 2. Create relationship
let mut edge_props = Properties::new();
edge_props.insert("since".to_string(), PropertyValue::Integer(2020));
db.create_edge(Edge::new(
"knows".to_string(),
"alice".to_string(),
"bob".to_string(),
RelationType { name: "KNOWS".to_string() },
edge_props,
)).unwrap();
// 3. Verify everything was created
let alice = db.get_node("alice").unwrap();
let bob = db.get_node("bob").unwrap();
let edge = db.get_edge("knows").unwrap();
assert_eq!(alice.labels[0].name, "Person");
assert_eq!(bob.labels[0].name, "Person");
assert_eq!(edge.rel_type.name, "KNOWS");
assert_eq!(edge.from_node, "alice");
assert_eq!(edge.to_node, "bob");
}
#[test]
fn test_social_network_scenario() {
let db = GraphDB::new();
// Create users
for i in 0..10 {
let mut props = Properties::new();
props.insert("username".to_string(), PropertyValue::String(format!("user{}", i)));
props.insert("followers".to_string(), PropertyValue::Integer(i * 100));
db.create_node(Node::new(
format!("user{}", i),
vec![Label { name: "User".to_string() }],
props,
)).unwrap();
}
// Create follow relationships
for i in 0..9 {
let edge = Edge::new(
format!("follow_{}", i),
format!("user{}", i),
format!("user{}", i + 1),
RelationType { name: "FOLLOWS".to_string() },
Properties::new(),
);
db.create_edge(edge).unwrap();
}
// Verify graph structure
for i in 0..10 {
assert!(db.get_node(&format!("user{}", i)).is_some());
}
for i in 0..9 {
assert!(db.get_edge(&format!("follow_{}", i)).is_some());
}
}
#[test]
fn test_movie_database_scenario() {
let db = GraphDB::new();
// Create movies
let mut inception_props = Properties::new();
inception_props.insert("title".to_string(), PropertyValue::String("Inception".to_string()));
inception_props.insert("year".to_string(), PropertyValue::Integer(2010));
inception_props.insert("rating".to_string(), PropertyValue::Float(8.8));
db.create_node(Node::new(
"inception".to_string(),
vec![Label { name: "Movie".to_string() }],
inception_props,
)).unwrap();
// Create actors
let mut dicaprio_props = Properties::new();
dicaprio_props.insert("name".to_string(), PropertyValue::String("Leonardo DiCaprio".to_string()));
db.create_node(Node::new(
"dicaprio".to_string(),
vec![Label { name: "Actor".to_string() }],
dicaprio_props,
)).unwrap();
// Create ACTED_IN relationship
let mut role_props = Properties::new();
role_props.insert("character".to_string(), PropertyValue::String("Cobb".to_string()));
db.create_edge(Edge::new(
"acted1".to_string(),
"dicaprio".to_string(),
"inception".to_string(),
RelationType { name: "ACTED_IN".to_string() },
role_props,
)).unwrap();
// Verify
let movie = db.get_node("inception").unwrap();
let actor = db.get_node("dicaprio").unwrap();
let role = db.get_edge("acted1").unwrap();
assert!(movie.properties.contains_key("title"));
assert!(actor.properties.contains_key("name"));
assert_eq!(role.rel_type.name, "ACTED_IN");
}
#[test]
fn test_knowledge_graph_scenario() {
let db = GraphDB::new();
// Create concepts
let concepts = vec![
("ml", "Machine Learning"),
("ai", "Artificial Intelligence"),
("dl", "Deep Learning"),
("nn", "Neural Networks"),
];
for (id, name) in concepts {
let mut props = Properties::new();
props.insert("name".to_string(), PropertyValue::String(name.to_string()));
db.create_node(Node::new(
id.to_string(),
vec![Label { name: "Concept".to_string() }],
props,
)).unwrap();
}
// Create relationships
db.create_edge(Edge::new(
"e1".to_string(),
"dl".to_string(),
"ml".to_string(),
RelationType { name: "IS_A".to_string() },
Properties::new(),
)).unwrap();
db.create_edge(Edge::new(
"e2".to_string(),
"ml".to_string(),
"ai".to_string(),
RelationType { name: "IS_A".to_string() },
Properties::new(),
)).unwrap();
db.create_edge(Edge::new(
"e3".to_string(),
"dl".to_string(),
"nn".to_string(),
RelationType { name: "USES".to_string() },
Properties::new(),
)).unwrap();
// Verify concept hierarchy
assert!(db.get_node("ai").is_some());
assert!(db.get_edge("e1").is_some());
}
// ============================================================================
// Complex Multi-Step Operations
// ============================================================================
#[test]
fn test_batch_import() {
let db = GraphDB::new();
// Simulate importing a batch of data
let nodes_to_import = 100;
for i in 0..nodes_to_import {
let mut props = Properties::new();
props.insert("id".to_string(), PropertyValue::Integer(i));
props.insert("type".to_string(), PropertyValue::String("imported".to_string()));
let node = Node::new(
format!("import_{}", i),
vec![Label { name: "Imported".to_string() }],
props,
);
db.create_node(node).unwrap();
}
// Verify all were imported
for i in 0..nodes_to_import {
assert!(db.get_node(&format!("import_{}", i)).is_some());
}
}
#[test]
fn test_graph_transformation() {
let db = GraphDB::new();
// Original graph: Linear chain
for i in 0..10 {
db.create_node(Node::new(
format!("n{}", i),
vec![],
Properties::new(),
)).unwrap();
}
for i in 0..9 {
db.create_edge(Edge::new(
format!("e{}", i),
format!("n{}", i),
format!("n{}", i + 1),
RelationType { name: "NEXT".to_string() },
Properties::new(),
)).unwrap();
}
// Transform: Add reverse edges
for i in 0..9 {
db.create_edge(Edge::new(
format!("rev_e{}", i),
format!("n{}", i + 1),
format!("n{}", i),
RelationType { name: "PREV".to_string() },
Properties::new(),
)).unwrap();
}
// Verify bidirectional graph
assert!(db.get_edge("e5").is_some());
assert!(db.get_edge("rev_e5").is_some());
}
// ============================================================================
// Error Recovery Tests
// ============================================================================
#[test]
fn test_handle_missing_nodes_gracefully() {
let db = GraphDB::new();
// Try to get non-existent node
let result = db.get_node("does_not_exist");
assert!(result.is_none());
// Try to get non-existent edge
let result = db.get_edge("missing_edge");
assert!(result.is_none());
}
#[test]
fn test_duplicate_id_handling() {
let db = GraphDB::new();
let node1 = Node::new(
"duplicate".to_string(),
vec![],
Properties::new(),
);
db.create_node(node1).unwrap();
// Try to create node with same ID
let node2 = Node::new(
"duplicate".to_string(),
vec![],
Properties::new(),
);
// This should either update or error, depending on desired semantics
// For now, just verify it doesn't panic
let _result = db.create_node(node2);
}
// ============================================================================
// Data Integrity Tests
// ============================================================================
#[test]
fn test_edge_referential_integrity() {
let db = GraphDB::new();
// Create nodes
db.create_node(Node::new("a".to_string(), vec![], Properties::new())).unwrap();
db.create_node(Node::new("b".to_string(), vec![], Properties::new())).unwrap();
// Create valid edge
let edge = Edge::new(
"e1".to_string(),
"a".to_string(),
"b".to_string(),
RelationType { name: "LINKS".to_string() },
Properties::new(),
);
let result = db.create_edge(edge);
assert!(result.is_ok());
// Try to create edge with non-existent source
// Note: Current implementation doesn't check this, but it should
let bad_edge = Edge::new(
"e2".to_string(),
"nonexistent".to_string(),
"b".to_string(),
RelationType { name: "LINKS".to_string() },
Properties::new(),
);
let _result = db.create_edge(bad_edge);
// TODO: Should fail with error
}
// ============================================================================
// Performance Integration Tests
// ============================================================================
#[test]
fn test_large_graph_operations() {
let db = GraphDB::new();
let num_nodes = 1000;
let num_edges = 5000;
// Create nodes
for i in 0..num_nodes {
db.create_node(Node::new(
format!("large_{}", i),
vec![],
Properties::new(),
)).unwrap();
}
// Create edges
for i in 0..num_edges {
let from = i % num_nodes;
let to = (i + 1) % num_nodes;
db.create_edge(Edge::new(
format!("e_{}", i),
format!("large_{}", from),
format!("large_{}", to),
RelationType { name: "EDGE".to_string() },
Properties::new(),
)).unwrap();
}
// Verify graph size
// TODO: Add methods to get counts
}