Home | History | Annotate | Download | only in race
      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