github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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  }
   185  `, `
   186  ==================
   187  --- FAIL: TestFail \(0.00s\)
   188  .*testing.go:.*: race detected during execution of test
   189  FAIL`},
   190  
   191  	{"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
   192  package main
   193  func main() {
   194  	done := make(chan string)
   195  	data := make([]byte, 10)
   196  	go func() {
   197  		done <- string(data)
   198  	}()
   199  	data[0] = 1
   200  	<-done
   201  }
   202  `, `
   203    runtime\.slicebytetostring\(\)
   204        .*/runtime/string\.go:.*
   205    main\.main\.func1\(\)
   206        .*/main.go:7`},
   207  
   208  	// Test for http://golang.org/issue/17190
   209  	{"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
   210  package main
   211  
   212  /*
   213  #include <pthread.h>
   214  typedef struct cb {
   215          int foo;
   216  } cb;
   217  extern void goCallback();
   218  static inline void *threadFunc(void *p) {
   219  	goCallback();
   220  	return 0;
   221  }
   222  static inline void startThread(cb* c) {
   223  	pthread_t th;
   224  	pthread_create(&th, 0, threadFunc, 0);
   225  }
   226  */
   227  import "C"
   228  
   229  import "time"
   230  
   231  var racy int
   232  
   233  //export goCallback
   234  func goCallback() {
   235  	racy++
   236  }
   237  
   238  func main() {
   239  	var c C.cb
   240  	C.startThread(&c)
   241  	time.Sleep(time.Second)
   242  	racy++
   243  }
   244  `, `==================
   245  WARNING: DATA RACE
   246  Read at 0x[0-9,a-f]+ by main goroutine:
   247    main\.main\(\)
   248        .*/main\.go:34 \+0x[0-9,a-f]+
   249  
   250  Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
   251    main\.goCallback\(\)
   252        .*/main\.go:27 \+0x[0-9,a-f]+
   253    main._cgoexpwrap_[0-9a-z]+_goCallback\(\)
   254        .*/_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
   255  
   256  Goroutine [0-9] \(running\) created at:
   257    runtime\.newextram\(\)
   258        .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
   259  ==================`},
   260  }