1
2
3
4
5 package main
6
7 import (
8 "flag"
9 "fmt"
10 "internal/coverage/slicewriter"
11 "io"
12 "log"
13 "os"
14 "path/filepath"
15 "runtime/coverage"
16 "strings"
17 )
18
19 var verbflag = flag.Int("v", 0, "Verbose trace output level")
20 var testpointflag = flag.String("tp", "", "Testpoint to run")
21 var outdirflag = flag.String("o", "", "Output dir into which to emit")
22
23 func emitToWriter() {
24 log.SetPrefix("emitToWriter: ")
25 var slwm slicewriter.WriteSeeker
26 if err := coverage.WriteMeta(&slwm); err != nil {
27 log.Fatalf("error: WriteMeta returns %v", err)
28 }
29 mf := filepath.Join(*outdirflag, "covmeta.0abcdef")
30 if err := os.WriteFile(mf, slwm.BytesWritten(), 0666); err != nil {
31 log.Fatalf("error: writing %s: %v", mf, err)
32 }
33 var slwc slicewriter.WriteSeeker
34 if err := coverage.WriteCounters(&slwc); err != nil {
35 log.Fatalf("error: WriteCounters returns %v", err)
36 }
37 cf := filepath.Join(*outdirflag, "covcounters.0abcdef.99.77")
38 if err := os.WriteFile(cf, slwc.BytesWritten(), 0666); err != nil {
39 log.Fatalf("error: writing %s: %v", cf, err)
40 }
41 }
42
43 func emitToDir() {
44 log.SetPrefix("emitToDir: ")
45 if err := coverage.WriteMetaDir(*outdirflag); err != nil {
46 log.Fatalf("error: WriteMetaDir returns %v", err)
47 }
48 if err := coverage.WriteCountersDir(*outdirflag); err != nil {
49 log.Fatalf("error: WriteCountersDir returns %v", err)
50 }
51 }
52
53 func emitToNonexistentDir() {
54 log.SetPrefix("emitToNonexistentDir: ")
55
56 want := []string{
57 "no such file or directory",
58 "system cannot find the file specified",
59 "does not exist",
60 }
61
62 checkWant := func(which string, got string) {
63 found := false
64 for _, w := range want {
65 if strings.Contains(got, w) {
66 found = true
67 break
68 }
69 }
70 if !found {
71 log.Fatalf("%s emit to bad dir: got error:\n %v\nwanted error with one of:\n %+v", which, got, want)
72 }
73 }
74
75
76 mangled := *outdirflag + "_MANGLED"
77 if err := coverage.WriteMetaDir(mangled); err == nil {
78 log.Fatal("expected error from WriteMetaDir to nonexistent dir")
79 } else {
80 got := fmt.Sprintf("%v", err)
81 checkWant("meta data", got)
82 }
83
84
85 if err := coverage.WriteCountersDir(mangled); err == nil {
86 log.Fatal("expected error emitting counter data to bad dir")
87 } else {
88 got := fmt.Sprintf("%v", err)
89 checkWant("counter data", got)
90 }
91 }
92
93 func emitToUnwritableDir() {
94 log.SetPrefix("emitToUnwritableDir: ")
95
96 want := "permission denied"
97
98 if err := coverage.WriteMetaDir(*outdirflag); err == nil {
99 log.Fatal("expected error from WriteMetaDir to unwritable dir")
100 } else {
101 got := fmt.Sprintf("%v", err)
102 if !strings.Contains(got, want) {
103 log.Fatalf("meta-data emit to unwritable dir: wanted error containing %q got %q", want, got)
104 }
105 }
106
107
108 if err := coverage.WriteCountersDir(*outdirflag); err == nil {
109 log.Fatal("expected error emitting counter data to unwritable dir")
110 } else {
111 got := fmt.Sprintf("%v", err)
112 if !strings.Contains(got, want) {
113 log.Fatalf("emitting counter data to unwritable dir: wanted error containing %q got %q", want, got)
114 }
115 }
116 }
117
118 func emitToNilWriter() {
119 log.SetPrefix("emitToWriter: ")
120 want := "nil writer"
121 var bad io.WriteSeeker
122 if err := coverage.WriteMeta(bad); err == nil {
123 log.Fatal("expected error passing nil writer for meta emit")
124 } else {
125 got := fmt.Sprintf("%v", err)
126 if !strings.Contains(got, want) {
127 log.Fatalf("emitting meta-data passing nil writer: wanted error containing %q got %q", want, got)
128 }
129 }
130
131 if err := coverage.WriteCounters(bad); err == nil {
132 log.Fatal("expected error passing nil writer for counter emit")
133 } else {
134 got := fmt.Sprintf("%v", err)
135 if !strings.Contains(got, want) {
136 log.Fatalf("emitting counter data passing nil writer: wanted error containing %q got %q", want, got)
137 }
138 }
139 }
140
141 type failingWriter struct {
142 writeCount int
143 writeLimit int
144 slws slicewriter.WriteSeeker
145 }
146
147 func (f *failingWriter) Write(p []byte) (n int, err error) {
148 c := f.writeCount
149 f.writeCount++
150 if f.writeLimit < 0 || c < f.writeLimit {
151 return f.slws.Write(p)
152 }
153 return 0, fmt.Errorf("manufactured write error")
154 }
155
156 func (f *failingWriter) Seek(offset int64, whence int) (int64, error) {
157 return f.slws.Seek(offset, whence)
158 }
159
160 func (f *failingWriter) reset(lim int) {
161 f.writeCount = 0
162 f.writeLimit = lim
163 f.slws = slicewriter.WriteSeeker{}
164 }
165
166 func writeStressTest(tag string, testf func(testf *failingWriter) error) {
167
168
169 fw := &failingWriter{writeLimit: -1}
170 testf(fw)
171
172
173
174
175
176 tot := fw.writeCount
177 for i := 0; i < tot; i++ {
178 fw.reset(i)
179 err := testf(fw)
180 if err == nil {
181 log.Fatalf("no error from write %d tag %s", i, tag)
182 }
183 }
184 }
185
186 func postClear() int {
187 return 42
188 }
189
190 func preClear() int {
191 return 42
192 }
193
194
195
196
197
198
199
200 func emitToFailingWriter() {
201 log.SetPrefix("emitToFailingWriter: ")
202
203 writeStressTest("emit-meta", func(f *failingWriter) error {
204 return coverage.WriteMeta(f)
205 })
206 writeStressTest("emit-counter", func(f *failingWriter) error {
207 return coverage.WriteCounters(f)
208 })
209 }
210
211 func emitWithCounterClear() {
212 log.SetPrefix("emitWitCounterClear: ")
213 preClear()
214 if err := coverage.ClearCounters(); err != nil {
215 log.Fatalf("clear failed: %v", err)
216 }
217 postClear()
218 if err := coverage.WriteMetaDir(*outdirflag); err != nil {
219 log.Fatalf("error: WriteMetaDir returns %v", err)
220 }
221 if err := coverage.WriteCountersDir(*outdirflag); err != nil {
222 log.Fatalf("error: WriteCountersDir returns %v", err)
223 }
224 }
225
226 func final() int {
227 println("I run last.")
228 return 43
229 }
230
231 func main() {
232 log.SetFlags(0)
233 flag.Parse()
234 if *testpointflag == "" {
235 log.Fatalf("error: no testpoint (use -tp flag)")
236 }
237 if *outdirflag == "" {
238 log.Fatalf("error: no output dir specified (use -o flag)")
239 }
240 switch *testpointflag {
241 case "emitToDir":
242 emitToDir()
243 case "emitToWriter":
244 emitToWriter()
245 case "emitToNonexistentDir":
246 emitToNonexistentDir()
247 case "emitToUnwritableDir":
248 emitToUnwritableDir()
249 case "emitToNilWriter":
250 emitToNilWriter()
251 case "emitToFailingWriter":
252 emitToFailingWriter()
253 case "emitWithCounterClear":
254 emitWithCounterClear()
255 default:
256 log.Fatalf("error: unknown testpoint %q", *testpointflag)
257 }
258 final()
259 }
260
View as plain text