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.
18 // testEnv excludes GODEBUG from the environment
19 // to prevent its output from breaking tests that
20 // are trying to parse other command output.
21 func testEnv(cmd
*exec
.Cmd
) *exec
.Cmd
{
23 panic("environment already set")
25 for _
, env
:= range os
.Environ() {
26 if strings
.HasPrefix(env
, "GODEBUG=") {
29 cmd
.Env
= append(cmd
.Env
, env
)
34 func executeTest(t
*testing
.T
, templ
string, data
interface{}) string {
35 t
.Skip("gccgo does not have a go command")
36 if runtime
.GOOS
== "nacl" {
37 t
.Skip("skipping on nacl")
42 st
:= template
.Must(template
.New("crashSource").Parse(templ
))
44 dir
, err
:= ioutil
.TempDir("", "go-build")
46 t
.Fatalf("failed to create temp directory: %v", err
)
48 defer os
.RemoveAll(dir
)
50 src
:= filepath
.Join(dir
, "main.go")
51 f
, err
:= os
.Create(src
)
53 t
.Fatalf("failed to create file: %v", err
)
55 err
= st
.Execute(f
, data
)
58 t
.Fatalf("failed to execute template: %v", err
)
60 if err
:= f
.Close(); err
!= nil {
61 t
.Fatalf("failed to close file: %v", err
)
64 got
, _
:= testEnv(exec
.Command("go", "run", src
)).CombinedOutput()
68 func checkStaleRuntime(t
*testing
.T
) {
69 // 'go run' uses the installed copy of runtime.a, which may be out of date.
70 out
, err
:= testEnv(exec
.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
72 t
.Fatalf("failed to execute 'go list': %v\n%v", err
, string(out
))
74 if string(out
) != "false\n" {
75 t
.Fatalf("Stale runtime.a. Run 'go install runtime'.")
79 func testCrashHandler(t
*testing
.T
, cgo
bool) {
80 type crashTest
struct {
83 output
:= executeTest(t
, crashSource
, &crashTest
{Cgo
: cgo
})
84 want
:= "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
86 t
.Fatalf("output:\n%s\n\nwanted:\n%s", output
, want
)
90 func TestCrashHandler(t
*testing
.T
) {
91 testCrashHandler(t
, false)
94 func testDeadlock(t
*testing
.T
, source
string) {
95 output
:= executeTest(t
, source
, nil)
96 want
:= "fatal error: all goroutines are asleep - deadlock!\n"
97 if !strings
.HasPrefix(output
, want
) {
98 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
102 func TestSimpleDeadlock(t
*testing
.T
) {
103 testDeadlock(t
, simpleDeadlockSource
)
106 func TestInitDeadlock(t
*testing
.T
) {
107 testDeadlock(t
, initDeadlockSource
)
110 func TestLockedDeadlock(t
*testing
.T
) {
111 testDeadlock(t
, lockedDeadlockSource
)
114 func TestLockedDeadlock2(t
*testing
.T
) {
115 testDeadlock(t
, lockedDeadlockSource2
)
118 func TestGoexitDeadlock(t
*testing
.T
) {
119 output
:= executeTest(t
, goexitDeadlockSource
, nil)
120 want
:= "no goroutines (main called runtime.Goexit) - deadlock!"
121 if !strings
.Contains(output
, want
) {
122 t
.Fatalf("output:\n%s\n\nwant output containing: %s", output
, want
)
126 func TestStackOverflow(t
*testing
.T
) {
127 output
:= executeTest(t
, stackOverflowSource
, nil)
128 want
:= "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
129 if !strings
.HasPrefix(output
, want
) {
130 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
134 func TestThreadExhaustion(t
*testing
.T
) {
135 output
:= executeTest(t
, threadExhaustionSource
, nil)
136 want
:= "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
137 if !strings
.HasPrefix(output
, want
) {
138 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
142 func TestRecursivePanic(t
*testing
.T
) {
143 output
:= executeTest(t
, recursivePanicSource
, nil)
148 if !strings
.HasPrefix(output
, want
) {
149 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
154 func TestGoexitCrash(t
*testing
.T
) {
155 output
:= executeTest(t
, goexitExitSource
, nil)
156 want
:= "no goroutines (main called runtime.Goexit) - deadlock!"
157 if !strings
.Contains(output
, want
) {
158 t
.Fatalf("output:\n%s\n\nwant output containing: %s", output
, want
)
162 func TestGoNil(t
*testing
.T
) {
163 output
:= executeTest(t
, goNilSource
, nil)
164 want
:= "go of nil func value"
165 if !strings
.Contains(output
, want
) {
166 t
.Fatalf("output:\n%s\n\nwant output containing: %s", output
, want
)
170 const crashSource
= `
182 func test(name string) {
184 if x := recover(); x != nil {
185 fmt.Printf(" recovered")
187 fmt.Printf(" done\n")
189 fmt.Printf("%s:", name)
192 fmt.Print("SHOULD NOT BE HERE")
195 func testInNewThread(name string) {
198 runtime.LockOSThread()
206 runtime.LockOSThread()
208 testInNewThread("new-thread")
209 testInNewThread("second-new-thread")
214 const simpleDeadlockSource
= `
221 const initDeadlockSource
= `
230 const lockedDeadlockSource
= `
234 runtime.LockOSThread()
239 const lockedDeadlockSource2
= `
247 runtime.LockOSThread()
250 time.Sleep(time.Millisecond)
255 const goexitDeadlockSource
= `
262 for i := 0; i < 10; i++ {
273 const stackOverflowSource
= `
276 import "runtime/debug"
279 debug.SetMaxStack(4<<20)
283 func f(x []byte) byte {
285 return x[0] + f(buf[:])
289 const threadExhaustionSource
= `
298 debug.SetMaxThreads(10)
300 for i := 0; i < 100; i++ {
302 runtime.LockOSThread()
311 const recursivePanicSource
= `
321 fmt.Println(recover())
326 if err := recover(); err != nil {
327 panic("wrap: " + err.(string))
337 const goexitExitSource
= `
347 time.Sleep(time.Millisecond)
350 runtime.SetFinalizer(&i, func(p *int) {})
356 const goNilSource
= `