1 // Copyright 2012 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.
27 func TestMain(m
*testing
.M
) {
29 for _
, file
:= range toRemove
{
35 func testEnv(cmd
*exec
.Cmd
) *exec
.Cmd
{
37 panic("environment already set")
39 for _
, env
:= range os
.Environ() {
40 // Exclude GODEBUG from the environment to prevent its output
41 // from breaking tests that are trying to parse other command output.
42 if strings
.HasPrefix(env
, "GODEBUG=") {
45 // Exclude GOTRACEBACK for the same reason.
46 if strings
.HasPrefix(env
, "GOTRACEBACK=") {
49 cmd
.Env
= append(cmd
.Env
, env
)
57 target
map[string]buildexe
60 type buildexe
struct {
65 func runTestProg(t
*testing
.T
, binary
, name
string) string {
66 testenv
.MustHaveGoBuild(t
)
68 exe
, err
:= buildTestProg(t
, binary
)
73 cmd
:= testEnv(exec
.Command(exe
, name
))
77 if err
:= cmd
.Start(); err
!= nil {
78 t
.Fatalf("starting %s %s: %v", binary
, name
, err
)
81 // If the process doesn't complete within 1 minute,
82 // assume it is hanging and kill it to get a stack trace.
84 done
:= make(chan bool)
87 // This GOARCH/GOOS test is copied from cmd/dist/test.go.
88 // TODO(iant): Have cmd/dist update the environment variable.
89 if runtime
.GOARCH
== "arm" || runtime
.GOOS
== "windows" {
92 if s
:= os
.Getenv("GO_TEST_TIMEOUT_SCALE"); s
!= "" {
93 if sc
, err
:= strconv
.Atoi(s
); err
== nil {
100 case <-time
.After(time
.Duration(scale
) * time
.Minute
):
105 if err
:= cmd
.Wait(); err
!= nil {
106 t
.Logf("%s %s exit status: %v", binary
, name
, err
)
113 func buildTestProg(t
*testing
.T
, binary
string, flags
...string) (string, error
) {
117 defer testprog
.Unlock()
118 if testprog
.dir
== "" {
119 dir
, err
:= ioutil
.TempDir("", "go-build")
121 t
.Fatalf("failed to create temp directory: %v", err
)
124 toRemove
= append(toRemove
, dir
)
127 if testprog
.target
== nil {
128 testprog
.target
= make(map[string]buildexe
)
132 name
+= "_" + strings
.Join(flags
, "_")
134 target
, ok
:= testprog
.target
[name
]
136 return target
.exe
, target
.err
139 exe
:= filepath
.Join(testprog
.dir
, name
+".exe")
140 cmd
:= exec
.Command(testenv
.GoToolPath(t
), append([]string{"build", "-o", exe
}, flags
...)...)
141 cmd
.Dir
= "testdata/" + binary
142 out
, err
:= testEnv(cmd
).CombinedOutput()
144 target
.err
= fmt
.Errorf("building %s %v: %v\n%s", binary
, flags
, err
, out
)
145 testprog
.target
[name
] = target
146 return "", target
.err
149 testprog
.target
[name
] = target
154 staleRuntimeOnce sync
.Once
// guards init of staleRuntimeErr
155 staleRuntimeErr error
158 func checkStaleRuntime(t
*testing
.T
) {
159 staleRuntimeOnce
.Do(func() {
160 // 'go run' uses the installed copy of runtime.a, which may be out of date.
161 out
, err
:= testEnv(exec
.Command(testenv
.GoToolPath(t
), "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
163 staleRuntimeErr
= fmt
.Errorf("failed to execute 'go list': %v\n%v", err
, string(out
))
166 if string(out
) != "false\n" {
167 t
.Logf("go list -f {{.Stale}} runtime:\n%s", out
)
168 out
, err
:= testEnv(exec
.Command(testenv
.GoToolPath(t
), "list", "-f", "{{.StaleReason}}", "runtime")).CombinedOutput()
170 t
.Logf("go list -f {{.StaleReason}} failed: %v", err
)
172 t
.Logf("go list -f {{.StaleReason}} runtime:\n%s", out
)
173 staleRuntimeErr
= fmt
.Errorf("Stale runtime.a. Run 'go install runtime'.")
176 if staleRuntimeErr
!= nil {
177 t
.Fatal(staleRuntimeErr
)
181 func testCrashHandler(t
*testing
.T
, cgo
bool) {
182 type crashTest
struct {
187 output
= runTestProg(t
, "testprogcgo", "Crash")
189 output
= runTestProg(t
, "testprog", "Crash")
191 want
:= "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
193 t
.Fatalf("output:\n%s\n\nwanted:\n%s", output
, want
)
197 func TestCrashHandler(t
*testing
.T
) {
198 testCrashHandler(t
, false)
201 func testDeadlock(t
*testing
.T
, name
string) {
202 output
:= runTestProg(t
, "testprog", name
)
203 want
:= "fatal error: all goroutines are asleep - deadlock!\n"
204 if !strings
.HasPrefix(output
, want
) {
205 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
209 func TestSimpleDeadlock(t
*testing
.T
) {
210 testDeadlock(t
, "SimpleDeadlock")
213 func TestInitDeadlock(t
*testing
.T
) {
214 testDeadlock(t
, "InitDeadlock")
217 func TestLockedDeadlock(t
*testing
.T
) {
218 testDeadlock(t
, "LockedDeadlock")
221 func TestLockedDeadlock2(t
*testing
.T
) {
222 testDeadlock(t
, "LockedDeadlock2")
225 func TestGoexitDeadlock(t
*testing
.T
) {
226 output
:= runTestProg(t
, "testprog", "GoexitDeadlock")
227 want
:= "no goroutines (main called runtime.Goexit) - deadlock!"
228 if !strings
.Contains(output
, want
) {
229 t
.Fatalf("output:\n%s\n\nwant output containing: %s", output
, want
)
233 func TestStackOverflow(t
*testing
.T
) {
234 if runtime
.Compiler
== "gccgo" {
235 t
.Skip("gccgo does not do stack overflow checking")
237 output
:= runTestProg(t
, "testprog", "StackOverflow")
238 want
:= "runtime: goroutine stack exceeds 1474560-byte limit\nfatal error: stack overflow"
239 if !strings
.HasPrefix(output
, want
) {
240 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
244 func TestThreadExhaustion(t
*testing
.T
) {
245 output
:= runTestProg(t
, "testprog", "ThreadExhaustion")
246 want
:= "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
247 if !strings
.HasPrefix(output
, want
) {
248 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
252 func TestRecursivePanic(t
*testing
.T
) {
253 output
:= runTestProg(t
, "testprog", "RecursivePanic")
258 if !strings
.HasPrefix(output
, want
) {
259 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
264 func TestGoexitCrash(t
*testing
.T
) {
265 output
:= runTestProg(t
, "testprog", "GoexitExit")
266 want
:= "no goroutines (main called runtime.Goexit) - deadlock!"
267 if !strings
.Contains(output
, want
) {
268 t
.Fatalf("output:\n%s\n\nwant output containing: %s", output
, want
)
272 func TestGoexitDefer(t
*testing
.T
) {
273 c
:= make(chan struct{})
278 t
.Errorf("non-nil recover during Goexit")
284 // Note: if the defer fails to run, we will get a deadlock here
288 func TestGoNil(t
*testing
.T
) {
289 output
:= runTestProg(t
, "testprog", "GoNil")
290 want
:= "go of nil func value"
291 if !strings
.Contains(output
, want
) {
292 t
.Fatalf("output:\n%s\n\nwant output containing: %s", output
, want
)
296 func TestMainGoroutineID(t
*testing
.T
) {
297 output
:= runTestProg(t
, "testprog", "MainGoroutineID")
298 want
:= "panic: test\n\ngoroutine 1 [running]:\n"
299 if !strings
.HasPrefix(output
, want
) {
300 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
304 func TestNoHelperGoroutines(t
*testing
.T
) {
305 output
:= runTestProg(t
, "testprog", "NoHelperGoroutines")
306 matches
:= regexp
.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output
, -1)
307 if len(matches
) != 1 || matches
[0][0] != "goroutine 1 [" {
308 t
.Fatalf("want to see only goroutine 1, see:\n%s", output
)
312 func TestBreakpoint(t
*testing
.T
) {
313 output
:= runTestProg(t
, "testprog", "Breakpoint")
314 // If runtime.Breakpoint() is inlined, then the stack trace prints
315 // "runtime.Breakpoint(...)" instead of "runtime.Breakpoint()".
316 // For gccgo, no parens.
317 want
:= "runtime.Breakpoint"
318 if !strings
.Contains(output
, want
) {
319 t
.Fatalf("output:\n%s\n\nwant output containing: %s", output
, want
)
323 func TestGoexitInPanic(t
*testing
.T
) {
324 // see issue 8774: this code used to trigger an infinite recursion
325 output
:= runTestProg(t
, "testprog", "GoexitInPanic")
326 want
:= "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
327 if !strings
.HasPrefix(output
, want
) {
328 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
332 // Issue 14965: Runtime panics should be of type runtime.Error
333 func TestRuntimePanicWithRuntimeError(t
*testing
.T
) {
334 testCases
:= [...]func(){
336 var m
map[uint64]bool
340 ch
:= make(chan struct{})
345 var ch
= make(chan struct{})
350 var s
= make([]int, 2)
355 _
= make(chan bool, n
)
358 close((chan bool)(nil))
362 for i
, fn
:= range testCases
{
363 got
:= panicValue(fn
)
364 if _
, ok
:= got
.(runtime
.Error
); !ok
{
365 t
.Errorf("test #%d: recovered value %v(type %T) does not implement runtime.Error", i
, got
, got
)
370 func panicValue(fn
func()) (recovered
interface{}) {
372 recovered
= recover()
378 func TestPanicAfterGoexit(t
*testing
.T
) {
379 // an uncaught panic should still work after goexit
380 output
:= runTestProg(t
, "testprog", "PanicAfterGoexit")
381 want
:= "panic: hello"
382 if !strings
.HasPrefix(output
, want
) {
383 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
387 func TestRecoveredPanicAfterGoexit(t
*testing
.T
) {
388 output
:= runTestProg(t
, "testprog", "RecoveredPanicAfterGoexit")
389 want
:= "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
390 if !strings
.HasPrefix(output
, want
) {
391 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
395 func TestRecoverBeforePanicAfterGoexit(t
*testing
.T
) {
396 // 1. defer a function that recovers
397 // 2. defer a function that panics
399 // Goexit should run the #2 defer. Its panic
400 // should be caught by the #1 defer, and execution
401 // should resume in the caller. Like the Goexit
415 func TestNetpollDeadlock(t
*testing
.T
) {
417 output
:= runTestProg(t
, "testprognet", "NetpollDeadlock")
419 if !strings
.HasSuffix(output
, want
) {
420 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
424 func TestPanicTraceback(t
*testing
.T
) {
426 output
:= runTestProg(t
, "testprog", "PanicTraceback")
427 want
:= "panic: hello"
428 if !strings
.HasPrefix(output
, want
) {
429 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
432 // Check functions in the traceback.
433 fns
:= []string{"main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
434 if runtime
.Compiler
== "gccgo" {
435 fns
= []string{"main.$nested", "panic", "main.$nested", "panic", "main.pt2", "main.pt1"}
437 for _
, fn
:= range fns
{
438 var re
*regexp
.Regexp
439 if runtime
.Compiler
!= "gccgo" {
440 re
= regexp
.MustCompile(`(?m)^` + regexp
.QuoteMeta(fn
) + `\(.*\n`)
442 re
= regexp
.MustCompile(`(?m)^` + regexp
.QuoteMeta(fn
) + `.*\n`)
444 idx
:= re
.FindStringIndex(output
)
446 t
.Fatalf("expected %q function in traceback:\n%s", fn
, output
)
448 output
= output
[idx
[1]:]
452 func testPanicDeadlock(t
*testing
.T
, name
string, want
string) {
454 output
:= runTestProg(t
, "testprog", name
)
455 if !strings
.HasPrefix(output
, want
) {
456 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
460 func TestPanicDeadlockGosched(t
*testing
.T
) {
461 testPanicDeadlock(t
, "GoschedInPanic", "panic: errorThatGosched\n\n")
464 func TestPanicDeadlockSyscall(t
*testing
.T
) {
465 testPanicDeadlock(t
, "SyscallInPanic", "1\n2\npanic: 3\n\n")
468 func TestPanicLoop(t
*testing
.T
) {
469 output
:= runTestProg(t
, "testprog", "PanicLoop")
470 if want
:= "panic while printing panic value"; !strings
.Contains(output
, want
) {
471 t
.Errorf("output does not contain %q:\n%s", want
, output
)
475 func TestMemPprof(t
*testing
.T
) {
476 testenv
.MustHaveGoRun(t
)
477 if runtime
.Compiler
== "gccgo" {
478 t
.Skip("gccgo may not have the pprof tool")
481 exe
, err
:= buildTestProg(t
, "testprog")
486 got
, err
:= testEnv(exec
.Command(exe
, "MemProf")).CombinedOutput()
490 fn
:= strings
.TrimSpace(string(got
))
493 for try
:= 0; try
< 2; try
++ {
494 cmd
:= testEnv(exec
.Command(testenv
.GoToolPath(t
), "tool", "pprof", "-alloc_space", "-top"))
495 // Check that pprof works both with and without explicit executable on command line.
497 cmd
.Args
= append(cmd
.Args
, exe
, fn
)
499 cmd
.Args
= append(cmd
.Args
, fn
)
502 for i
, e
:= range cmd
.Env
{
503 if strings
.HasPrefix(e
, "PPROF_TMPDIR=") {
504 cmd
.Env
[i
] = "PPROF_TMPDIR=" + os
.TempDir()
510 cmd
.Env
= append(cmd
.Env
, "PPROF_TMPDIR="+os
.TempDir())
513 top
, err
:= cmd
.CombinedOutput()
514 t
.Logf("%s:\n%s", cmd
.Args
, top
)
517 } else if !bytes
.Contains(top
, []byte("MemProf")) {
518 t
.Error("missing MemProf in pprof output")
523 var concurrentMapTest
= flag
.Bool("run_concurrent_map_tests", false, "also run flaky concurrent map tests")
525 func TestConcurrentMapWrites(t
*testing
.T
) {
526 if !*concurrentMapTest
{
527 t
.Skip("skipping without -run_concurrent_map_tests")
529 testenv
.MustHaveGoRun(t
)
530 output
:= runTestProg(t
, "testprog", "concurrentMapWrites")
531 want
:= "fatal error: concurrent map writes"
532 if !strings
.HasPrefix(output
, want
) {
533 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
536 func TestConcurrentMapReadWrite(t
*testing
.T
) {
537 if !*concurrentMapTest
{
538 t
.Skip("skipping without -run_concurrent_map_tests")
540 testenv
.MustHaveGoRun(t
)
541 output
:= runTestProg(t
, "testprog", "concurrentMapReadWrite")
542 want
:= "fatal error: concurrent map read and map write"
543 if !strings
.HasPrefix(output
, want
) {
544 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
547 func TestConcurrentMapIterateWrite(t
*testing
.T
) {
548 if !*concurrentMapTest
{
549 t
.Skip("skipping without -run_concurrent_map_tests")
551 testenv
.MustHaveGoRun(t
)
552 output
:= runTestProg(t
, "testprog", "concurrentMapIterateWrite")
553 want
:= "fatal error: concurrent map iteration and map write"
554 if !strings
.HasPrefix(output
, want
) {
555 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
563 func (p
*point
) negate() {
568 // Test for issue #10152.
569 func TestPanicInlined(t
*testing
.T
) {
573 t
.Fatalf("recover failed")
575 buf
:= make([]byte, 2048)
576 n
:= runtime
.Stack(buf
, false)
578 want
:= []byte("(*point).negate(")
579 if runtime
.Compiler
== "gccgo" {
580 want
= []byte("negate.pN18_runtime_test.point")
582 if !bytes
.Contains(buf
, want
) {
584 t
.Fatalf("expecting stack trace to contain call to %s", want
)
592 // Test for issues #3934 and #20018.
593 // We want to delay exiting until a panic print is complete.
594 func TestPanicRace(t
*testing
.T
) {
595 testenv
.MustHaveGoRun(t
)
597 exe
, err
:= buildTestProg(t
, "testprog")
602 // The test is intentionally racy, and in my testing does not
603 // produce the expected output about 0.05% of the time.
604 // So run the program in a loop and only fail the test if we
605 // get the wrong output ten times in a row.
608 for i
:= 0; i
< tries
; i
++ {
609 got
, err
:= testEnv(exec
.Command(exe
, "PanicRace")).CombinedOutput()
611 t
.Logf("try %d: program exited successfully, should have failed", i
+1)
616 t
.Logf("try %d:\n", i
+1)
625 if runtime
.Compiler
== "gccgo" {
626 // gccgo will dump a function name like main.$nested30.
627 // Match on the file name instead.
628 wants
[1] = "panicrace"
630 for _
, want
:= range wants
{
631 if !bytes
.Contains(got
, []byte(want
)) {
632 t
.Logf("did not find expected string %q", want
)
637 // Test generated expected output.
640 t
.Errorf("test ran %d times without producing expected output", tries
)