sqlitegraph 2.2.2

Embedded graph database with full ACID transactions, HNSW vector search, dual backend support, and comprehensive graph algorithms library
Documentation
//! Page Ownership Forensics Test
//!
//! This test uses the v3-forensics feature to track page ownership
//! and detect corruption by identifying page ownership conflicts.
//!
//! Run with:
//! ```bash
//! cargo test --features native-v3,v3-forensics v3_page_ownership -- --nocapture
//! ```

#[test]
#[cfg(feature = "v3-forensics")]
fn test_v3_page_ownership_tracking() {
    let temp = TempDir::new().unwrap();
    let db_path = temp.path().join("v3_ownership_test.db");

    // Reset page ownership tracking before test
    sqlitegraph::backend::native::v3::forensics::reset_page_ownership();

    println!("\n=== Testing page ownership tracking with 1K nodes ===\n");

    // Create and populate
    {
        let backend = V3Backend::create(&db_path).unwrap();

        // Insert 1K nodes
        println!("Inserting 1K nodes...");
        for i in 0..1_000 {
            backend
                .insert_node(NodeSpec {
                    kind: "TestNode".to_string(),
                    name: format!("node_{}", i),
                    file_path: None,
                    data: serde_json::json!({"id": i}),
                })
                .unwrap();
        }

        // Insert 5K edges
        println!("Inserting 5K edges...");
        for i in 0..5_000 {
            let from = (i % 1_000) as i64 + 1;
            let to = ((i * 7) % 1_000) as i64 + 1;
            if from != to {
                backend
                    .insert_edge(EdgeSpec {
                        from,
                        to,
                        edge_type: "TestEdge".to_string(),
                        data: serde_json::json!({}),
                    })
                    .unwrap();
            }
        }

        println!("Flushing...");
        backend.flush().unwrap();
    }

    // Print page ownership report
    println!("\n=== Page Ownership Report ===\n");
    sqlitegraph::backend::native::v3::forensics::print_page_ownership_report();

    println!("\n=== Page Ownership Map ===\n");
    sqlitegraph::backend::native::v3::forensics::print_page_ownership_map();

    // Check for conflicts
    let has_conflicts = sqlitegraph::backend::native::v3::forensics::has_page_conflicts();
    println!("\n=== Result ===");
    if has_conflicts {
        println!("❌ PAGE OWNERSHIP CONFLICTS DETECTED!");
        if let Some(conflict_page) =
            sqlitegraph::backend::native::v3::forensics::get_first_conflict_page()
        {
            println!("   First conflicting page: {}", conflict_page);
        }
    } else {
        println!("✓ No page ownership conflicts detected");
    }

    // Attempt to reopen
    println!("\n=== Attempting to reopen ===\n");
    match V3Backend::open(&db_path) {
        Ok(_) => {
            println!("✓ Database reopened successfully");
        }
        Err(e) => {
            println!("❌ Reopen failed: {}", e);

            // Scan the database file for corruption
            if let Ok(scan_report) =
                sqlitegraph::backend::native::v3::forensics::scan_database_pages(&db_path)
            {
                scan_report.print();
            }
        }
    }

    // Assert no conflicts (for now - this will likely fail until corruption is fixed)
    // assert!(!has_conflicts, "Page ownership conflicts detected");
}

#[test]
#[cfg(feature = "v3-forensics")]
fn test_v3_page_type_detection() {
    use sqlitegraph::backend::native::v3::forensics::PageType;

    println!("\n=== Testing page type detection ===\n");

    // Test NodePage detection
    let mut node_page_bytes = vec![0u8; 4096];
    node_page_bytes[0..8].copy_from_slice(&1u64.to_be_bytes());
    node_page_bytes[8..16].copy_from_slice(&0u64.to_be_bytes());
    node_page_bytes[16..18].copy_from_slice(&10u16.to_be_bytes());
    node_page_bytes[18..20].copy_from_slice(&512u16.to_be_bytes());

    let detected = PageType::detect_from_bytes(&node_page_bytes);
    println!("NodePage detection: {:?}", detected);
    assert_eq!(detected, PageType::Node);

    // Test B+Tree Leaf page detection
    let mut btree_bytes = vec![0u8; 4096];
    btree_bytes[0..8].copy_from_slice(&2u64.to_be_bytes());
    btree_bytes[8] = 1; // is_leaf
    btree_bytes[9] = 0; // is_root

    let detected = PageType::detect_from_bytes(&btree_bytes);
    println!("B+Tree Leaf detection: {:?}", detected);
    assert_eq!(detected, PageType::BTree);

    // Test B+Tree Internal page detection
    let mut btree_internal = vec![0u8; 4096];
    btree_internal[0..8].copy_from_slice(&3u64.to_be_bytes());
    btree_internal[8] = 0; // is_leaf (internal)
    btree_internal[9] = 0; // is_root

    let detected = PageType::detect_from_bytes(&btree_internal);
    println!("B+Tree Internal detection: {:?}", detected);
    assert_eq!(detected, PageType::BTree);
}