Documentation
¶
Overview ¶
Example ¶
package main
import (
"context"
"fmt"
"go.llib.dev/testcase/faultinject"
)
type FaultTag struct{}
func main() {
defer faultinject.Enable()()
ctx := context.Background()
fmt.Println(ctx.Err()) // no error as expected
// arrange one fault injection for FaultTag
ctx = faultinject.Inject(ctx, FaultTag{}, fmt.Errorf("example error to inject"))
if err, ok := ctx.Value(FaultTag{}).(error); ok {
fmt.Println(err) // prints the injected error
}
if err, ok := ctx.Value(FaultTag{}).(error); ok {
fmt.Println(err) // code not reached as injectedFault is already consumed
}
}
Example (ChaosEngineeringWithExplicitFaultPoints) ¶
package main
import (
"context"
"errors"
"fmt"
"go.llib.dev/testcase/faultinject"
)
type FaultTag struct{}
func main() {
defer faultinject.Enable()()
ctx := context.Background()
fmt.Println(MyFuncWithChaosEngineeringFaultPoints(ctx)) // no error
ctx = faultinject.Inject(ctx, FaultTag{}, errors.New("boom")) // arrange fault injection for FaultTag
fmt.Println(MyFuncWithChaosEngineeringFaultPoints(ctx)) // "boom" is returned
}
func MyFuncWithChaosEngineeringFaultPoints(ctx context.Context) error {
if err, ok := ctx.Value(FaultTag{}).(error); ok {
return err
}
if err := ctx.Err(); err != nil {
return err
}
return nil
}
Example (FaultInjectWithFixErrorReplyFromTheFaultPoint) ¶
package main
import (
"context"
"errors"
"fmt"
"go.llib.dev/testcase/faultinject"
)
type FaultTag struct{}
func main() {
defer faultinject.Enable()()
ctx := context.Background()
ctx = faultinject.Inject(ctx, FaultTag{}, errors.New("ignored"))
fmt.Println(MyFuncWithFixErrorReplyFromTheFaultPoin(ctx)) // error is returned
}
func MyFuncWithFixErrorReplyFromTheFaultPoin(ctx context.Context) error {
if _, ok := ctx.Value(FaultTag{}).(error); ok {
return errors.New("my error value")
}
return nil
}
Index ¶
- Constants
- Variables
- func After(returnErr *error, ctx context.Context, faults ...any)
- func Check(ctx context.Context, faults ...any) error
- func Enable() (Disable func())
- func EnableForTest(tb testingTB)
- func Enabled() bool
- func Finish(returnErr *error, ctx context.Context, faults ...any)deprecated
- func Inject(ctx context.Context, fault any, err error) context.Context
- type CallerFault
Examples ¶
Constants ¶
const DefaultErr errT = "fault injected"
Variables ¶
var WaitForContextDoneTimeout = time.Second / 2
Functions ¶
func After ¶
After is function that can be called from a deferred context, and will inject fault after the function finished its execution. The error pointer should point to the function's named return error variable. If the function encountered an actual error, fault injection is skipped. It is safe to use from production code.
Example ¶
package main
import (
"context"
"fmt"
"go.llib.dev/testcase/faultinject"
)
func main() {
type fault struct{}
ctx := faultinject.Inject(context.Background(), fault{}, fmt.Errorf("boom"))
_ = func(ctx context.Context) (returnErr error) {
defer faultinject.After(&returnErr, ctx, fault{})
return nil
}(ctx)
}
func Check ¶
Check is a fault-injection helper method which check if there is an injected fault(s) in the given context. It checks for errors injected as context value, or ensures to trigger a CallerFault. It is safe to use from production code.
Example ¶
package main
import (
"context"
"go.llib.dev/testcase/faultinject"
)
func main() {
type FaultName struct{}
ctx := context.Background()
if err := faultinject.Check(ctx, FaultName{}); err != nil {
return // err
}
}
func EnableForTest ¶
func EnableForTest(tb testingTB)
func Finish
deprecated
Finish is an alias for After
Deprecated: use After instead
Example ¶
package main
import (
"context"
"go.llib.dev/testcase/faultinject"
)
func main() {
type FaultName struct{}
ctx := context.Background()
_ = func(ctx context.Context) (rErr error) {
defer faultinject.After(&rErr, ctx, FaultName{})
return nil
}(ctx)
}
func Inject ¶
Inject will arrange context to trigger fault injection for the provided fault.
Example (ByTargetingCaller) ¶
package main
import (
"context"
"errors"
"fmt"
"go.llib.dev/testcase/faultinject"
)
func main() {
ctx := faultinject.Inject(
context.Background(),
faultinject.CallerFault{
Package: "", // empty will match everything
Receiver: "", //
Function: "", //
},
errors.New("boom"),
)
fmt.Println(ctx.Err()) // "boom"
}
Types ¶
type CallerFault ¶
CallerFault allows you to inject Fault by Caller stack position.
Example ¶
package main
import (
"context"
"fmt"
"go.llib.dev/testcase/faultinject"
"go.llib.dev/testcase/random"
)
func main() {
defer faultinject.Enable()()
ctx := context.Background()
fmt.Println(MyFuncWithStandardContextErrCheck(ctx)) // no error
fault := faultinject.CallerFault{ // inject Fault that targets a specific context Err check
Function: "MyFuncWithStandardContextErrCheck", // selector to tell where to inject
}
err := random.New(random.CryptoSeed{}).Error()
ctx = faultinject.Inject(ctx, fault, err) // some random error)
fmt.Println(MyFuncWithStandardContextErrCheck(ctx)) // Fault.Error injected and returned
}
func MyFuncWithStandardContextErrCheck(ctx context.Context) error {
if err := ctx.Err(); err != nil {
return err
}
return nil
}