github.com/newrelic/go-agent@v3.26.0+incompatible/internal/stacktrace_test.go (about) 1 // Copyright 2020 New Relic Corporation. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package internal 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "strings" 10 "testing" 11 12 "github.com/newrelic/go-agent/internal/stacktracetest" 13 ) 14 15 func TestGetStackTrace(t *testing.T) { 16 stack := GetStackTrace() 17 js, err := json.Marshal(stack) 18 if nil != err { 19 t.Fatal(err) 20 } 21 if nil == js { 22 t.Fatal(string(js)) 23 } 24 } 25 26 func TestLongStackTraceLimitsFrames(t *testing.T) { 27 st := stacktracetest.CountedCall(maxStackTraceFrames+20, func() []uintptr { 28 return GetStackTrace() 29 }) 30 if len(st) != maxStackTraceFrames { 31 t.Error("Unexpected size of stacktrace", maxStackTraceFrames, len(st)) 32 } 33 l := len(StackTrace(st).frames()) 34 if l != maxStackTraceFrames { 35 t.Error("Unexpected number of frames", maxStackTraceFrames, l) 36 } 37 } 38 39 func TestManyStackTraceFramesLimitsOutput(t *testing.T) { 40 frames := make([]stacktraceFrame, maxStackTraceFrames+20) 41 expect := `[ 42 {},{},{},{},{},{},{},{},{},{}, 43 {},{},{},{},{},{},{},{},{},{}, 44 {},{},{},{},{},{},{},{},{},{}, 45 {},{},{},{},{},{},{},{},{},{}, 46 {},{},{},{},{},{},{},{},{},{}, 47 {},{},{},{},{},{},{},{},{},{}, 48 {},{},{},{},{},{},{},{},{},{}, 49 {},{},{},{},{},{},{},{},{},{}, 50 {},{},{},{},{},{},{},{},{},{}, 51 {},{},{},{},{},{},{},{},{},{} 52 ]` 53 estimate := 256 * len(frames) 54 output := bytes.NewBuffer(make([]byte, 0, estimate)) 55 writeFrames(output, frames) 56 if CompactJSONString(expect) != output.String() { 57 t.Error("Unexpected JSON output", CompactJSONString(expect), output.String()) 58 } 59 } 60 61 func TestStacktraceFrames(t *testing.T) { 62 // This stacktrace taken from Go 1.11 63 inputFrames := []stacktraceFrame{ 64 { 65 File: "/Users/will/Desktop/gopath/src/github.com/newrelic/go-agent/internal/stacktrace.go", 66 Name: "github.com/newrelic/go-agent/internal.GetStackTrace", 67 Line: 17, 68 }, 69 { 70 File: "/Users/will/Desktop/gopath/src/github.com/newrelic/go-agent/internal_txn.go", 71 Name: "github.com/newrelic/go-agent.(*txn).NoticeError", 72 Line: 696, 73 }, 74 { 75 File: "\u003cautogenerated\u003e", 76 Name: "go.(*struct { github.com/newrelic/go-agent.threadWithExtras }).NoticeError", 77 Line: 1, 78 }, 79 { 80 File: "/Users/will/Desktop/gopath/src/github.com/newrelic/go-agent/internal_attributes_test.go", 81 Name: "github.com/newrelic/go-agent.TestAddAttributeSecurityPolicyDisablesInclude", 82 Line: 68, 83 }, 84 { 85 File: "/Users/will/.gvm/gos/go1.11/src/testing/testing.go", 86 Name: "testing.tRunner", 87 Line: 827, 88 }, 89 { 90 File: "/Users/will/.gvm/gos/go1.11/src/runtime/asm_amd64.s", 91 Name: "runtime.goexit", 92 Line: 1333, 93 }, 94 } 95 buf := &bytes.Buffer{} 96 writeFrames(buf, inputFrames) 97 expectedJSON := `[ 98 { 99 "name":"testing.tRunner", 100 "filepath":"/Users/will/.gvm/gos/go1.11/src/testing/testing.go", 101 "line":827 102 }, 103 { 104 "name":"runtime.goexit", 105 "filepath":"/Users/will/.gvm/gos/go1.11/src/runtime/asm_amd64.s", 106 "line":1333 107 } 108 ]` 109 testExpectedJSON(t, expectedJSON, buf.String()) 110 } 111 112 func TestStackTraceTopFrame(t *testing.T) { 113 // This test uses a separate package since the stacktrace code removes 114 // the top stack frames which are in packages "newrelic" and "internal". 115 stackJSON := stacktracetest.TopStackFrame(func() []byte { 116 st := GetStackTrace() 117 js, _ := json.Marshal(st) 118 return js 119 }) 120 121 stack := []struct { 122 Name string `json:"name"` 123 FilePath string `json:"filepath"` 124 Line int `json:"line"` 125 }{} 126 if err := json.Unmarshal(stackJSON, &stack); err != nil { 127 t.Fatal(err) 128 } 129 if len(stack) < 2 { 130 t.Fatal(string(stackJSON)) 131 } 132 if stack[0].Name != "stacktracetest.TopStackFrame" { 133 t.Error(string(stackJSON)) 134 } 135 if stack[0].Line != 9 { 136 t.Error(string(stackJSON)) 137 } 138 if !strings.Contains(stack[0].FilePath, "go-agent/internal/stacktracetest/stacktracetest.go") { 139 t.Error(string(stackJSON)) 140 } 141 } 142 143 func TestFramesCount(t *testing.T) { 144 st := stacktracetest.CountedCall(3, func() []uintptr { 145 return GetStackTrace() 146 }) 147 frames := StackTrace(st).frames() 148 if len(st) != len(frames) { 149 t.Error("Invalid # of frames", len(st), len(frames)) 150 } 151 }