1 [!fuzz] skip
2
3 # Test basic fuzzing mutator behavior.
4 #
5 # fuzz_test.go has two fuzz targets (FuzzA, FuzzB) which both add a seed value.
6 # Each fuzz function writes the input to a log file. The coordinator and worker
7 # use separate log files. check_logs.go verifies that the coordinator only
8 # tests seed values and the worker tests mutated values on the fuzz target.
9
10 [short] skip
11
12 go test -fuzz=FuzzA -fuzztime=100x -parallel=1 -log=fuzz
13 go run check_logs.go fuzz fuzz.worker
14
15 # TODO(b/181800488): remove -parallel=1, here and below. For now, when a
16 # crash is found, all workers keep running, wasting resources and reducing
17 # the number of executions available to the minimizer, increasing flakiness.
18
19 # Test that the mutator is good enough to find several unique mutations.
20 ! go test -fuzz=FuzzMutator -parallel=1 -fuzztime=100x mutator_test.go
21 ! stdout '^ok'
22 stdout FAIL
23 stdout 'mutator found enough unique mutations'
24
25 -- go.mod --
26 module m
27
28 go 1.16
29 -- fuzz_test.go --
30 package fuzz_test
31
32 import (
33 "flag"
34 "fmt"
35 "os"
36 "testing"
37 )
38
39 var (
40 logPath = flag.String("log", "", "path to log file")
41 logFile *os.File
42 )
43
44 func TestMain(m *testing.M) {
45 flag.Parse()
46 var err error
47 logFile, err = os.OpenFile(*logPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
48 if os.IsExist(err) {
49 *logPath += ".worker"
50 logFile, err = os.OpenFile(*logPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
51 }
52 if err != nil {
53 fmt.Fprintln(os.Stderr, err)
54 os.Exit(1)
55 }
56 os.Exit(m.Run())
57 }
58
59 func FuzzA(f *testing.F) {
60 f.Add([]byte("seed"))
61 f.Fuzz(func(t *testing.T, b []byte) {
62 fmt.Fprintf(logFile, "FuzzA %q\n", b)
63 })
64 }
65
66 func FuzzB(f *testing.F) {
67 f.Add([]byte("seed"))
68 f.Fuzz(func(t *testing.T, b []byte) {
69 fmt.Fprintf(logFile, "FuzzB %q\n", b)
70 })
71 }
72
73 -- check_logs.go --
74 // +build ignore
75
76 package main
77
78 import (
79 "bufio"
80 "bytes"
81 "fmt"
82 "io"
83 "os"
84 "strings"
85 )
86
87 func main() {
88 coordPath, workerPath := os.Args[1], os.Args[2]
89
90 coordLog, err := os.Open(coordPath)
91 if err != nil {
92 fmt.Fprintln(os.Stderr, err)
93 os.Exit(1)
94 }
95 defer coordLog.Close()
96 if err := checkCoordLog(coordLog); err != nil {
97 fmt.Fprintln(os.Stderr, err)
98 os.Exit(1)
99 }
100
101 workerLog, err := os.Open(workerPath)
102 if err != nil {
103 fmt.Fprintln(os.Stderr, err)
104 os.Exit(1)
105 }
106 defer workerLog.Close()
107 if err := checkWorkerLog(workerLog); err != nil {
108 fmt.Fprintln(os.Stderr, err)
109 os.Exit(1)
110 }
111 }
112
113 func checkCoordLog(r io.Reader) error {
114 b, err := io.ReadAll(r)
115 if err != nil {
116 return err
117 }
118 if string(bytes.TrimSpace(b)) != `FuzzB "seed"` {
119 return fmt.Errorf("coordinator: did not test FuzzB seed")
120 }
121 return nil
122 }
123
124 func checkWorkerLog(r io.Reader) error {
125 scan := bufio.NewScanner(r)
126 var sawAMutant bool
127 for scan.Scan() {
128 line := scan.Text()
129 if !strings.HasPrefix(line, "FuzzA ") {
130 return fmt.Errorf("worker: tested something other than target: %s", line)
131 }
132 if strings.TrimPrefix(line, "FuzzA ") != `"seed"` {
133 sawAMutant = true
134 }
135 }
136 if err := scan.Err(); err != nil && err != bufio.ErrTooLong {
137 return err
138 }
139 if !sawAMutant {
140 return fmt.Errorf("worker: did not test any mutants")
141 }
142 return nil
143 }
144 -- mutator_test.go --
145 package fuzz_test
146
147 import (
148 "testing"
149 )
150
151 // TODO(katiehockman): re-work this test once we have a better fuzzing engine
152 // (ie. more mutations, and compiler instrumentation)
153 func FuzzMutator(f *testing.F) {
154 // TODO(katiehockman): simplify this once we can dedupe crashes (e.g.
155 // replace map with calls to panic, and simply count the number of crashes
156 // that were added to testdata)
157 crashes := make(map[string]bool)
158 // No seed corpus initiated
159 f.Fuzz(func(t *testing.T, b []byte) {
160 crashes[string(b)] = true
161 if len(crashes) >= 10 {
162 panic("mutator found enough unique mutations")
163 }
164 })
165 }
166
View as plain text