github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/protocol/decoder/pyroscope/decoder_test.go (about)

     1  // Copyright 2023 iLogtail Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package pyroscope
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"encoding/json"
    21  	"net/http"
    22  	"os"
    23  	"sort"
    24  	"testing"
    25  
    26  	"github.com/alibaba/ilogtail/pkg/helper"
    27  	"github.com/alibaba/ilogtail/pkg/protocol"
    28  
    29  	"github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func TestDecoder_DecodeTire(t *testing.T) {
    35  
    36  	type value struct {
    37  		k string
    38  		v uint64
    39  	}
    40  	values := []value{
    41  		{"foo;bar;baz", 1},
    42  		{"foo;bar;baz;a", 1},
    43  		{"foo;bar;baz;b", 1},
    44  		{"foo;bar;baz;c", 1},
    45  
    46  		{"foo;bar;bar", 1},
    47  
    48  		{"foo;bar;qux", 1},
    49  
    50  		{"foo;bax;bar", 1},
    51  
    52  		{"zoo;boo", 1},
    53  		{"zoo;bao", 1},
    54  	}
    55  
    56  	trie := transporttrie.New()
    57  	for _, v := range values {
    58  		trie.Insert([]byte(v.k), v.v)
    59  	}
    60  	var buf bytes.Buffer
    61  	trie.Serialize(&buf)
    62  	println(buf.String())
    63  	request, err := http.NewRequest("POST", "http://localhost:8080?aggregationType=sum&from=1673495500&name=demo.cpu{a=b}&sampleRate=100&spyName=ebpfspy&units=samples&until=1673495510", &buf)
    64  	request.Header.Set("Content-Type", "binary/octet-stream+trie")
    65  	assert.NoError(t, err)
    66  	d := new(Decoder)
    67  	logs, err := d.Decode(buf.Bytes(), request, map[string]string{"cluster": "sls-mall"})
    68  	assert.NoError(t, err)
    69  	assert.True(t, len(logs) == 9)
    70  	log := logs[1]
    71  	require.Equal(t, ReadLogVal(log, "name"), "baz")
    72  	require.Equal(t, ReadLogVal(log, "stack"), "bar\nfoo")
    73  	require.Equal(t, ReadLogVal(log, "language"), "ebpf")
    74  	require.Equal(t, ReadLogVal(log, "type"), "profile_cpu")
    75  	require.Equal(t, ReadLogVal(log, "units"), "nanoseconds")
    76  	require.Equal(t, ReadLogVal(log, "valueTypes"), "cpu")
    77  	require.Equal(t, ReadLogVal(log, "aggTypes"), "sum")
    78  	require.Equal(t, ReadLogVal(log, "dataType"), "CallStack")
    79  	require.Equal(t, ReadLogVal(log, "durationNs"), "10000000000")
    80  	require.Equal(t, ReadLogVal(log, "labels"), "{\"__name__\":\"demo\",\"a\":\"b\",\"cluster\":\"sls-mall\"}")
    81  	require.Equal(t, ReadLogVal(log, "val"), "10000000.00")
    82  }
    83  
    84  func TestDecoder_DecodePprofCumulative(t *testing.T) {
    85  	data, err := os.ReadFile("test/dump_pprof_mem_data")
    86  	require.NoError(t, err)
    87  	var length uint32
    88  	buffer := bytes.NewBuffer(data)
    89  	require.NoError(t, binary.Read(buffer, binary.BigEndian, &length))
    90  	data = data[4 : 4+int(length)]
    91  	var d helper.DumpData
    92  	require.NoError(t, json.Unmarshal(data, &d))
    93  	request, err := http.NewRequest("POST", d.Req.URL, bytes.NewReader(d.Req.Body))
    94  	require.NoError(t, err)
    95  	request.Header = d.Req.Header
    96  	dec := new(Decoder)
    97  	logs, err := dec.Decode(d.Req.Body, request, map[string]string{"cluster": "sls-mall"})
    98  	require.NoError(t, err)
    99  	require.Equal(t, len(logs), 4)
   100  	sort.Slice(logs, func(i, j int) bool {
   101  		if ReadLogVal(logs[i], "name") < ReadLogVal(logs[j], "name") {
   102  			return true
   103  		} else if ReadLogVal(logs[i], "name") == ReadLogVal(logs[j], "name") {
   104  			return ReadLogVal(logs[i], "valueTypes") < ReadLogVal(logs[j], "valueTypes")
   105  		}
   106  		return false
   107  	})
   108  	require.Equal(t, ReadLogVal(logs[0], "name"), "compress/flate.NewWriter /Users/evan/sdk/go1.19.4/src/compress/flate/deflate.go")
   109  	require.Equal(t, ReadLogVal(logs[0], "valueTypes"), "alloc_objects")
   110  	require.Equal(t, ReadLogVal(logs[0], "val"), "1.00")
   111  
   112  	require.Equal(t, ReadLogVal(logs[1], "name"), "compress/flate.NewWriter /Users/evan/sdk/go1.19.4/src/compress/flate/deflate.go")
   113  	require.Equal(t, ReadLogVal(logs[1], "valueTypes"), "alloc_space")
   114  	require.Equal(t, ReadLogVal(logs[1], "val"), "924248.00")
   115  
   116  	require.Equal(t, ReadLogVal(logs[2], "name"), "runtime/pprof.WithLabels /Users/evan/sdk/go1.19.4/src/runtime/pprof/label.go")
   117  	require.Equal(t, ReadLogVal(logs[2], "valueTypes"), "alloc_objects")
   118  	require.Equal(t, ReadLogVal(logs[2], "val"), "1820.00")
   119  
   120  	require.Equal(t, ReadLogVal(logs[3], "name"), "runtime/pprof.WithLabels /Users/evan/sdk/go1.19.4/src/runtime/pprof/label.go")
   121  	require.Equal(t, ReadLogVal(logs[3], "valueTypes"), "alloc_space")
   122  	require.Equal(t, ReadLogVal(logs[3], "val"), "524432.00")
   123  }
   124  
   125  // ReadLogVal returns the log content value for the input key, and returns empty string when not found.
   126  func ReadLogVal(log *protocol.Log, key string) string {
   127  	for _, content := range log.Contents {
   128  		if content.Key == key {
   129  			return content.Value
   130  		}
   131  	}
   132  	return ""
   133  }