Skip to main content

nodedb_types/fail_point/
macros.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! The `fail_point!` and `fail_point_err!` injection macros.
4//!
5//! Each takes the scope the point is evaluated in as its first argument. A
6//! call site with a node identity passes `FailScope::Node(id)`. The form
7//! without a scope evaluates in `FailScope::Any`, for code with no node
8//! identity. Without the calling crate's `failpoints` feature, a scoped form
9//! only type-checks its scope and evaluates no name.
10
11/// Inject a fail point. Does nothing at runtime without the `failpoints`
12/// feature.
13///
14/// Usage in production code:
15///   `nodedb_types::fail_point!(scope, "calvin_static::during_overlay_stage");`
16///   `nodedb_types::fail_point!("wal::roll_before_seal");` (no node identity)
17///
18/// Tests opt in by enabling the feature and arming actions:
19///   `FailGuard::for_node(node_id, "calvin_static::during_overlay_stage",
20///                        FailAction::Panic);`
21#[macro_export]
22macro_rules! fail_point {
23    ($name:expr) => {
24        #[cfg(feature = "failpoints")]
25        $crate::fail_point::eval($crate::fail_point::FailScope::Any, $name);
26    };
27    ($scope:expr, $name:expr) => {
28        #[cfg(feature = "failpoints")]
29        $crate::fail_point::eval($scope, $name);
30        #[cfg(not(feature = "failpoints"))]
31        let _: $crate::fail_point::FailScope = $scope;
32    };
33}
34
35/// Inject a fail point that can abort the enclosing function with an error.
36///
37/// `$map` receives the detail string armed with `FailAction::Fail` and
38/// returns the error value to propagate, so each crate injects its own error
39/// type without the framework knowing about it:
40///
41/// ```ignore
42/// fail_point_err!("wal::flush_out_of_space", |_| WalError::OutOfSpace {
43///     context: "WAL segment append (failpoint)",
44/// });
45/// fail_point_err!(FailScope::Node(node_id), "cut_floor::before_persist", |detail| {
46///     Error::Internal { detail }
47/// });
48/// ```
49///
50/// Does nothing at runtime without the `failpoints` feature.
51#[macro_export]
52macro_rules! fail_point_err {
53    ($name:expr, $map:expr) => {
54        #[cfg(feature = "failpoints")]
55        if let Some(detail) =
56            $crate::fail_point::eval_fail($crate::fail_point::FailScope::Any, $name)
57        {
58            return Err(($map)(detail));
59        }
60    };
61    ($scope:expr, $name:expr, $map:expr) => {
62        #[cfg(feature = "failpoints")]
63        if let Some(detail) = $crate::fail_point::eval_fail($scope, $name) {
64            return Err(($map)(detail));
65        }
66        #[cfg(not(feature = "failpoints"))]
67        let _: $crate::fail_point::FailScope = $scope;
68    };
69}