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