fault

package
v1.22.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package fault defines the fault primitives that rules execute when they fire. Each fault implements Apply(ctx); a non-nil error short-circuits the adapter's Action.Before chain and is delivered to the caller in the adapter's native error model.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrConnDrop = errors.New("chaotic: connection drop")

ErrConnDrop is the sentinel returned by ConnDrop's Apply. Each adapter detects this sentinel via errors.Is and substitutes its native connection-drop error (driver.ErrBadConn, status.Unavailable, etc.).

Functions

func ResetClock added in v1.22.0

func ResetClock(ctx context.Context)

ResetClock stores zero skew into the clock cell bound to ctx, undoing any skew a Clock fault has set (a mid-test reset). A no-op if no cell is bound.

func Skew added in v1.22.0

func Skew(ctx context.Context) time.Duration

Skew returns the wall-clock skew currently stored in the clock cell bound to ctx, or 0 if no cell is bound. Safe for concurrent use.

func WithClock added in v1.22.0

func WithClock(ctx context.Context) context.Context

WithClock binds a fresh, zero-skew clock cell to ctx and returns the child context. A Clock fault firing on this context writes its skew into the cell, and engine.Now reads it back. chaos.WithEngine calls this for you; call it directly only when using the engine without the chaos package.

Types

type Fault

type Fault interface {
	Apply(ctx context.Context) error
}

Fault is one chaos primitive. Apply may sleep, return an error, or panic. A return of nil means the fault completed without affecting the call.

func Clock added in v1.22.0

func Clock(d time.Duration) Fault

Clock returns a fault that, when it fires, sets the skew of the clock cell bound to the context to d, so subsequent engine.Now(ctx) reads observe a wall clock shifted by d. It injects no error and no sleep (Apply returns nil), so it composes with other faults in the same rule. If no clock cell is bound to the context, Apply is a no-op.

Example

ExampleClock shows that a Clock fault, once applied, sets the skew that fault.Skew (and engine.Now) read back from the context.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	ctx := fault.WithClock(context.Background())
	_ = fault.Clock(72 * time.Hour).Apply(ctx)
	fmt.Println(fault.Skew(ctx))
}
Output:
72h0m0s

func ConnDrop

func ConnDrop() Fault

ConnDrop returns ErrConnDrop. Each adapter detects this sentinel and substitutes its native connection-drop error.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	// ConnDrop returns a sentinel each adapter maps to its native
	// connection-drop error (driver.ErrBadConn, codes.Unavailable, ...).
	f := fault.ConnDrop()
	err := f.Apply(context.Background())
	fmt.Println(errors.Is(err, fault.ErrConnDrop))
}
Output:
true

func Error

func Error(err error) Fault

Error returns err verbatim from Apply. The adapter is responsible for wrapping it into its native error model (e.g., &url.Error{Op: "chaos"} for http). A nil err makes Apply a no-op.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	f := fault.Error(errors.New("upstream unavailable"))
	fmt.Println(f.Apply(context.Background()))
}
Output:
upstream unavailable

func HTTPStatus added in v1.7.0

func HTTPStatus(code int, body ...string) Fault

HTTPStatus returns a fault that makes the HTTP adapters render the given status code: adapter/httpsrv writes it, adapter/http synthesizes a response carrying it. Body is optional. When omitted the adapter uses http.StatusText.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	// HTTPStatus carries a status code on a sentinel the HTTP adapters render.
	err := fault.HTTPStatus(503, "overloaded").Apply(context.Background())
	var hse *fault.HTTPStatusError
	errors.As(err, &hse)
	fmt.Println(hse.StatusCode(), hse.Body)
}
Output:
503 overloaded

func HeaderInject added in v1.7.0

func HeaderInject(key, value string) Fault

HeaderInject returns a fault that sets header key to value on the headers flowing toward the code under test.

func HeaderStrip added in v1.7.0

func HeaderStrip(key string) Fault

HeaderStrip returns a fault that deletes header key from the headers flowing toward the code under test.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	// HeaderStrip yields a sentinel describing a header deletion; the adapters
	// apply it to the headers flowing toward the code under test.
	err := fault.HeaderStrip("X-Trace-Id").Apply(context.Background())
	var hf *fault.HeaderFault
	errors.As(err, &hf)
	fmt.Println(hf.Strip, hf.Key)
}
Output:
true X-Trace-Id

