Skip to documentation
SLOP

tiny.tripwire.failpoint

Reference tiny.tripwire failpoint

Defined in tiny.tripwire.

API (1)

Actions

Public operations.

No direct callersNo direct callstiny.tripwirefailpoint
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/tripwire/src/failpoint.zig

zig
const std = @import("std");const builtin = @import("builtin");const assert = std.debug.assert;const testing = std.testing;fn TripwireType(comptime Error: type) type {    return struct {        err: Error,        reached: usize = 0,        min: usize = 0,        tripped: bool = false,    };}/// Creates a failpoint module at compile time for the failpoint enum `P` and/// the error specification `E`: the namespace that holds one group of named/// check sites.////// - `P` is an enum whose fields name the check sites./// - `E` is one of four things: an error set type such as `anyerror` or///   `error{...}`, an error union type such as `E!T`, a function type whose///   return is an error union such as `fn (...) E!T`, or a function value that///   declares such a return. An error value such as `error.OutOfMemory` does///   not work as `E`, because the error set case hands `E` straight back and///   the result has to be a type.////// Every caller naming the same `P` and `E` shares one state map, which belongs/// to the returned type, so no instance of the returned type carries the state./// Nothing synchronizes the state across threads.pub fn module(    comptime P: type,    comptime E: anytype,) type {    return struct {        /// The enum type whose tags name the check sites of this failpoint        /// module, named here so a caller can write out the type that other        /// functions take.        pub const FailPoint: type = P;        /// The error set read out of the error specification at compile time,        /// which `check` returns so a caller can match an enclosing function's        /// error set against it.        pub const Error: type = err: {            const T = if (@TypeOf(E) == type) E else @TypeOf(E);            break :err switch (@typeInfo(T)) {                .error_set => E,                .error_union => |info| info.error_set,                .@"fn" => |info| @typeInfo(info.return_type.?).error_union.error_set,                else => @compileError("E must be an error set or function type"),            };        };        /// The compile-time flag that turns the checks on, true in a test build        /// and false everywhere else.        pub const enabled = builtin.is_test;        comptime {            assert(@typeInfo(FailPoint) == .@"enum");            assert(@typeInfo(Error) == .error_set);        }        var tripwires: TripwireMap = .{};        const TripwireMap: type = std.EnumMap(FailPoint, Tripwire);        const Tripwire: type = TripwireType(Error);        /// Evaluates the check site named by `point` inside an operation where        /// a simulated error should arrive, so a test can drive the error path        /// that a successful run leaves alone.        ///        /// - Where `enabled` is false, meaning `builtin.is_test == false`, the        ///   call is an inlined no-op that returns `void`.        /// - In a test build, the call returns `void` when `point` has no        ///   configuration or while the visit count stands at or below the        ///   threshold. Once the visit count passes the threshold, the site is        ///   marked tripped and the configured error is returned. The error        ///   comes back on every later visit as well, as long as the visit        ///   count stays inside `usize` range.        pub fn check(point: FailPoint) callconv(callingConvention()) Error!void {            if (comptime !enabled) return;            return checkConstrained(point, Error);        }        /// Evaluates the check site named by `point` and returns an error typed        /// as `ConstrainedError`, letting the check sit inside a function whose        /// declared error set is wider than the module's own.        ///        /// - Where `enabled` is false, the call is an inlined no-op that        ///   returns `void`.        /// - In a test build, it follows the same visit count and threshold        ///   rules as `check`.        /// - The typing requirement in a test build comes from the body: it        ///   runs `return tripwire.err;`, and that value has type `Error`. Zig        ///   coerces an error set only into a set that holds it, so        ///   `ConstrainedError` has to be `Error` or a superset of `Error`.        pub fn checkConstrained(            point: FailPoint,            comptime ConstrainedError: type,        ) callconv(callingConvention()) ConstrainedError!void {            if (comptime !enabled) return;            const tripwire = tripwires.getPtr(point) orelse return;            tripwire.reached += 1;            if (tripwire.reached <= tripwire.min) return;            tripwire.tripped = true;            return tripwire.err;        }        /// Provides the one-line setup for a test that wants the site to fail        /// the first time an operation reaches it, configuring `point` to        /// deliver `err` on its first visit, which is a threshold of 0. The        /// call replaces whatever configuration `point` already had, putting        /// the visit count back to 0 and the trip flag back to false. In a test        /// build, later calls to `check(point)` follow the visit count rules        /// written on `check`.        pub fn errorAlways(point: FailPoint, err: Error) void {            errorAfter(point, err, 0);        }        /// Lets earlier visits through when an operation reaches the same site        /// more than once before reaching the state the test targets, for        /// example while parsing earlier records or running earlier loop        /// iterations. The function configures `point` to pass its first `min`        /// visits and to deliver `err` on visit `min + 1` and on every visit        /// after that. This registration replaces whatever configuration        /// `point` already had, putting the visit count back to 0 and the trip        /// flag back to false. In a test build, later calls to `check(point)`        /// follow the visit count rules written on `check`.        pub fn errorAfter(point: FailPoint, err: Error, min: usize) void {            tripwires.put(point, .{ .err = err, .min = min });        }        /// Settles whether a test reached its configured sites, because a        /// passing test proves its error path only once the site is known to        /// have been reached. The function verifies that every configured site        /// in the failpoint module was visited past its threshold and tripped.        ///        /// - With no site configured, it succeeds at once.        /// - With any configured site still untripped, it returns        ///   `error.UntrippedError`.        /// - Under `.reset`, it clears every configured site, including on the        ///   run that returns the error.        /// - Under `.retain`, it keeps the registrations and the counters, so        ///   the trip flags stay set and a later call passes with no further        ///   visits in between.        ///        /// The call proves that the configured error was delivered at the check        /// site. Whether the caller caught the error, ran its cleanup, or held        /// its domain invariants is left to the test's own assertions.        pub fn end(reset_mode: enum { reset, retain }) error{UntrippedError}!void {            var untripped = false;            var iter = tripwires.iterator();            while (iter.next()) |entry| {                if (!entry.value.tripped) {                    untripped = true;                }            }            switch (reset_mode) {                .reset => reset(),                .retain => {},            }            if (untripped) return error.UntrippedError;        }        /// Clears every failpoint registration and the counters behind them. A        /// test calls it before it starts and again on the way out, because        /// that state belongs to the type and outlives any one test.        pub fn reset() void {            tripwires = .{};        }        fn callingConvention() std.builtin.CallingConvention {            return if (!enabled) .@"inline" else .auto;        }    };}const TestFailPoint = enum {    anonymous_read,    anonymous_write,};fn test_error_function() error{ Foo, Bar }!void {    return error.Foo;}test {    const io = module(TestFailPoint, anyerror);    io.reset();    defer io.reset();    try io.end(.reset);    try io.check(.anonymous_read);    io.errorAlways(.anonymous_read, error.OutOfMemory);    try testing.expectError(error.OutOfMemory, io.check(.anonymous_read));    try testing.expectError(error.OutOfMemory, io.check(.anonymous_read));    try io.end(.reset);}test "module as error set" {    const io = module(enum { error_set_read, error_set_write }, @TypeOf(test_error_function));    io.reset();    defer io.reset();    try io.end(.reset);}test "errorAfter" {    const io = module(enum { after_read, after_write }, anyerror);    io.reset();    defer io.reset();    io.errorAfter(.after_read, error.OutOfMemory, 2);    try io.check(.after_read);    try io.check(.after_read);    try testing.expectError(error.OutOfMemory, io.check(.after_read));    try testing.expectError(error.OutOfMemory, io.check(.after_read));    try io.end(.reset);}test "errorAfter reports untripped expectations" {    const io = module(enum { untripped_read }, anyerror);    io.reset();    defer io.reset();    io.errorAfter(.untripped_read, error.OutOfMemory, 2);    try io.check(.untripped_read);    try testing.expectError(error.UntrippedError, io.end(.reset));}

Source: lib/tripwire/src/root.zig:308

zig
/// The implementation of the package, holding the generic constructor and the/// runtime logic behind every check site.pub const failpoint = @import("failpoint.zig");

Audit

Definitions1
Public names1
Members0
Version26.7.0
Revisiondaab053ee433