Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/components/kvstore/test/gtest/src/   (Firefox Browser Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 8 kB image not shown  

Quelle  store.rs

  Sprache: Rust
 

/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */


use std::{convert::Infallible, fmt, sync::Arc, time::Duration};

use kvstore::skv::{
    checker::{CheckerAction, IntoChecker},
    connection::{ConnectionIncidents, ConnectionMaintenanceTask},
    store::{Store, StoreError, StorePath},
};

use crate::latch::CountDownLatch;

pub fn under_maintenance() {
    static READY: CountDownLatch = CountDownLatch::new(1);
    static DONE: CountDownLatch = CountDownLatch::new(1);

    struct Checker;

    impl IntoChecker<Checker> for ConnectionIncidents<'_> {
        fn into_checker(self) -> CheckerAction<Checker> {
            CheckerAction::Check(Checker)
        }
    }

    impl ConnectionMaintenanceTask for Checker {
        type Error = Infallible;

        fn run(self, _conn: &mut rusqlite::Connection) -> Result<(), Self::Error> {
            // Tell the main thread that we've started the checker.
            READY.count_down();
            // Wait to return until the main thread tells us to wrap up.
            assert!(
                DONE.wait_timeout(Duration::from_secs(5)),
                "timed out waiting for checker to finish"
            );
            Ok(())
        }
    }

    let store = Arc::new(Store::new(StorePath::for_in_memory()));
    let thread = {
        let store = store.clone();
        std::thread::spawn(move || {
            // This should start the checker, wait, and return once the
            // main thread advances the phase to `Finished`.
            assert!(store.check::<Checker>().is_ok(), "check should succeed");
        })
    };
    // Wait for the spawned thread to start the checker, so that
    // its `check()` call doesn't race with ours.
    assert!(
        READY.wait_timeout(Duration::from_secs(5)),
        "timed out waiting for checker to start"
    );
    assert!(
        matches!(store.check::<Checker>(), Err(StoreError::Busy)),
        "check during maintenance should fail"
    );
    // Advance the phase to unblock the spawned thread, then
    // wait for its `check()` call to return.
    DONE.count_down();
    thread.join().unwrap();
    store.close();
}

pub fn close_during_maintenance() {
    static READY: CountDownLatch = CountDownLatch::new(1);

    struct Checker;

    impl IntoChecker<Checker> for ConnectionIncidents<'_> {
        fn into_checker(self) -> CheckerAction<Checker> {
            CheckerAction::Check(Checker)
        }
    }

    impl ConnectionMaintenanceTask for Checker {
        type Error = rusqlite::Error;

        fn run(self, conn: &mut rusqlite::Connection) -> Result<(), Self::Error> {
            // Tell the main thread that we've started the checker.
            READY.count_down();
            // Start a query that will run forever, until
            // interrupted by `close()`.
            conn.execute(
                "WITH RECURSIVE x(i) AS (
                   SELECT 1
                   UNION ALL
                   SELECT i + 1 FROM x
                 )
                 SELECT i FROM x",
                [],
            )?;
            unreachable!("query should never return")
        }
    }

    let store = Arc::new(Store::new(StorePath::for_in_memory()));
    let thread = {
        let store = store.clone();
        std::thread::spawn(move || {
            assert!(
                matches!(store.check::<Checker>(), Err(StoreError::Maintenance(_))),
                "interrupted check should fail"
            );
        })
    };
    assert!(
        READY.wait_timeout(Duration::from_secs(5)),
        "timed out waiting for checker to start"
    );
    store.close();
    assert!(
        matches!(store.check::<Checker>(), Err(StoreError::Closed)),
        "check on closed store should fail"
    );
    thread.join().unwrap();
}

pub fn maintenance_succeeds() {
    struct Checker;

    impl IntoChecker<Checker> for ConnectionIncidents<'_> {
        fn into_checker(self) -> CheckerAction<Checker> {
            CheckerAction::Check(Checker)
        }
    }

    impl ConnectionMaintenanceTask for Checker {
        type Error = Infallible;

        fn run(self, _conn: &mut rusqlite::Connection) -> Result<(), Self::Error> {
            Ok(())
        }
    }

    let store = Store::new(StorePath::for_in_memory());
    assert!(store.check::<Checker>().is_ok(), "check should succeed");
    store.close();
}