func Jittered

func Jittered(min, max time.Duration) Fault

Jittered sleeps for a uniformly random duration in [min, max]. Negative or zero values are treated as "no sleep". If max <= min, sleeps for min.

func JitteredSeed added in v1.4.0

func JitteredSeed(min, max time.Duration, seed int64) Fault

JitteredSeed is like Jittered but draws from a seeded PCG source, so the sequence of sleep durations is reproducible across runs with the same seed. Use it when a chaos test must be deterministically replayable. The draw is mutex-guarded. The fault is safe for concurrent use.

Example
package main

import (
	"context"
	"time"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	// JitteredSeed draws sleep durations from a seeded source, so a chaos test
	// replays the same delays across runs. No Output: the delays are time-based
	// and intentionally not printed.
	f := fault.JitteredSeed(10*time.Millisecond, 50*time.Millisecond, 42)
	_ = f.Apply(context.Background())
}

func Latency

func Latency(d time.Duration) Fault

Latency sleeps for d. Returns ctx.Err() if the context is canceled first. A non-positive d returns immediately.

Example (ContextCancellation)
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	// A canceled context makes a latency fault return immediately with the
	// context error instead of sleeping.
	ctx, cancel := context.WithCancel(context.Background())
	cancel()
	f := fault.Latency(time.Hour)
	fmt.Println(f.Apply(ctx))
}
Output:
context canceled

func Panic

func Panic(v any) Fault

Panic calls panic(v) from Apply. The panic propagates through the action, through the adapter, out to the caller. Recovery is the caller's responsibility.

Example
package main

import (
	"context"
	"fmt"

	"github.com/ag4r/chaotic/fault"
)

func main() {
	f := fault.Panic("boom")
	defer func() {
		fmt.Println("recovered:", recover())
	}()
	_ = f.Apply(context.Background())
}
Output:
recovered: boom

type HTTPStatusError added in v1.7.0

type HTTPStatusError struct {
	Code int
	Body string // empty => the adapter substitutes http.StatusText(Code)
}

HTTPStatusError is the sentinel an HTTPStatus fault returns. The HTTP adapters detect it via errors.As and render the status instead of the generic 500. The fault package stays free of net/http: this carries only the code and an optional body string.

func (*HTTPStatusError) Error added in v1.7.0

func (e *HTTPStatusError) Error() string

func (*HTTPStatusError) StatusCode added in v1.7.0

func (e *HTTPStatusError) StatusCode() int

StatusCode reports the HTTP status code the fault should render.

type HeaderFault added in v1.7.0

type HeaderFault struct {
	Strip bool // true => delete Key, false => set Key to Value
	Key   string
	Value string
}

HeaderFault is the sentinel a header fault returns. Adapters detect it via errors.As, apply the mutation to the headers flowing toward the code under test (request headers on the server, response headers on the client), then let the wrapped call proceed - it does NOT abort the call.

Because the engine fires at most one rule per Op and rule's fault chain short-circuits on the first sentinel, only one header fault applies per rule (a preceding Latency is fine, it returns nil and continues). To mutate several headers, use several rules, or wait for a future batch helper.

func (*HeaderFault) Error added in v1.7.0

func (*HeaderFault) Error() string

type Kind added in v1.4.0

type Kind int

Kind classifies a Fault for introspection (linting, observability). It does not affect behavior.

const (
	KindUnknown Kind = iota
	KindLatency
	KindJittered
	KindError
	KindPanic
	KindConnDrop
	KindHTTPStatus
	KindHeader
	KindClock
)

Fault kinds, one per built-in fault type.

func KindOf added in v1.4.0

func KindOf(f Fault) Kind

KindOf returns f's Kind, or KindUnknown for a custom fault that does not implement Kinded.

type Kinded added in v1.4.0

type Kinded interface {
	Kind() Kind
}

Kinded is implemented by every built-in fault so tools can classify it without type-switching on unexported types.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL