github.com/grafana/pyroscope@v1.18.0/pkg/model/stacktraces_test.go (about)

     1  package model
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  
     8  	ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1"
     9  )
    10  
    11  func TestStackTraceMerger(t *testing.T) {
    12  	for _, tc := range []struct {
    13  		name     string
    14  		in       []*ingestv1.MergeProfilesStacktracesResult
    15  		maxNodes int64
    16  		expected *Tree
    17  	}{
    18  		{
    19  			name:     "empty",
    20  			in:       []*ingestv1.MergeProfilesStacktracesResult{},
    21  			expected: newTree(nil),
    22  		},
    23  		{
    24  			name: "single",
    25  			in: []*ingestv1.MergeProfilesStacktracesResult{
    26  				{
    27  					Stacktraces: []*ingestv1.StacktraceSample{
    28  						{
    29  							FunctionIds: []int32{1, 0},
    30  							Value:       1,
    31  						},
    32  						{
    33  							FunctionIds: []int32{2, 1, 0},
    34  							Value:       3,
    35  						},
    36  					},
    37  					FunctionNames: []string{"my", "other", "stack"},
    38  				},
    39  			},
    40  			expected: newTree([]stacktraces{
    41  				{locations: []string{"other", "my"}, value: 1},
    42  				{locations: []string{"stack", "other", "my"}, value: 3},
    43  			}),
    44  		},
    45  		{
    46  			name: "multiple",
    47  			in: []*ingestv1.MergeProfilesStacktracesResult{
    48  				{
    49  					Stacktraces: []*ingestv1.StacktraceSample{
    50  						{
    51  							FunctionIds: []int32{1, 0},
    52  							Value:       1,
    53  						},
    54  						{
    55  							FunctionIds: []int32{2, 1, 0},
    56  							Value:       3,
    57  						},
    58  						{
    59  							FunctionIds: []int32{3},
    60  							Value:       4,
    61  						},
    62  					},
    63  					FunctionNames: []string{"my", "other", "stack", "foo"},
    64  				},
    65  				{
    66  					Stacktraces: []*ingestv1.StacktraceSample{
    67  						{
    68  							FunctionIds: []int32{1, 0},
    69  							Value:       1,
    70  						},
    71  						{
    72  							FunctionIds: []int32{2, 1, 0},
    73  							Value:       3,
    74  						},
    75  						{
    76  							FunctionIds: []int32{3},
    77  							Value:       5,
    78  						},
    79  					},
    80  					FunctionNames: []string{"my", "other", "stack", "bar"},
    81  				},
    82  			},
    83  			expected: newTree([]stacktraces{
    84  				{locations: []string{"bar"}, value: 5},
    85  				{locations: []string{"foo"}, value: 4},
    86  				{locations: []string{"other", "my"}, value: 2},
    87  				{locations: []string{"stack", "other", "my"}, value: 6},
    88  			}),
    89  		},
    90  		{
    91  			name:     "multiple with truncation",
    92  			maxNodes: 3,
    93  			in: []*ingestv1.MergeProfilesStacktracesResult{
    94  				{
    95  					Stacktraces: []*ingestv1.StacktraceSample{
    96  						{
    97  							FunctionIds: []int32{1, 0},
    98  							Value:       1,
    99  						},
   100  						{
   101  							FunctionIds: []int32{2, 1, 0},
   102  							Value:       3,
   103  						},
   104  						{
   105  							FunctionIds: []int32{3},
   106  							Value:       4,
   107  						},
   108  					},
   109  					FunctionNames: []string{"my", "qux", "stack", "foo"},
   110  				},
   111  				{
   112  					Stacktraces: []*ingestv1.StacktraceSample{
   113  						{
   114  							FunctionIds: []int32{1, 0},
   115  							Value:       1,
   116  						},
   117  						{
   118  							FunctionIds: []int32{2, 1, 0},
   119  							Value:       3,
   120  						},
   121  						{
   122  							FunctionIds: []int32{3},
   123  							Value:       5,
   124  						},
   125  					},
   126  					FunctionNames: []string{"my", "qux", "stack", "bar"},
   127  				},
   128  			},
   129  			expected: newTree([]stacktraces{
   130  				{locations: []string{"other"}, value: 9},
   131  				{locations: []string{"qux", "my"}, value: 2},
   132  				{locations: []string{"stack", "qux", "my"}, value: 6},
   133  			}),
   134  		},
   135  	} {
   136  		tc := tc
   137  		t.Run(tc.name, func(t *testing.T) {
   138  			m := NewStackTraceMerger()
   139  			for _, x := range tc.in {
   140  				m.MergeStackTraces(x.Stacktraces, x.FunctionNames)
   141  			}
   142  			yn := m.TreeBytes(tc.maxNodes)
   143  			actual, err := UnmarshalTree(yn)
   144  			require.NoError(t, err)
   145  			require.Equal(t, tc.expected.String(), actual.String())
   146  		})
   147  	}
   148  }