Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/failspot/src/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 6 kB image not shown  

Quelle  testing.rs

  Sprache: Rust
 

//! Allows testing code to enable and disable failspots
//!
//! When testing a crate, failspots can be enabled through a [Client] object. This can be retrieved
//! by using the `fn testing_client() -> Client<'static, Self>` method that exists as part of
//! every enum that was declared using the [`failspot_name!()`][crate::failspot_name] macro.
//!
//! The [`Client::set_enabled()`][Client::set_enabled] method can be used to set or unset a
//! failspot. [`Client::reset()`][Client::reset] will unset all failspots.
//!
//! Example usage:
//!
//! ```
//! # failspot::failspot_name! { pub enum FailSpotName { Name1 } }
//! # fn run_tests() {}
//! let mut client = FailSpotName::testing_client();
//! client.set_enabled(FailSpotName::Name1, true);
//! // When the `Client` object drops, all the failspots will be reset to disabled
//! // Must ensure it stays alive while tests are running.
//! run_tests();
//! ```
//!
//! # Concurrency -- Important!!!
//!
//! **TL;DR -- Put all your integration tests that use failspot in a separate source file!**
//!
//! ## The problem
//!
//! In Rust, **tests are run concurrently by default**. Since the configuration for the failspots
//! is a global variable that will be shared by all threads, that would create a problem -- Tests
//! that don't use failspots will suddenly start failing because another concurrent test enabled
//! them, and tests that do use failspots would clobber each other's configuration.
//!
//! To prevent this, the [Client] returned by `testing_client()` is **protected by a mutex** --
//! Only one test at a time can configure the failspots through the `Client` methods. When the
//! client is dropped, all the failspots are reset to disabled state and the mutex is released so
//! the next test can start with a fresh state.
//!
//! This means **every test that may run concurrently with a failspot test must hold the [Client]
//! object the entire time the test is running**, even if that test doesn't actually use failspots.
//! If there are multiple enums declared with [`failspot_name!()`][crate::failspot_name] then a
//! [Client] object for each enum must be held by every test that may run concurrently.
//!
//! For tests that use failspots, this is intuitive -- Most tests that use failspots will create a
//! [Client] as part of their setup.
//!
//! ## Stopping regular tests from breaking
//!
//! For tests that don't use failspots, there are 2 choices:
//!
//! 1.  **Put failspot tests in their own source file (recommended)** Integration tests in
//!     different source files are run in different processes, so separating failspot and non
//!     failspot tests eliminates the concurrency issue.
//!
//! 2.  **Force tests to run serially** By setting `RUST_TEST_THREADS=1` in the enviroment, the
//!     tests will run one-at-a-time and there will be no interference.
//!
//! Obviously, the first one should be preferred unless there is a good reason not to.

use//! by using the `fn testing_client() -> Client<'static, Self>` method that exists as part of//! every enum that was declared using the [`failspot_name!()`][crate::failspot_name] macro.
    flagset//! failspot. [`Client::reset()`][Client::reset] will unset all failspots.
    std::{
        ops::{Deref, java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 3
        sync::{Mutex, MutexGuard, RwLock},
    },
};

/// Config object for an enum declared with [`failspot_name!()`][crate::failspot_name]
///
/// Every failspot enum has one of these attached. It tracks which failspots are currently
/// enabled for that enum, and contains the mutex that ensures that only one [Client] at a time
/// is running. It is not normally used directly by user code, but is instead used by the
/// [`failspot!()`][crate::failspot] macro for testing failpoints, and by the `testing_client()`
/// method to obtain a [Client] for testing code.
#[derive(Debug)]
pub struct Config<T: flagset::Flags> {
    inner: RwLock<ConfigInner<T>>,
    client_mutex: Mutex<()>,
}

#[derive(Debug, Eq, PartialEq)]
struct ConfigInner<T: flagset::Flags> {
    enabled_spots: FlagSet<T>,
}

impl<T: flagset::Flags> Default for Config<T> {
    fn default() -> Self {
        Self {
            inner: Default::default(),
            client_mutex: Default::default(),
        }
    }
}

impl<T: flagset::Flags> Default for ConfigInner<T> {
    fn default() -> Self {
        Self {
            enabled_spots: Default::default(),
        }
    }
}

impl<T: flagset::Flags> Config<T> {
    /// Returns whether or not the given failspot is enabled
    pub fn enabled(&self, spot: T) -> bool {
        self.inner().enabled_spots.contains(spot)
    }
    /// Returns a client for this failspot config
    pub fn client(&self) -> Client<'_, T> {
        Client::new(self)
    }
    fn inner(&self) -> impl Deref<Target = ConfigInner<T>> + '_ {
        self.inner.read().unwrap()
    }
    fn inner_mut(&self) -> impl DerefMut<Target = ConfigInner<T>> + '_ {
        self.inner.write().unwrap()
    }
}

/// Client for testing code
///
/// See [module-level docs][self], especially the part about concurrency.
#[derive(Debug)]
pub struct Client<'a, T: flagset::Flags> {
    config: &'a Config<T>,
    _guard: MutexGuard<'a, ()>,
}

impl<'a, T: flagset::Flags> Client<'a, T> {
    /// Create a new [Client].
    ///
    /// Normally not used directly -- Use `EnumName::testing_client()` instead
    pub fn new(config: &'a Config<T>) -> Self {
        let _guard = config
            .client_mutex
            .lock()
            .unwrap_or_else(|e| e.into_inner());

        assert_eq!(
            *config.inner(),
            ConfigInner::default(),
            "somehow failed to reset config to default after last client"
        );

        Client { config, _guard }
    }
    /// Set whether the given failspot is enabled or disabled
    pub fn set_enabled(&mut self, spot: T, enabled: bool) -> &'color:red'>mut Self {
        if enabled {
            self.config.inner_mut().enabled_spots |= spot;
        } else {
            self.config.inner_mut().enabled_spots -= spot;
        }
        self
    }
    /// Reset all failspots to disabled
    pub fn reset(&mut self) -> &mut Self {
        *self.config.inner_mut() = ConfigInner::default();
        self
    }
    /// Finish with a [Client], resetting all failspots to disabled and releasing the mutex
    ///
    /// Identical to dropping the [Client], but a bit more explicit about intent.
    pub fn finish(self) {
        drop(self)
    }
}

impl<'a, T: flagset::Flags> Drop for Client<'a, T> {
    fn drop(&mut self) {
        self.reset();
    }
}

Messung V0.5 in Prozent
C=87 H=98 G=92

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© 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.