|
7 | 7 | "fmt"
|
8 | 8 | "io"
|
9 | 9 | "os"
|
| 10 | + "strings" |
10 | 11 | "testing"
|
11 | 12 |
|
12 | 13 | googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1"
|
@@ -144,6 +145,78 @@ func TestSymbolizePprof(t *testing.T) {
|
144 | 145 | assertLocationHasFunction(t, p, p.Location[2], "main", "main")
|
145 | 146 | },
|
146 | 147 | },
|
| 148 | + { |
| 149 | + name: "preserve existing symbols when HasFunctions=false", |
| 150 | + // This tests a defensive check against data inconsistency where a mapping has |
| 151 | + // HasFunctions=false but contains locations with existing symbols. |
| 152 | + // This scenario should be rare, but we maintain the check for robustness. |
| 153 | + profile: &googlev1.Profile{ |
| 154 | + Mapping: []*googlev1.Mapping{{ |
| 155 | + Id: 1, |
| 156 | + BuildId: 1, |
| 157 | + Filename: 2, |
| 158 | + MemoryStart: 0x0, |
| 159 | + MemoryLimit: 0x1000000, |
| 160 | + FileOffset: 0x0, |
| 161 | + HasFunctions: false, |
| 162 | + }}, |
| 163 | + Location: []*googlev1.Location{ |
| 164 | + { |
| 165 | + Id: 1, |
| 166 | + MappingId: 1, |
| 167 | + Address: 0x1000, |
| 168 | + Line: []*googlev1.Line{{ |
| 169 | + FunctionId: 1, |
| 170 | + Line: 42, |
| 171 | + }}, |
| 172 | + }, |
| 173 | + { |
| 174 | + Id: 2, |
| 175 | + MappingId: 1, |
| 176 | + Address: 0x1500, |
| 177 | + Line: nil, |
| 178 | + }, |
| 179 | + }, |
| 180 | + Function: []*googlev1.Function{{ |
| 181 | + Id: 1, |
| 182 | + Name: 3, |
| 183 | + }}, |
| 184 | + StringTable: []string{"", "build-id", "alloy", "existing_function"}, |
| 185 | + }, |
| 186 | + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { |
| 187 | + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(openTestFile(t), nil).Once() |
| 188 | + mockBucket.On("Get", mock.Anything, "build-id").Return(nil, fmt.Errorf("not found")).Once() |
| 189 | + mockBucket.On("Upload", mock.Anything, "build-id", mock.Anything).Return(nil).Once() |
| 190 | + }, |
| 191 | + validate: func(t *testing.T, p *googlev1.Profile) { |
| 192 | + require.True(t, p.Mapping[0].HasFunctions) |
| 193 | + |
| 194 | + require.Len(t, p.Location[0].Line, 1) |
| 195 | + require.Equal(t, uint64(1), p.Location[0].Line[0].FunctionId) |
| 196 | + require.Equal(t, "existing_function", p.StringTable[p.Function[0].Name]) |
| 197 | + |
| 198 | + require.Len(t, p.Location[1].Line, 1) |
| 199 | + assertLocationHasFunction(t, p, p.Location[1], "main", "main") |
| 200 | + |
| 201 | + existingFuncStillExists := false |
| 202 | + for _, str := range p.StringTable { |
| 203 | + if str == "existing_function" { |
| 204 | + existingFuncStillExists = true |
| 205 | + break |
| 206 | + } |
| 207 | + } |
| 208 | + require.True(t, existingFuncStillExists) |
| 209 | + |
| 210 | + placeholderFound := false |
| 211 | + for _, str := range p.StringTable { |
| 212 | + if strings.Contains(str, "!0x") { |
| 213 | + placeholderFound = true |
| 214 | + break |
| 215 | + } |
| 216 | + } |
| 217 | + require.False(t, placeholderFound) |
| 218 | + }, |
| 219 | + }, |
147 | 220 | }
|
148 | 221 |
|
149 | 222 | for _, tt := range tests {
|
|
0 commit comments