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}