github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/runtime/race/output_test.go (about)

     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  	"internal/testenv"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"regexp"
    16  	"runtime"
    17  	"strings"
    18  	"testing"
    19  )
    20  
    21  func TestOutput(t *testing.T) {
    22  	for _, test := range tests {
    23  		if test.goos != "" && test.goos != runtime.GOOS {
    24  			t.Logf("test %v runs only on %v, skipping: ", test.name, test.goos)
    25  			continue
    26  		}
    27  		dir, err := ioutil.TempDir("", "go-build")
    28  		if err != nil {
    29  			t.Fatalf("failed to create temp directory: %v", err)
    30  		}
    31  		defer os.RemoveAll(dir)
    32  		source := "main.go"
    33  		if test.run == "test" {
    34  			source = "main_test.go"
    35  		}
    36  		src := filepath.Join(dir, source)
    37  		f, err := os.Create(src)
    38  		if err != nil {
    39  			t.Fatalf("failed to create file: %v", err)
    40  		}
    41  		_, err = f.WriteString(test.source)
    42  		if err != nil {
    43  			f.Close()
    44  			t.Fatalf("failed to write: %v", err)
    45  		}
    46  		if err := f.Close(); err != nil {
    47  			t.Fatalf("failed to close file: %v", err)
    48  		}
    49  		// Pass -l to the compiler to test stack traces.
    50  		cmd := exec.Command(testenv.GoToolPath(t), test.run, "-race", "-gcflags=-l", src)
    51  		// GODEBUG spoils program output, GOMAXPROCS makes it flaky.
    52  		for _, env := range os.Environ() {
    53  			if strings.HasPrefix(env, "GODEBUG=") ||
    54  				strings.HasPrefix(env, "GOMAXPROCS=") ||
    55  				strings.HasPrefix(env, "GORACE=") {
    56  				continue
    57  			}
    58  			cmd.Env = append(cmd.Env, env)
    59  		}
    60  		cmd.Env = append(cmd.Env,
    61  			"GOMAXPROCS=1", // see comment in race_test.go
    62  			"GORACE="+test.gorace,
    63  		)
    64  		got, _ := cmd.CombinedOutput()
    65  		if !regexp.MustCompile(test.re).MatchString(string(got)) {
    66  			t.Fatalf("failed test case %v, expect:\n%v\ngot:\n%s",
    67  				test.name, test.re, got)
    68  		}
    69  	}
    70  }
    71  
    72  var tests = []struct {
    73  	name   string
    74  	run    string
    75  	goos   string
    76  	gorace string
    77  	source string
    78  	re     string
    79  }{
    80  	{"simple", "run", "", "atexit_sleep_ms=0", `
    81  package main
    82  import "time"
    83  func main() {
    84  	done := make(chan bool)
    85  	x := 0
    86  	startRacer(&x, done)
    87  	store(&x, 43)
    88  	<-done
    89  }
    90  func store(x *int, v int) {
    91  	*x = v
    92  }
    93  func startRacer(x *int, done chan bool) {
    94  	go racer(x, done)
    95  }
    96  func racer(x *int, done chan bool) {
    97  	time.Sleep(10*time.Millisecond)
    98  	store(x, 42)
    99  	done <- true
   100  }
   101  `, `==================
   102  WARNING: DATA RACE
   103  Write at 0x[0-9,a-f]+ by goroutine [0-9]:
   104    main\.store\(\)
   105        .+/main\.go:12 \+0x[0-9,a-f]+
   106    main\.racer\(\)
   107        .+/main\.go:19 \+0x[0-9,a-f]+
   108  
   109  Previous write at 0x[0-9,a-f]+ by main goroutine:
   110    main\.store\(\)
   111        .+/main\.go:12 \+0x[0-9,a-f]+
   112    main\.main\(\)
   113        .+/main\.go:8 \+0x[0-9,a-f]+
   114  
   115  Goroutine [0-9] \(running\) created at:
   116    main\.startRacer\(\)
   117        .+/main\.go:15 \+0x[0-9,a-f]+
   118    main\.main\(\)
   119        .+/main\.go:7 \+0x[0-9,a-f]+
   120  ==================
   121  Found 1 data race\(s\)
   122  exit status 66
   123  `},
   124  
   125  	{"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `
   126  package main
   127  func main() {
   128  	done := make(chan bool)
   129  	x := 0
   130  	go func() {
   131  		x = 42
   132  		done <- true
   133  	}()
   134  	x = 43
   135  	<-done
   136  }
   137  `, `exit status 13`},
   138  
   139  	{"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
   140  package main
   141  func main() {
   142  	done := make(chan bool)
   143  	x := 0
   144  	go func() {
   145  		x = 42
   146  		done <- true
   147  	}()
   148  	x = 43
   149  	<-done
   150  }
   151  `, `
   152        go:7 \+0x[0-9,a-f]+
   153  `},
   154  
   155  	{"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `
   156  package main
   157  func main() {
   158  	done := make(chan bool)
   159  	x := 0
   160  	go func() {
   161  		x = 42
   162  		done <- true
   163  	}()
   164  	x = 43
   165  	<-done
   166  }
   167  `, `
   168  ==================
   169  exit status 66
   170  `},
   171  
   172  	{"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `
   173  package main_test
   174  import "testing"
   175  func TestFail(t *testing.T) {
   176  	done := make(chan bool)
   177  	x := 0
   178  	go func() {
   179  		x = 42
   180  		done <- true
   181  	}()
   182  	x = 43
   183  	<-done
   184  	t.Log(t.Failed())
   185  }
   186  `, `
   187  ==================
   188  --- FAIL: TestFail \(0...s\)
   189  .*main_test.go:13: true
   190  .*testing.go:.*: race detected during execution of test
   191  FAIL`},
   192  
   193  	{"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
   194  package main
   195  func main() {
   196  	done := make(chan string)
   197  	data := make([]byte, 10)
   198  	go func() {
   199  		done <- string(data)
   200  	}()
   201  	data[0] = 1
   202  	<-done
   203  }
   204  `, `
   205    runtime\.slicebytetostring\(\)
   206        .*/runtime/string\.go:.*
   207    main\.main\.func1\(\)
   208        .*/main.go:7`},
   209  
   210  	// Test for http://golang.org/issue/17190
   211  	{"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
   212  package main
   213  
   214  /*
   215  #include <pthread.h>
   216  typedef struct cb {
   217          int foo;
   218  } cb;
   219  extern void goCallback();
   220  static inline void *threadFunc(void *p) {
   221  	goCallback();
   222  	return 0;
   223  }
   224  static inline void startThread(cb* c) {
   225  	pthread_t th;
   226  	pthread_create(&th, 0, threadFunc, 0);
   227  }
   228  */
   229  import "C"
   230  
   231  import "time"
   232  
   233  var racy int
   234  
   235  //export goCallback
   236  func goCallback() {
   237  	racy++
   238  }
   239  
   240  func main() {
   241  	var c C.cb
   242  	C.startThread(&c)
   243  	time.Sleep(time.Second)
   244  	racy++
   245  }
   246  `, `==================
   247  WARNING: DATA RACE
   248  Read at 0x[0-9,a-f]+ by main goroutine:
   249    main\.main\(\)
   250        .*/main\.go:34 \+0x[0-9,a-f]+
   251  
   252  Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
   253    main\.goCallback\(\)
   254        .*/main\.go:27 \+0x[0-9,a-f]+
   255    main._cgoexpwrap_[0-9a-z]+_goCallback\(\)
   256        .*/_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
   257  
   258  Goroutine [0-9] \(running\) created at:
   259    runtime\.newextram\(\)
   260        .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
   261  ==================`},
   262  	{"second_test_passes", "test", "", "atexit_sleep_ms=0", `
   263  package main_test
   264  import "testing"
   265  func TestFail(t *testing.T) {
   266  	done := make(chan bool)
   267  	x := 0
   268  	go func() {
   269  		x = 42
   270  		done <- true
   271  	}()
   272  	x = 43
   273  	<-done
   274  }
   275  
   276  func TestPass(t *testing.T) {
   277  }
   278  `, `
   279  ==================
   280  --- FAIL: TestFail \(0...s\)
   281  .*testing.go:.*: race detected during execution of test
   282  FAIL`},
   283  }