pub fn maintenance_fails() {
    struct Checker;

    impl IntoChecker<Checker> for ConnectionIncidents<'_> {
        fn into_checker(self) -> CheckerAction<Checker> {
            CheckerAction::Check(Checker)
        }
    }

    impl ConnectionMaintenanceTask for Checker {
        type Error = CheckerError;

        fn run(self, _conn: &mut rusqlite::Connection) -> Result<(), Self::Error> {
            Err(CheckerError)
        }
    }

    #[derive(Debug)]
    struct CheckerError;
    impl std::error::Error for CheckerError {}

    impl fmt::Display for CheckerError {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str("mercury in retrograde")
        }
    }

    let store = Store::new(StorePath::for_in_memory());
    assert!(
        matches!(store.check::<Checker>(), Err(StoreError::Maintenance(_))),
        "check should fail"
    );
    store.close();
}

pub fn renames_corrupt_database_file() {
    struct SucceedingChecker;

    impl IntoChecker<SucceedingChecker> for ConnectionIncidents<'_> {
        fn into_checker(self) -> CheckerAction<SucceedingChecker> {
            CheckerAction::Check(SucceedingChecker)
        }
    }

    impl ConnectionMaintenanceTask for SucceedingChecker {
        type Error = Infallible;

        fn run(self, _conn: &mut rusqlite::Connection) -> Result<(), Self::Error> {
            Ok(())
        }
    }

    struct FailingChecker;

    impl IntoChecker<FailingChecker> for ConnectionIncidents<'_> {
        fn into_checker(self) -> CheckerAction<FailingChecker> {
            CheckerAction::Check(FailingChecker)
        }
    }

    impl ConnectionMaintenanceTask for FailingChecker {
        type Error = CheckerError;

        fn run(self, _conn: &mut rusqlite::Connection) -> Result<(), Self::Error> {
            Err(CheckerError)
        }
    }

    #[derive(Debug)]
    struct CheckerError;
    impl std::error::Error for CheckerError {}

    impl fmt::Display for CheckerError {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str("mercury in retrograde")
        }
    }

    // Make a temporary copy of our (non-empty, valid) fixture database file.
    let fixture_file_path = std::env::current_dir()
        .expect("current dir")
        .join("kvstore-ok.sqlite");
    let storage_dir = tempfile::tempdir().expect("should create storage dir");
    let file_path = storage_dir.path().join("kvstore-ok.sqlite");
    std::fs::copy(fixture_file_path, file_path.as_path())
        .expect("should copy database fixture file to storage dir");

    // Simulate a failing check.
    let store = Arc::new(Store::new(StorePath::OnDisk(file_path.clone())));
    assert!(
        matches!(
            store.check::<FailingChecker>(),
            Err(StoreError::Maintenance(_))
        ),
        "failing checker should fail"
    );
    store.close();

    // Make sure that we backed up the "corrupt" database, and all its
    // temporary files.
    let files = std::fs::read_dir(storage_dir.path())
        .unwrap()
        .map(|result| result.map(|entry| entry.file_name()))
        .collect::<Result<Vec<_>, _>>()
        .expect("should collect files in storage dir");
    assert!(
        files.iter().all(|f| f
            .to_string_lossy()
            .starts_with("kvstore-ok.sqlite.corrupt-")),
        "should rename corrupt database file"
    );

    // Reopening the store should create a fresh database.
    let store = Arc::new(Store::new(StorePath::OnDisk(file_path)));
    assert!(
        store.check::<SucceedingChecker>().is_ok(),
        "succeeding checker should succeed"
    );
    assert!(
        matches!(
            store
                .writer()
                .and_then(|writer| writer.read(|conn| Ok(conn.query_row(
                    "SELECT count(*) FROM dbs",
                    [],
                    |row| row.get::<_, usize>(0)
                )?))),
            Ok(0)
        ),
        "should recreate empty database file"
    );

    store.close();
}

Messung V0.5 in Prozent
C=95 H=100 G=97

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet am  2026-06-18) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.