Golang failpoint工具

failpoint是用于测试时注入错误的工具。
来源是BSD系统的failpoint功能,已有的go语言实现有etcd的gofail。

它与gofail的区别是用标记函数代替了注释,标记函数的好处在于IDE可以识别并且编译时可以进行语法检查。

分析

使用

注入错误

1
2
3
4
5
6
7
8
9
package main

import "github.com/pingcap/failpoint"

func main() {
failpoint.Inject("testPanic", func() {
panic("failpoint triggerd")
})
}

打开错误failpoint-ctl enable
关闭failpoint-ctl disable

源码

enable和disable命令对应code目录下面的两个功能模块

  • rewriter
  • restorer

rewriter

Rewriter遍历目录,根据文件名过滤掉非go文件和rewrite之后生成的文件。
parse文件的import,过滤没有import标记函数包的文件

file, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)

对所有函数定义进行rewrite

1
2
fn, ok := decl.(*ast.FuncDecl)
r.rewriteFuncDecl(fn)

rewrite使用了递归,覆盖了所有可能出现注入错误的语句。
实际需要修改的是表达式*ast.ExprStmt,并且是包函数调用*ast.SelectorExpr

1
2
3
4
5
6
7
8
exprRewriter, found := exprRewriters[expr.Sel.Name]
if !found {
break
}
rewritten, stmt, err := exprRewriter(r, call)
if err != nil {
return err
}

标记函数对应的修改函数的映射放在exprRewriters这个map
修改函数构造一个新的stmt替换掉原来的语句,再输出到原文件,修改就完成了。
除了修改原文件,rewriter会生成一个binding文件和原文件的备份,备份文件用于disable的时候来恢复原文件。

restorer

restore没有直接把备份文件rename为原文件,而是把生成的文件跟备份文件做了一次diff,然后把patch加到备份文件上,这样做是为了把生成之后对新文件的修改应用到备份文件上,避免用户disable之后修改丢失。

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2015-2024 RivenZoo
  • Powered by Hexo Theme Ayer
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信