github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/coverage/testdata/harness.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "flag" 9 "fmt" 10 "internal/coverage/slicewriter" 11 "io" 12 "io/ioutil" 13 "log" 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 := ioutil.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 := ioutil.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", // linux-ish 58 "system cannot find the file specified", // windows 59 "does not exist", // plan9 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 // Mangle the output directory to produce something nonexistent. 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 // Now try to emit counter data file to a bad dir. 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 // Similarly with writing counter data. 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 // Invoke the function initially without the write limit 168 // set, to capture the number of writes performed. 169 fw := &failingWriter{writeLimit: -1} 170 testf(fw) 171 172 // Now that we know how many writes are going to happen, run the 173 // function repeatedly, each time with a Write operation set to 174 // fail at a new spot. The goal here is to make sure that: 175 // A) an error is reported, and B) nothing crashes. 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 // This test is designed to ensure that write errors are properly 195 // handled by the code that writes out coverage data. It repeatedly 196 // invokes the 'emit to writer' apis using a specially crafted writer 197 // that captures the total number of expected writes, then replays the 198 // execution N times with a manufactured write error at the 199 // appropriate spot. 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 }