Source file src/runtime/debug/stack_test.go

     1  // Copyright 2011 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  package debug_test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"runtime"
    15  	. "runtime/debug"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  func TestMain(m *testing.M) {
    21  	if os.Getenv("GO_RUNTIME_DEBUG_TEST_DUMP_GOROOT") != "" {
    22  		fmt.Println(runtime.GOROOT())
    23  		os.Exit(0)
    24  	}
    25  	os.Exit(m.Run())
    26  }
    27  
    28  type T int
    29  
    30  func (t *T) ptrmethod() []byte {
    31  	return Stack()
    32  }
    33  func (t T) method() []byte {
    34  	return t.ptrmethod()
    35  }
    36  
    37  /*
    38  The traceback should look something like this, modulo line numbers and hex constants.
    39  Don't worry much about the base levels, but check the ones in our own package.
    40  
    41  	goroutine 10 [running]:
    42  	runtime/debug.Stack(0x0, 0x0, 0x0)
    43  		/Users/r/go/src/runtime/debug/stack.go:28 +0x80
    44  	runtime/debug.(*T).ptrmethod(0xc82005ee70, 0x0, 0x0, 0x0)
    45  		/Users/r/go/src/runtime/debug/stack_test.go:15 +0x29
    46  	runtime/debug.T.method(0x0, 0x0, 0x0, 0x0)
    47  		/Users/r/go/src/runtime/debug/stack_test.go:18 +0x32
    48  	runtime/debug.TestStack(0xc8201ce000)
    49  		/Users/r/go/src/runtime/debug/stack_test.go:37 +0x38
    50  	testing.tRunner(0xc8201ce000, 0x664b58)
    51  		/Users/r/go/src/testing/testing.go:456 +0x98
    52  	created by testing.RunTests
    53  		/Users/r/go/src/testing/testing.go:561 +0x86d
    54  */
    55  func TestStack(t *testing.T) {
    56  	b := T(0).method()
    57  	lines := strings.Split(string(b), "\n")
    58  	if len(lines) < 6 {
    59  		t.Fatal("too few lines")
    60  	}
    61  
    62  	// If built with -trimpath, file locations should start with package paths.
    63  	// Otherwise, file locations should start with a GOROOT/src prefix
    64  	// (for whatever value of GOROOT is baked into the binary, not the one
    65  	// that may be set in the environment).
    66  	fileGoroot := ""
    67  	if envGoroot := os.Getenv("GOROOT"); envGoroot != "" {
    68  		// Since GOROOT is set explicitly in the environment, we can't be certain
    69  		// that it is the same GOROOT value baked into the binary, and we can't
    70  		// change the value in-process because runtime.GOROOT uses the value from
    71  		// initial (not current) environment. Spawn a subprocess to determine the
    72  		// real baked-in GOROOT.
    73  		t.Logf("found GOROOT %q from environment; checking embedded GOROOT value", envGoroot)
    74  		testenv.MustHaveExec(t)
    75  		exe, err := os.Executable()
    76  		if err != nil {
    77  			t.Fatal(err)
    78  		}
    79  		cmd := exec.Command(exe)
    80  		cmd.Env = append(os.Environ(), "GOROOT=", "GO_RUNTIME_DEBUG_TEST_DUMP_GOROOT=1")
    81  		out, err := cmd.Output()
    82  		if err != nil {
    83  			t.Fatal(err)
    84  		}
    85  		fileGoroot = string(bytes.TrimSpace(out))
    86  	} else {
    87  		// Since GOROOT is not set in the environment, its value (if any) must come
    88  		// from the path embedded in the binary.
    89  		fileGoroot = runtime.GOROOT()
    90  	}
    91  	filePrefix := ""
    92  	if fileGoroot != "" {
    93  		filePrefix = filepath.ToSlash(fileGoroot) + "/src/"
    94  	}
    95  
    96  	n := 0
    97  	frame := func(file, code string) {
    98  		t.Helper()
    99  
   100  		line := lines[n]
   101  		if !strings.Contains(line, code) {
   102  			t.Errorf("expected %q in %q", code, line)
   103  		}
   104  		n++
   105  
   106  		line = lines[n]
   107  
   108  		wantPrefix := "\t" + filePrefix + file
   109  		if !strings.HasPrefix(line, wantPrefix) {
   110  			t.Errorf("in line %q, expected prefix %q", line, wantPrefix)
   111  		}
   112  		n++
   113  	}
   114  	n++
   115  
   116  	frame("runtime/debug/stack.go", "runtime/debug.Stack")
   117  	frame("runtime/debug/stack_test.go", "runtime/debug_test.(*T).ptrmethod")
   118  	frame("runtime/debug/stack_test.go", "runtime/debug_test.T.method")
   119  	frame("runtime/debug/stack_test.go", "runtime/debug_test.TestStack")
   120  	frame("testing/testing.go", "")
   121  }
   122  

View as plain text