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  }