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 {
38 target map[string]buildexe
41 type buildexe struct {
46 func runTestProg(t *testing.T, binary, name string, env ...string) string {
51 testenv.MustHaveGoBuild(t)
53 exe, err := buildTestProg(t, binary)
58 cmd := testenv.CleanCmdEnv(exec.Command(exe, name))
59 cmd.Env = append(cmd.Env, env...)
61 cmd.Env = append(cmd.Env, "RUNTIME_TEST_SHORT=1")
66 if err := cmd.Start(); err != nil {
67 t.Fatalf("starting %s %s: %v", binary, name, err)
70 // If the process doesn't complete within 1 minute,
71 // assume it is hanging and kill it to get a stack trace.
73 done := make(chan bool)
76 // This GOARCH/GOOS test is copied from cmd/dist/test.go.
77 // TODO(iant): Have cmd/dist update the environment variable.
78 if runtime.GOARCH == "arm" || runtime.GOOS == "windows" {
81 if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
82 if sc, err := strconv.Atoi(s); err == nil {
89 case <-time.After(time.Duration(scale) * time.Minute):
94 if err := cmd.Wait(); err != nil {
95 t.Logf("%s %s exit status: %v", binary, name, err)
102 func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) {
108 defer testprog.Unlock()
109 if testprog.dir == "" {
110 dir, err := ioutil.TempDir("", "go-build")
112 t.Fatalf("failed to create temp directory: %v", err)
115 toRemove = append(toRemove, dir)
118 if testprog.target == nil {
119 testprog.target = make(map[string]buildexe)
123 name += "_" + strings.Join(flags, "_")
125 target, ok := testprog.target[name]
127 return target.exe, target.err
130 exe := filepath.Join(testprog.dir, name+".exe")
131 cmd := exec.Command(testenv.GoToolPath(t), append([]string{"build", "-o", exe}, flags...)...)
132 cmd.Dir = "testdata/" + binary
133 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
135 target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out)
136 testprog.target[name] = target
137 return "", target.err
140 testprog.target[name] = target
144 func TestVDSO(t *testing.T) {
146 output := runTestProg(t, "testprog", "SignalInVDSO")
149 t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
153 func testCrashHandler(t *testing.T, cgo bool) {
154 type crashTest struct {
159 output = runTestProg(t, "testprogcgo", "Crash")
161 output = runTestProg(t, "testprog", "Crash")
163 want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
165 t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
169 func TestCrashHandler(t *testing.T) {
170 testCrashHandler(t, false)
173 func testDeadlock(t *testing.T, name string) {
174 output := runTestProg(t, "testprog", name)
175 want := "fatal error: all goroutines are asleep - deadlock!\n"
176 if !strings.HasPrefix(output, want) {
177 t.Fatalf("output does not start with %q:\n%s", want, output)
181 func TestSimpleDeadlock(t *testing.T) {
182 testDeadlock(t, "SimpleDeadlock")
185 func TestInitDeadlock(t *testing.T) {
186 testDeadlock(t, "InitDeadlock")
189 func TestLockedDeadlock(t *testing.T) {
190 testDeadlock(t, "LockedDeadlock")
193 func TestLockedDeadlock2(t *testing.T) {
194 testDeadlock(t, "LockedDeadlock2")
197 func TestGoexitDeadlock(t *testing.T) {
198 output := runTestProg(t, "testprog", "GoexitDeadlock")
199 want := "no goroutines (main called runtime.Goexit) - deadlock!"
200 if !strings.Contains(output, want) {
201 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
205 func TestStackOverflow(t *testing.T) {
206 output := runTestProg(t, "testprog", "StackOverflow")
207 want := "runtime: goroutine stack exceeds 1474560-byte limit\nfatal error: stack overflow"
208 if !strings.HasPrefix(output, want) {
209 t.Fatalf("output does not start with %q:\n%s", want, output)
213 func TestThreadExhaustion(t *testing.T) {
214 output := runTestProg(t, "testprog", "ThreadExhaustion")
215 want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
216 if !strings.HasPrefix(output, want) {
217 t.Fatalf("output does not start with %q:\n%s", want, output)
221 func TestRecursivePanic(t *testing.T) {
222 output := runTestProg(t, "testprog", "RecursivePanic")
227 if !strings.HasPrefix(output, want) {
228 t.Fatalf("output does not start with %q:\n%s", want, output)
233 func TestRecursivePanic2(t *testing.T) {
234 output := runTestProg(t, "testprog", "RecursivePanic2")
240 if !strings.HasPrefix(output, want) {
241 t.Fatalf("output does not start with %q:\n%s", want, output)
246 func TestRecursivePanic3(t *testing.T) {
247 output := runTestProg(t, "testprog", "RecursivePanic3")
248 want := `panic: first panic
251 if !strings.HasPrefix(output, want) {
252 t.Fatalf("output does not start with %q:\n%s", want, output)
257 func TestRecursivePanic4(t *testing.T) {
258 output := runTestProg(t, "testprog", "RecursivePanic4")
259 want := `panic: first panic [recovered]
262 if !strings.HasPrefix(output, want) {
263 t.Fatalf("output does not start with %q:\n%s", want, output)
268 func TestGoexitCrash(t *testing.T) {
269 output := runTestProg(t, "testprog", "GoexitExit")
270 want := "no goroutines (main called runtime.Goexit) - deadlock!"
271 if !strings.Contains(output, want) {
272 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
276 func TestGoexitDefer(t *testing.T) {
277 c := make(chan struct{})
282 t.Errorf("non-nil recover during Goexit")
288 // Note: if the defer fails to run, we will get a deadlock here
292 func TestGoNil(t *testing.T) {
293 output := runTestProg(t, "testprog", "GoNil")
294 want := "go of nil func value"
295 if !strings.Contains(output, want) {
296 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
300 func TestMainGoroutineID(t *testing.T) {
301 output := runTestProg(t, "testprog", "MainGoroutineID")
302 want := "panic: test\n\ngoroutine 1 [running]:\n"
303 if !strings.HasPrefix(output, want) {
304 t.Fatalf("output does not start with %q:\n%s", want, output)
308 func TestNoHelperGoroutines(t *testing.T) {
309 output := runTestProg(t, "testprog", "NoHelperGoroutines")
310 matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
311 if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
312 t.Fatalf("want to see only goroutine 1, see:\n%s", output)
316 func TestBreakpoint(t *testing.T) {
317 output := runTestProg(t, "testprog", "Breakpoint")
318 // If runtime.Breakpoint() is inlined, then the stack trace prints
319 // "runtime.Breakpoint(...)" instead of "runtime.Breakpoint()".
320 want := "runtime.Breakpoint("
321 if !strings.Contains(output, want) {
322 t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
326 func TestGoexitInPanic(t *testing.T) {
327 // see issue 8774: this code used to trigger an infinite recursion
328 output := runTestProg(t, "testprog", "GoexitInPanic")
329 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
330 if !strings.HasPrefix(output, want) {
331 t.Fatalf("output does not start with %q:\n%s", want, output)
335 // Issue 14965: Runtime panics should be of type runtime.Error
336 func TestRuntimePanicWithRuntimeError(t *testing.T) {
337 testCases := [...]func(){
339 var m map[uint64]bool
343 ch := make(chan struct{})
348 var ch = make(chan struct{})
353 var s = make([]int, 2)
358 _ = make(chan bool, n)
361 close((chan bool)(nil))
365 for i, fn := range testCases {
366 got := panicValue(fn)
367 if _, ok := got.(runtime.Error); !ok {
368 t.Errorf("test #%d: recovered value %v(type %T) does not implement runtime.Error", i, got, got)
373 func panicValue(fn func()) (recovered interface{}) {
375 recovered = recover()
381 func TestPanicAfterGoexit(t *testing.T) {
382 // an uncaught panic should still work after goexit
383 output := runTestProg(t, "testprog", "PanicAfterGoexit")
384 want := "panic: hello"
385 if !strings.HasPrefix(output, want) {
386 t.Fatalf("output does not start with %q:\n%s", want, output)
390 func TestRecoveredPanicAfterGoexit(t *testing.T) {
391 output := runTestProg(t, "testprog", "RecoveredPanicAfterGoexit")
392 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
393 if !strings.HasPrefix(output, want) {
394 t.Fatalf("output does not start with %q:\n%s", want, output)
398 func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
400 output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit")
401 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
402 if !strings.HasPrefix(output, want) {
403 t.Fatalf("output does not start with %q:\n%s", want, output)
407 func TestRecoverBeforePanicAfterGoexit2(t *testing.T) {
409 output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit2")
410 want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
411 if !strings.HasPrefix(output, want) {
412 t.Fatalf("output does not start with %q:\n%s", want, output)
416 func TestNetpollDeadlock(t *testing.T) {
417 if os.Getenv("GO_BUILDER_NAME") == "darwin-amd64-10_12" {
418 // A suspected kernel bug in macOS 10.12 occasionally results in
419 // an apparent deadlock when dialing localhost. The errors have not
420 // been observed on newer versions of the OS, so we don't plan to work
421 // around them. See https://golang.org/issue/22019.
422 testenv.SkipFlaky(t, 22019)
426 output := runTestProg(t, "testprognet", "NetpollDeadlock")
428 if !strings.HasSuffix(output, want) {
429 t.Fatalf("output does not start with %q:\n%s", want, output)
433 func TestPanicTraceback(t *testing.T) {
435 output := runTestProg(t, "testprog", "PanicTraceback")
436 want := "panic: hello\n\tpanic: panic pt2\n\tpanic: panic pt1\n"
437 if !strings.HasPrefix(output, want) {
438 t.Fatalf("output does not start with %q:\n%s", want, output)
441 // Check functions in the traceback.
442 fns := []string{"main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
443 for _, fn := range fns {
444 re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
445 idx := re.FindStringIndex(output)
447 t.Fatalf("expected %q function in traceback:\n%s", fn, output)
449 output = output[idx[1]:]
453 func testPanicDeadlock(t *testing.T, name string, want string) {
455 output := runTestProg(t, "testprog", name)
456 if !strings.HasPrefix(output, want) {
457 t.Fatalf("output does not start with %q:\n%s", want, output)
461 func TestPanicDeadlockGosched(t *testing.T) {
462 testPanicDeadlock(t, "GoschedInPanic", "panic: errorThatGosched\n\n")
465 func TestPanicDeadlockSyscall(t *testing.T) {
466 testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n")
469 func TestPanicLoop(t *testing.T) {
470 output := runTestProg(t, "testprog", "PanicLoop")
471 if want := "panic while printing panic value"; !strings.Contains(output, want) {
472 t.Errorf("output does not contain %q:\n%s", want, output)
476 func TestMemPprof(t *testing.T) {
477 testenv.MustHaveGoRun(t)
479 exe, err := buildTestProg(t, "testprog")
484 got, err := testenv.CleanCmdEnv(exec.Command(exe, "MemProf")).CombinedOutput()
488 fn := strings.TrimSpace(string(got))
491 for try := 0; try < 2; try++ {
492 cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top"))
493 // Check that pprof works both with and without explicit executable on command line.
495 cmd.Args = append(cmd.Args, exe, fn)
497 cmd.Args = append(cmd.Args, fn)
500 for i, e := range cmd.Env {
501 if strings.HasPrefix(e, "PPROF_TMPDIR=") {
502 cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
508 cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
511 top, err := cmd.CombinedOutput()
512 t.Logf("%s:\n%s", cmd.Args, top)
515 } else if !bytes.Contains(top, []byte("MemProf")) {
516 t.Error("missing MemProf in pprof output")
521 var concurrentMapTest = flag.Bool("run_concurrent_map_tests", false, "also run flaky concurrent map tests")
523 func TestConcurrentMapWrites(t *testing.T) {
524 if !*concurrentMapTest {
525 t.Skip("skipping without -run_concurrent_map_tests")
527 testenv.MustHaveGoRun(t)
528 output := runTestProg(t, "testprog", "concurrentMapWrites")
529 want := "fatal error: concurrent map writes"
530 if !strings.HasPrefix(output, want) {
531 t.Fatalf("output does not start with %q:\n%s", want, output)
534 func TestConcurrentMapReadWrite(t *testing.T) {
535 if !*concurrentMapTest {
536 t.Skip("skipping without -run_concurrent_map_tests")
538 testenv.MustHaveGoRun(t)
539 output := runTestProg(t, "testprog", "concurrentMapReadWrite")
540 want := "fatal error: concurrent map read and map write"
541 if !strings.HasPrefix(output, want) {
542 t.Fatalf("output does not start with %q:\n%s", want, output)
545 func TestConcurrentMapIterateWrite(t *testing.T) {
546 if !*concurrentMapTest {
547 t.Skip("skipping without -run_concurrent_map_tests")
549 testenv.MustHaveGoRun(t)
550 output := runTestProg(t, "testprog", "concurrentMapIterateWrite")
551 want := "fatal error: concurrent map iteration and map write"
552 if !strings.HasPrefix(output, want) {
553 t.Fatalf("output does not start with %q:\n%s", want, output)
561 func (p *point) negate() {
566 // Test for issue #10152.
567 func TestPanicInlined(t *testing.T) {
571 t.Fatalf("recover failed")
573 buf := make([]byte, 2048)
574 n := runtime.Stack(buf, false)
576 if !bytes.Contains(buf, []byte("(*point).negate(")) {
577 t.Fatalf("expecting stack trace to contain call to (*point).negate()")
585 // Test for issues #3934 and #20018.
586 // We want to delay exiting until a panic print is complete.
587 func TestPanicRace(t *testing.T) {
588 testenv.MustHaveGoRun(t)
590 exe, err := buildTestProg(t, "testprog")
595 // The test is intentionally racy, and in my testing does not
596 // produce the expected output about 0.05% of the time.
597 // So run the program in a loop and only fail the test if we
598 // get the wrong output ten times in a row.
601 for i := 0; i < tries; i++ {
602 got, err := testenv.CleanCmdEnv(exec.Command(exe, "PanicRace")).CombinedOutput()
604 t.Logf("try %d: program exited successfully, should have failed", i+1)
609 t.Logf("try %d:\n", i+1)
618 for _, want := range wants {
619 if !bytes.Contains(got, []byte(want)) {
620 t.Logf("did not find expected string %q", want)
625 // Test generated expected output.
628 t.Errorf("test ran %d times without producing expected output", tries)
631 func TestBadTraceback(t *testing.T) {
632 output := runTestProg(t, "testprog", "BadTraceback")
633 for _, want := range []string{
634 "runtime: unexpected return pc",
636 "00000bad", // Smashed LR in hex dump
637 "<main.badLR", // Symbolization in hex dump (badLR1 or badLR2)
639 if !strings.Contains(output, want) {
640 t.Errorf("output does not contain %q:\n%s", want, output)
645 func TestTimePprof(t *testing.T) {
646 fn := runTestProg(t, "testprog", "TimeProf")
647 fn = strings.TrimSpace(fn)
650 cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1", fn))
651 cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
652 top, err := cmd.CombinedOutput()
656 } else if bytes.Contains(top, []byte("ExternalCode")) {
657 t.Error("profiler refers to ExternalCode")
661 // Test that runtime.abort does so.
662 func TestAbort(t *testing.T) {
663 // Pass GOTRACEBACK to ensure we get runtime frames.
664 output := runTestProg(t, "testprog", "Abort", "GOTRACEBACK=system")
665 if want := "runtime.abort"; !strings.Contains(output, want) {
666 t.Errorf("output does not contain %q:\n%s", want, output)
668 if strings.Contains(output, "BAD") {
669 t.Errorf("output contains BAD:\n%s", output)
671 // Check that it's a signal traceback.
673 // For systems that use a breakpoint, check specifically for that.
674 switch runtime.GOARCH {
676 switch runtime.GOOS {
678 want = "sys: breakpoint"
680 want = "Exception 0x80000003"
685 if !strings.Contains(output, want) {
686 t.Errorf("output does not contain %q:\n%s", want, output)
690 // For TestRuntimePanic: test a panic in the runtime package without
691 // involving the testing harness.
693 if os.Getenv("GO_TEST_RUNTIME_PANIC") == "1" {
695 if r := recover(); r != nil {
696 // We expect to crash, so exit 0
697 // to indicate failure.
701 runtime.PanicForTesting(nil, 1)
702 // We expect to crash, so exit 0 to indicate failure.
707 func TestRuntimePanic(t *testing.T) {
708 testenv.MustHaveExec(t)
709 cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestRuntimePanic"))
710 cmd.Env = append(cmd.Env, "GO_TEST_RUNTIME_PANIC=1")
711 out, err := cmd.CombinedOutput()
714 t.Error("child process did not fail")
715 } else if want := "runtime.unexportedPanicForTesting"; !bytes.Contains(out, []byte(want)) {
716 t.Errorf("output did not contain expected string %q", want)
720 // Test that g0 stack overflows are handled gracefully.
721 func TestG0StackOverflow(t *testing.T) {
722 testenv.MustHaveExec(t)
724 switch runtime.GOOS {
725 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "android":
726 t.Skipf("g0 stack is wrong on pthread platforms (see golang.org/issue/26061)")
729 if os.Getenv("TEST_G0_STACK_OVERFLOW") != "1" {
730 cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestG0StackOverflow", "-test.v"))
731 cmd.Env = append(cmd.Env, "TEST_G0_STACK_OVERFLOW=1")
732 out, err := cmd.CombinedOutput()
733 // Don't check err since it's expected to crash.
734 if n := strings.Count(string(out), "morestack on g0\n"); n != 1 {
735 t.Fatalf("%s\n(exit status %v)", out, err)
737 // Check that it's a signal-style traceback.
738 if runtime.GOOS != "windows" {
739 if want := "PC="; !strings.Contains(string(out), want) {
740 t.Errorf("output does not contain %q:\n%s", want, out)
746 runtime.G0StackOverflow()
749 // Test that panic message is not clobbered.
751 func TestDoublePanic(t *testing.T) {
752 output := runTestProg(t, "testprog", "DoublePanic", "GODEBUG=clobberfree=1")
753 wants := []string{"panic: XXX", "panic: YYY"}
754 for _, want := range wants {
755 if !strings.Contains(output, want) {
756 t.Errorf("output:\n%s\n\nwant output containing: %s", output, want)