relay-knowledge 1.1.14

Graph-database-based knowledge graph project.
Documentation
use rusqlite::Connection;

use crate::{
    domain::{CodeIndexResourceBudget, CodeRepositoryRegistration},
    storage::StorageError,
    storage::sqlite::code::{
        code_tests::{
            retarget_snapshot_scope, retarget_snapshot_to_fact_scope, snapshot_with_chunk,
        },
        initialize_code_schema,
        lifecycle::status::upsert_repository,
    },
};

use super::super::apply_snapshot;
use super::{
    require_fresh_full_snapshot_within_budget, require_incremental_snapshot_within_budget,
};

#[test]
fn zero_reference_snapshot_cannot_bypass_the_all_surface_row_budget() {
    let mut connection = Connection::open_in_memory().expect("database should open");
    initialize_code_schema(&connection).expect("schema should initialize");
    let transaction = connection.transaction().expect("transaction should begin");
    let snapshot = snapshot_with_chunk("repo", "src/lib.rs", "fn bounded() {}");
    assert!(snapshot.references.is_empty());
    let budget =
        CodeIndexResourceBudget::new(1, 1_000_000, 3).expect("test budget should validate");

    let error = require_fresh_full_snapshot_within_budget(&transaction, &snapshot, budget)
        .expect_err("files, symbols, chunks, and search ownership must share one row budget");

    assert!(matches!(error, StorageError::CapacityExceeded(_)));
}

#[test]
fn existing_scope_reservation_requires_durable_staging() {
    let mut connection = Connection::open_in_memory().expect("database should open");
    initialize_code_schema(&connection).expect("schema should initialize");
    register_repository(&mut connection);
    let snapshot = snapshot_with_chunk("repo", "src/lib.rs", "fn bounded() {}");
    apply_snapshot(&mut connection, snapshot.clone()).expect("initial scope should publish");
    let transaction = connection.transaction().expect("transaction should begin");

    let error = require_fresh_full_snapshot_within_budget(
        &transaction,
        &snapshot,
        CodeIndexResourceBudget::default(),
    )
    .expect_err("an existing scope must never enter direct replacement cleanup");

    assert!(matches!(error, StorageError::DurableStagingRequired(_)));
}

#[test]
fn existing_checkpoint_reservation_requires_durable_staging() {
    let mut connection = Connection::open_in_memory().expect("database should open");
    initialize_code_schema(&connection).expect("schema should initialize");
    register_repository(&mut connection);
    connection
        .execute(
            "INSERT INTO code_repository_index_checkpoints (
                 source_scope, repository_id, state, resolved_commit_sha, tree_hash,
                 path_filters_json, language_filters_json, total_path_count,
                 parsed_file_count, committed_file_count, committed_symbol_count,
                 committed_reference_count, committed_chunk_count, batch_count,
                 last_path, resource_budget_json, updated_at_ms, error_message
             ) VALUES (
                 'reserved', 'repo', 'indexing', 'commit', 'tree', '[]', '[]',
                 0, 0, 0, 0, 0, 0, 0, NULL,
                 '{\"max_files_per_batch\":1,\"max_bytes_per_batch\":1,\"max_rows_per_batch\":1}',
                 1, NULL
             )",
            [],
        )
        .expect("checkpoint reservation should insert");
    let mut snapshot = snapshot_with_chunk("repo", "src/lib.rs", "fn bounded() {}");
    retarget_snapshot_scope(&mut snapshot, "reserved");
    let transaction = connection.transaction().expect("transaction should begin");

    let error = require_fresh_full_snapshot_within_budget(
        &transaction,
        &snapshot,
        CodeIndexResourceBudget::default(),
    )
    .expect_err("an existing checkpoint must reserve its scope from direct publication");

    assert!(matches!(error, StorageError::DurableStagingRequired(_)));
}

#[test]
fn incremental_base_surface_over_budget_requires_staging_before_target_writes() {
    let mut connection = Connection::open_in_memory().expect("database should open");
    initialize_code_schema(&connection).expect("schema should initialize");
    register_repository(&mut connection);
    let mut base = snapshot_with_chunk("repo", "src/lib.rs", "fn bounded() {}");
    base.resolved_commit_sha = "base-commit".to_owned();
    base.tree_hash = "base-tree".to_owned();
    retarget_snapshot_to_fact_scope(&mut base);
    let mut incremental = base.clone();
    apply_snapshot(&mut connection, base).expect("base snapshot should publish");

    incremental.base_resolved_commit_sha = Some("base-commit".to_owned());
    incremental.resolved_commit_sha = "next-commit".to_owned();
    incremental.tree_hash = "next-tree".to_owned();
    incremental.full_replace = false;
    incremental.changed_path_count = 0;
    incremental.skipped_unchanged_count = 1;
    retarget_snapshot_to_fact_scope(&mut incremental);
    let target_scope = incremental.source_scope.clone();
    incremental.files.clear();
    incremental.symbols.clear();
    incremental.references.clear();
    incremental.imports.clear();
    incremental.calls.clear();
    incremental.dependencies.clear();
    incremental.feature_flags.clear();
    incremental.routes.clear();
    incremental.chunks.clear();
    incremental.workspaces.clear();
    incremental.diagnostics.clear();
    incremental.tombstones.clear();

    let transaction = connection.transaction().expect("transaction should begin");
    let error = require_incremental_snapshot_within_budget(
        &transaction,
        &incremental,
        CodeIndexResourceBudget::new(1, 1024 * 1024, 8).expect("test budget should validate"),
    )
    .expect_err("the cloned base cannot exceed the same writer quantum as the delta");
    assert!(matches!(error, StorageError::DurableStagingRequired(_)));
    transaction
        .rollback()
        .expect("read-only admission transaction should roll back");

    let target_rows = connection
        .query_row(
            "SELECT
                 (SELECT COUNT(*) FROM code_repository_scopes WHERE source_scope = ?1)
               + (SELECT COUNT(*) FROM code_repository_files WHERE source_scope = ?1)
               + (SELECT COUNT(*) FROM code_repository_search_metadata WHERE source_scope = ?1)",
            [target_scope],
            |row| row.get::<_, usize>(0),
        )
        .expect("target row count should load");
    assert_eq!(target_rows, 0);
}

fn register_repository(connection: &mut Connection) {
    upsert_repository(
        connection,
        CodeRepositoryRegistration::new("repo", "fixture", "/tmp/repo", Vec::new(), Vec::new())
            .expect("registration should validate"),
    )
    .expect("repository should persist");
}