見出し画像

GO言語のプログラミングエッセンスを読んで:Go Fuzzingを試してみた その2

今朝は5時から開発開始です。
かみさんのウッドデッキ補修は、昨日は天気予報で雨と言っていたので2度塗りを諦めていました。でも、雨は降りませんでした。天気予報、がんばれ!

さて、昨日から始めたGo Fuzzingを使ってログ分析ツールのテストをしてみる試みです。
昨日ビルドエラーになっていたのは

 % go test -fuzztime 20s -fuzz FuzzSetting
# github.com/twsnmp/TWLogAIAN
./processor.go:810:11: fmt.Errorf format %s has arg b.processConf.Extractor of wrong type *github.com/vjeantet/grok.Grok
FAIL	github.com/twsnmp/TWLogAIAN [build failed]

というものです。ソースコードの場所をみると

return fmt.Errorf("invalid extractor type %s", b.processConf.Extractor)

ポインターを%sで文字列にしようとしていることを指摘していました。
実行するためのビルドだと指摘されないエラーですが、テストのためのビルドが厳格なのかもしれません。本題のFuzzingテストではありませんが一つバグが見つかりました。
ここを修正 (%s->%v)してFuzzingテストを実行すると面白いほど問題が見つかりました。私は見つかった問題を解決するのが趣味なのかもしれません。

例えば、

% go test -fuzztime 10s -fuzz FuzzSetting
fuzz: elapsed: 0s, gathering baseline coverage: 0/11 completed
fuzz: elapsed: 0s, gathering baseline coverage: 11/11 completed, now fuzzing with 6 workers
fuzz: minimizing 40-byte failing input file
fuzz: elapsed: 0s, minimizing
--- FAIL: FuzzSetting (0.07s)
    --- FAIL: FuzzSetting (0.00s)
        setting_test.go:17: failed td='0A0=0' k='0A0=0' s='' rmap=map[A0=0:A0=%{NUMBER:A0}]

のようなエラーです。0A0=0のような入力は期待していないのですが、間違った結果を返しています。
テストコードのチェックも厳密にやりすぎるとFuzzingテストをパスするようにはできません。テストのチェックもFuzzingしたほうがちょうどよいかもしれません。
テストした関数の仕様は

  • 文字列の中に" a=10 "のようなパターンがあればa=10:a=%{NUMBER:a}というデータをmapに設定する

  • 文字列の中に" b=test "のようなパターンがあればb=test:b=%{WORD:b}というデータをmapに設定する

 というものです。ログの中からデータを抽出するために使います。

最終的に、

のように修正して

func FuzzSetting(f *testing.F) {
	f.Add(" number=1 ")
	f.Add(" string=hehehe ")
	f.Fuzz(func(t *testing.T, td string) {
		rmap := make(map[string]string)
		findSplunkPat(td, rmap)

		if len(rmap) > 0 {
			for k := range rmap {
				if !strings.Contains(td, k) {
					t.Fatalf("failed td='%s' k='%s' rmap=%+v", td, k, rmap)
				}
			}
		}
	})
}

のようなテストを実行すると

% go test -fuzztime 20s -fuzz FuzzSetting
fuzz: elapsed: 0s, gathering baseline coverage: 0/117 completed
fuzz: elapsed: 0s, gathering baseline coverage: 117/117 completed, now fuzzing with 6 workers
fuzz: elapsed: 3s, execs: 70662 (23548/sec), new interesting: 8 (total: 125)
fuzz: elapsed: 6s, execs: 187539 (38955/sec), new interesting: 12 (total: 129)
fuzz: elapsed: 9s, execs: 330331 (47612/sec), new interesting: 18 (total: 135)
fuzz: elapsed: 12s, execs: 490155 (53274/sec), new interesting: 22 (total: 139)
fuzz: elapsed: 15s, execs: 602263 (37365/sec), new interesting: 31 (total: 148)
fuzz: elapsed: 18s, execs: 711206 (36319/sec), new interesting: 32 (total: 149)
fuzz: elapsed: 21s, execs: 794372 (27723/sec), new interesting: 39 (total: 156)
fuzz: elapsed: 21s, execs: 794372 (0/sec), new interesting: 39 (total: 156)
PASS
ok  	github.com/twsnmp/TWLogAIAN	21.357s

のように20秒間に80万パターン実行して問題なしになりました。
品質がアップしたような気がします。

明日に続く

開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。