1 // Copyright 2013 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 // +build race 6 7 package race_test 8 9 import ( 10 "io/ioutil" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "regexp" 15 "strings" 16 "testing" 17 ) 18 19 func TestOutput(t *testing.T) { 20 for _, test := range tests { 21 dir, err := ioutil.TempDir("", "go-build") 22 if err != nil { 23 t.Fatalf("failed to create temp directory: %v", err) 24 } 25 defer os.RemoveAll(dir) 26 source := "main.go" 27 if test.run == "test" { 28 source = "main_test.go" 29 } 30 src := filepath.Join(dir, source) 31 f, err := os.Create(src) 32 if err != nil { 33 t.Fatalf("failed to create file: %v", err) 34 } 35 _, err = f.WriteString(test.source) 36 if err != nil { 37 f.Close() 38 t.Fatalf("failed to write: %v", err) 39 } 40 if err := f.Close(); err != nil { 41 t.Fatalf("failed to close file: %v", err) 42 } 43 // Pass -l to the compiler to test stack traces. 44 cmd := exec.Command("go", test.run, "-race", "-gcflags=-l", src) 45 // GODEBUG spoils program output, GOMAXPROCS makes it flaky. 46 for _, env := range os.Environ() { 47 if strings.HasPrefix(env, "GODEBUG=") || 48 strings.HasPrefix(env, "GOMAXPROCS=") || 49 strings.HasPrefix(env, "GORACE=") { 50 continue 51 } 52 cmd.Env = append(cmd.Env, env) 53 } 54 cmd.Env = append(cmd.Env, "GORACE="+test.gorace) 55 got, _ := cmd.CombinedOutput() 56 if !regexp.MustCompile(test.re).MatchString(string(got)) { 57 t.Fatalf("failed test case %v, expect:\n%v\ngot:\n%s", 58 test.name, test.re, got) 59 } 60 } 61 } 62 63 var tests = []struct { 64 name string 65 run string 66 gorace string 67 source string 68 re string 69 }{ 70 {"simple", "run", "atexit_sleep_ms=0", ` 71 package main 72 import "time" 73 func main() { 74 done := make(chan bool) 75 x := 0 76 startRacer(&x, done) 77 store(&x, 43) 78 <-done 79 } 80 func store(x *int, v int) { 81 *x = v 82 } 83 func startRacer(x *int, done chan bool) { 84 go racer(x, done) 85 } 86 func racer(x *int, done chan bool) { 87 time.Sleep(10*time.Millisecond) 88 store(x, 42) 89 done <- true 90 } 91 `, `================== 92 WARNING: DATA RACE 93 Write by goroutine [0-9]: 94 main\.store\(\) 95 .+/main\.go:12 \+0x[0-9,a-f]+ 96 main\.racer\(\) 97 .+/main\.go:19 \+0x[0-9,a-f]+ 98 99 Previous write by main goroutine: 100 main\.store\(\) 101 .+/main\.go:12 \+0x[0-9,a-f]+ 102 main\.main\(\) 103 .+/main\.go:8 \+0x[0-9,a-f]+ 104 105 Goroutine [0-9] \(running\) created at: 106 main\.startRacer\(\) 107 .+/main\.go:15 \+0x[0-9,a-f]+ 108 main\.main\(\) 109 .+/main\.go:7 \+0x[0-9,a-f]+ 110 ================== 111 Found 1 data race\(s\) 112 exit status 66 113 `}, 114 115 {"exitcode", "run", "atexit_sleep_ms=0 exitcode=13", ` 116 package main 117 func main() { 118 done := make(chan bool) 119 x := 0 120 go func() { 121 x = 42 122 done <- true 123 }() 124 x = 43 125 <-done 126 } 127 `, `exit status 13`}, 128 129 {"strip_path_prefix", "run", "atexit_sleep_ms=0 strip_path_prefix=/main.", ` 130 package main 131 func main() { 132 done := make(chan bool) 133 x := 0 134 go func() { 135 x = 42 136 done <- true 137 }() 138 x = 43 139 <-done 140 } 141 `, ` 142 go:7 \+0x[0-9,a-f]+ 143 `}, 144 145 {"halt_on_error", "run", "atexit_sleep_ms=0 halt_on_error=1", ` 146 package main 147 func main() { 148 done := make(chan bool) 149 x := 0 150 go func() { 151 x = 42 152 done <- true 153 }() 154 x = 43 155 <-done 156 } 157 `, ` 158 ================== 159 exit status 66 160 `}, 161 162 {"test_fails_on_race", "test", "atexit_sleep_ms=0", ` 163 package main_test 164 import "testing" 165 func TestFail(t *testing.T) { 166 done := make(chan bool) 167 x := 0 168 go func() { 169 x = 42 170 done <- true 171 }() 172 x = 43 173 <-done 174 } 175 `, ` 176 ================== 177 PASS 178 Found 1 data race\(s\) 179 FAIL`}, 180 } 181