測試是功能上線之前的重要環節。
測試過程中,要儘量覆蓋各種場景。故障情況或異常情況下的場景測試,也是必不可少的。
如何模擬故障呢?
在FreeBSD 中, failpoints經常用來模擬故障。
在golang,也有failpoint的實現,就是目前pingcap 公司的開源項目failpoint
.
下面介紹golang中的failpoint的實現。
1.安裝failpoint工具
cd $GOPATH/src
mkdir -p github.com/pingcap
cd github.com/pingcap
git clone https://github.com/pingcap/failpoint.git
cd failpoint
make
GO111MODULE=on CGO_ENABLED=0 GO111MODULE=on go build -ldflags '-X "github.com/pingcap/failpoint/failpoint-ctl/version.releaseVersion=12f4ac2-dev" -X "github.com/pingcap/failpoint/failpoint-ctl/version.buildTS=2019-11-15 09:41:49" -X "github.com/pingcap/failpoint/failpoint-ctl/version.gitHash=12f4ac2fd11dfc6b2f7018b00bb90f61a5b6b692" -X "github.com/pingcap/failpoint/failpoint-ctl/version.gitBranch=master" -X "github.com/pingcap/failpoint/failpoint-ctl/version.goVersion=go version go1.13 darwin/amd64"' -o bin/failpoint-ctl failpoint-ctl/main.go
failpoint-ctl build successfully :-) !
注意:仔細確認這些步驟。如果搞錯,會出現無法轉換代碼的情況。
編譯後,生成可執行文件failpoint-ctl:
ll bin
total 6840
-rwxr-xr-x 1 lanyang staff 3.3M 11 15 17:41 failpoint-ctl
2. 測試代碼
代碼結構如下:
cd $GOPATH/src
mkdir fp_example
cd fp_example
# tree ./
./
├── fruit
│ └── banana.go
├── main.go
└── util
├── apple.go
└── orange.go
其中,main.go文件內容:
package main
import (
"fmt"
"fp_example/hot_fruit"
"fp_example/fruit"
)
func main() {
hot_fruit.Apple()
hot_fruit.Orange()
fruit.Banana()
fmt.Println("main end")
}
fruit/banana.go:
package fruit
import (
"fmt"
"github.com/pingcap/failpoint"
)
func Banana() {
fmt.Println("banana....")
failpoint.Inject("bananaPanic", func() {
panic("banana failpoint triggerd")
})
}
注入一個panic。
hot_fruit/apple.go:
package hot_fruit
import (
"fmt"
"github.com/pingcap/failpoint"
)
func Apple() {
fmt.Println("apple....")
failpoint.Inject("applePanic", func() {
panic("apple failpoint triggerd")
})
}
再次注入一個panic。
hot_fruit/orange.go:
package hot_fruit
import (
"fmt"
"github.com/pingcap/failpoint"
)
func Orange() {
fmt.Println("orange....")
failpoint.Inject("orangePanic", func() {
panic("orange failpoint triggerd")
})
}
再次注入一個panic。
3. 使用failpoint轉換代碼
$GOPATH/src/github.com/pingcap/failpoint/bin/failpoint-ctl enable
代碼轉換之後,看下代碼文件結構:
tree ./
./
├── fruit
│ ├── banana.go
│ ├── banana.go__failpoint_stash__
│ └── binding__failpoint_binding__.go
├── hot_fruit
│ ├── apple.go
│ ├── apple.go__failpoint_stash__
│ ├── binding__failpoint_binding__.go
│ ├── orange.go
│ └── orange.go__failpoint_stash__
├── main.go
2 directories, 10 files
可以看到多了幾個文件。
如果執行disable,這些文件又會消失。
$GOPATH/src/github.com/pingcap/failpoint/bin/failpoint-ctl disable
4.編譯和執行
使用裝換之後的代碼,進行編譯:
go build -o simple main.go
生成可執行文件simple
.
正常執行:
./simple
apple....
orange....
banana....
main end
觸發bananaPanic故障執行:
GO_FAILPOINTS="fp_example/fruit/bananaPanic=return(true)" ./simple
apple....
orange....
banana....
panic: banana failpoint triggerd
goroutine 1 [running]:
fp_example/fruit.Banana()
/Users/lanyang/workspace/go_projects/src/fp_example/fruit/banana.go:12 +0x10e
main.main()
/Users/lanyang/workspace/go_projects/src/fp_example/main.go:13 +0x2c
其中,fp_example/fruit
是package名稱, bananaPanic
是注入的故障名稱。
觸發applePanic故障執行:
GO_FAILPOINTS="fp_example/hot_fruit/applePanic=return(true)" ./simple
apple....
panic: apple failpoint triggerd
goroutine 1 [running]:
fp_example/hot_fruit.Apple()
/Users/lanyang/workspace/go_projects/src/fp_example/hot_fruit/apple.go:12 +0x10e
main.main()
/Users/lanyang/workspace/go_projects/src/fp_example/main.go:11 +0x22
觸發orangePanic故障執行:
GO_FAILPOINTS="fp_example/hot_fruit/orangePanic=return(true)" ./simple
apple....
orange....
panic: orange failpoint triggerd
goroutine 1 [running]:
fp_example/hot_fruit.Orange()
/Users/lanyang/workspace/go_projects/src/fp_example/hot_fruit/orange.go:12 +0x10e
main.main()
/Users/lanyang/workspace/go_projects/src/fp_example/main.go:12 +0x27