
Bibliothèque d'injection de fautes pour Go qui ajoute des failpoints contrôlables au runtime pour déclencher des panics, des mises en veille, des retours et des chemins d'erreur conditionnels via des variables d'environnement.
Une implémentation des failpoints pour Golang. Les failpoints sont utilisés pour ajouter des points de code où des erreurs peuvent être injectées de manière contrôlée par l'utilisateur. Un failpoint est un extrait de code qui n'est exécuté que lorsque le failpoint correspondant est actif.
failpoint-ctl)Compilez failpoint-ctl à partir des sources
git clone https://github.com/pingcap/failpoint.git
cd failpoint
make
ls bin/failpoint-ctl
Injectez des failpoints dans votre programme, par exemple :
package main
import "github.com/pingcap/failpoint"
func main() {
failpoint.Inject("testPanic", func() {
panic("failpoint triggerd")
})
}
Transformez votre code avec failpoint-ctl enable
Compilez avec go build
Activez les failpoints avec la variable d'environnement GO_FAILPOINTS
GO_FAILPOINTS="main/testPanic=return(true)" ./your-program
Remarque : GO_FAILPOINTS ne fonctionne pas avec le type de marqueur InjectCall.
Si vous utilisez go run pour exécuter le test, n'oubliez pas d'ajouter le fichier généré binding__failpoint_binding__.go à votre commande, par exemple :
GO_FAILPOINTS="main/testPanic=return(true)" go run your-program.go binding__failpoint_binding__.go
failpoint-toolexec)Compilez failpoint-toolexec à partir des sources
git clone https://github.com/pingcap/failpoint.git
cd failpoint
make
ls bin/failpoint-toolexec
Injectez des failpoints dans votre programme, par exemple :
package main
import "github.com/pingcap/failpoint"
func main() {
failpoint.Inject("testPanic", func() {
panic("failpoint triggerd")
})
}
Utilisez un cache de build séparé pour éviter de mélanger les caches sans failpoint-toolexec, et compilez
GOCACHE=/tmp/failpoint-cache go build -toolexec path/to/failpoint-toolexec
Activez les failpoints avec la variable d'environnement GO_FAILPOINTS
GO_FAILPOINTS="main/testPanic=return(true)" ./your-program
Vous pouvez aussi utiliser go run ou go test, par exemple :
GOCACHE=/tmp/failpoint-cache GO_FAILPOINTS="main/testPanic=return(true)" go run -toolexec path/to/failpoint-toolexec your-program.go
Définir le failpoint dans du code Golang valide, pas dans des commentaires ou autre chose
Un failpoint n'a aucun coût supplémentaire
Le code du failpoint est lisible/modifiable et doit être vérifié par un compilateur
Le code généré par la définition d'un failpoint est facile à lire
Conserve les numéros de ligne identiques aux codes d'injection (plus facile à déboguer)
Prend en charge les tests parallèles avec context.Context
Failpoint
Un failpoint est un extrait de code qui n'est exécuté que lorsque le failpoint correspondant est actif.
La fermeture ne sera jamais exécutée si failpoint.Disable("failpoint-name-for-demo") est exécuté.
var outerVar = "declare in outer scope"
failpoint.Inject("failpoint-name-for-demo", func(val failpoint.Value) {
fmt.Println("unit-test", val, outerVar)
})
Fonctions de marqueur
Ce n'est qu'une fonction vide
C'est facile à écrire/lire
Introduit une vérification par le compilateur pour les failpoints qui ne peuvent pas compiler en mode normal si le code du failpoint est invalide
Liste des fonctions de marqueur
func Inject(fpname string, fpblock func(val Value)) {}func InjectContext(fpname string, ctx context.Context, fpblock func(val Value)) {}func InjectCall(fpname string, args ...any) {}func Break(label ...string) {}func Goto(label string) {}func Continue(label ...string) {}func Fallthrough() {}func Return(results ...interface{}) {}func Label(label string) {}Variable d'environnement de failpoint prise en charge
Un failpoint peut être activé en exportant des variables d'environnement selon le modèle suivant, ce qui ressemble beaucoup aux variables SYSCTL du failpoint FreeBSD
Remarque : InjectCall ne peut pas être activé par des variables d'environnement.
[<percent>%][<count>*]<type>[(args...)][-><more terms>]
L'argument spécifie l'action à effectuer ; il peut être l'un des suivants :
Vous pouvez appeler failpoint.Inject pour injecter un failpoint au site d'appel, où failpoint-name est utilisé pour déclencher le failpoint et failpoint-closure sera développé comme corps de l'instruction IF.
failpoint.Inject("failpoint-name", func(val failpoint.Value) {
failpoint.Return("unit-test", val)
})
Le code converti ressemble à :
if val, _err_ := failpoint.Eval(_curpkg_("failpoint-name")); _err_ == nil {
return "unit-test", val
}
failpoint.Value est la valeur transmise par failpoint.Enable("failpoint-name", "return(5)"), qui peut être ignorée.
failpoint.Inject("failpoint-name", func(_ failpoint.Value) {
fmt.Println("unit-test")
})
OU
failpoint.Inject("failpoint-name", func() {
fmt.Println("unit-test")
})
Et le code converti ressemble à :
if _, _err_ := failpoint.Eval(_curpkg_("failpoint-name")); _err_ == nil {
fmt.Println("unit-test")
}