
مكتبة حقن أعطال للغة Go تضيف نقاط فشل قابلة للتحكم في وقت التشغيل لإحداث حالات panic، ونوم (sleeps)، وإرجاعات (returns)، ومسارات أخطاء شرطية عبر متغيرات البيئة.
تنفيذ لنقاط الفشل failpoints بلغة Golang. تُستخدم نقاط الفشل لإضافة نقاط في الكود يمكن عندها حقن الأخطاء بطريقة يتحكم بها المستخدم. نقطة الفشل هي مقتطف برمجي لا يُنفَّذ إلا عندما تكون نقطة الفشل المقابلة نشطة.
failpoint-ctl)ابنِ failpoint-ctl من المصدر
git clone https://github.com/pingcap/failpoint.git
cd failpoint
make
ls bin/failpoint-ctl
احقن نقاط الفشل في برنامجك، مثال:
package main
import "github.com/pingcap/failpoint"
func main() {
failpoint.Inject("testPanic", func() {
panic("failpoint triggerd")
})
}
حوّل الكود الخاص بك باستخدام failpoint-ctl enable
ابنِ باستخدام go build
فعّل نقاط الفشل باستخدام متغير البيئة GO_FAILPOINTS
GO_FAILPOINTS="main/testPanic=return(true)" ./your-program
ملاحظة: GO_FAILPOINTS لا تعمل مع نوع العلامات InjectCall.
إذا كنت تستخدم go run لتشغيل الاختبار، لا تنسَ إضافة الملف المُولَّد binding__failpoint_binding__.go إلى أمرك، مثل:
GO_FAILPOINTS="main/testPanic=return(true)" go run your-program.go binding__failpoint_binding__.go
failpoint-toolexec)ابنِ failpoint-toolexec من المصدر
git clone https://github.com/pingcap/failpoint.git
cd failpoint
make
ls bin/failpoint-toolexec
احقن نقاط الفشل في برنامجك، مثال:
package main
import "github.com/pingcap/failpoint"
func main() {
failpoint.Inject("testPanic", func() {
panic("failpoint triggerd")
})
}
استخدم مخزنًا مؤقتًا منفصلاً للبناء لتجنب خلط المخزونات بدون failpoint-toolexec، ثم ابنِ
GOCACHE=/tmp/failpoint-cache go build -toolexec path/to/failpoint-toolexec
فعّل نقاط الفشل باستخدام متغير البيئة GO_FAILPOINTS
GO_FAILPOINTS="main/testPanic=return(true)" ./your-program
يمكنك أيضًا استخدام go run أو go test، مثل:
GOCACHE=/tmp/failpoint-cache GO_FAILPOINTS="main/testPanic=return(true)" go run -toolexec path/to/failpoint-toolexec your-program.go
عرّف نقطة الفشل في كود Golang صالح، وليس في تعليقات أو أي شيء آخر
لا تكلف نقطة الفشل أي عبء إضافي
روتين نقطة الفشل قابل للكتابة/القراءة ويجب أن يفحصه المترجم
الكود المُولَّد من تعريف نقطة الفشل سهل القراءة
الحفاظ على نفس أرقام الأسطر كما في الأكواد المُحقنة (أسهل للتنقيح)
دعم الاختبارات المتوازية باستخدام context.Context
نقطة الفشل
نقطة الفشل هي مقتطف برمجي لا يُنفَّذ إلا عندما تكون نقطة الفشل المقابلة نشطة.
لن يُنفَّذ الإغلاق أبدًا إذا تم تنفيذ failpoint.Disable("failpoint-name-for-demo").
var outerVar = "declare in outer scope"
failpoint.Inject("failpoint-name-for-demo", func(val failpoint.Value) {
fmt.Println("unit-test", val, outerVar)
})
دوال العلامات
هي مجرد دوال فارغة
سهلة الكتابة/القراءة
توفير فحص مترجم لنقاط الفشل التي قد لا تُترجم في الوضع العادي إذا كان كود نقطة الفشل غير صالح
قائمة دوال العلامات
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) {}متغير بيئة نقطة الفشل المدعوم
يمكن تفعيل نقطة الفشل بتصدير متغيرات بيئة بالنمط التالي، وهو مشابه جدًا لمتغيرات freebsd failpoint SYSCTL VARIABLES
ملاحظة: لا يمكن تفعيل InjectCall عبر متغيرات البيئة.
[<percent>%][<count>*]<type>[(args...)][-><more terms>]
وسيطة تحدد الإجراء الذي سيتم اتخاذه؛ يمكن أن تكون واحدة من:
يمكنك استدعاء failpoint.Inject لحقن نقطة فشل في موقع الاستدعاء، حيث يُستخدم failpoint-name لتفعيل نقطة الفشل وسيتم توسيع failpoint-closure ليكون جسم جملة IF.
failpoint.Inject("failpoint-name", func(val failpoint.Value) {
failpoint.Return("unit-test", val)
})
الكود المحوَّل يبدو كالتالي:
if val, _err_ := failpoint.Eval(_curpkg_("failpoint-name")); _err_ == nil {
return "unit-test", val
}
failpoint.Value هي القيمة التي تُمرَّر عبر failpoint.Enable("failpoint-name", "return(5)") ويمكن تجاهلها.
failpoint.Inject("failpoint-name", func(_ failpoint.Value) {
fmt.Println("unit-test")
})
أو
failpoint.Inject("failpoint-name", func() {
fmt.Println("unit-test")
})
والكود المحوَّل يبدو كالتالي:
if _, _err_ := failpoint.Eval(_curpkg_("failpoint-name")); _err_ == nil {
fmt.Println("unit-test")
}
أيضًا، يمكن أن يكون إغلاق نقطة الفشل دالة تأخذ context.Context. يمكنك القيام بأشياء مخصصة باستخدام context.Context مثل التحكم فيما إذا كانت نقطة الفشل نشطة في الاختبارات المتوازية أو في حالات أخرى. على سبيل المثال،
failpoint.InjectContext(ctx, "failpoint-name", func(val failpoint.Value) {
fmt.Println("unit-test", val)
})
الكود المحوَّل يبدو كالتالي:
if val, _err_ := failpoint.EvalContext(ctx, _curpkg_("failpoint-name")); _err_ == nil {
fmt.Println("unit-test", val)
}
يمكنك تجاهل context.Context، وسيؤدي ذلك إلى توليد نفس الكود المذكور أعلاه للنسخة غير المعتمدة على السياق. على سبيل المثال،
failpoint.InjectContext(nil, "failpoint-name", func(val failpoint.Value) {
fmt.Println("unit-test", val)
})
يصبح
if val, _err_ := failpoint.EvalContext(nil, _curpkg_("failpoint-name")); _err_ == nil {
fmt.Println("unit-test", val)
}