Path: blob/main/pkg/integrations/v2/app_agent_receiver/sourcemaps_test.go
5340 views
package app_agent_receiver12import (3"bytes"4"errors"5"io"6"io/fs"7"net/http"8"path/filepath"9"testing"1011"github.com/go-kit/log"12"github.com/prometheus/client_golang/prometheus"13"github.com/stretchr/testify/require"14)1516type mockHTTPClient struct {17responses []struct {18*http.Response19error20}21requests []string22}2324func (cl *mockHTTPClient) Get(url string) (resp *http.Response, err error) {25if len(cl.responses) > len(cl.requests) {26r := cl.responses[len(cl.requests)]27cl.requests = append(cl.requests, url)28return r.Response, r.error29}30return nil, errors.New("mockHTTPClient got more requests than expected")31}3233type mockFileService struct {34files map[string][]byte35stats []string36reads []string37}3839func (s *mockFileService) Stat(name string) (fs.FileInfo, error) {40s.stats = append(s.stats, name)41_, ok := s.files[name]42if !ok {43return nil, errors.New("file not found")44}45return nil, nil46}4748func (s *mockFileService) ReadFile(name string) ([]byte, error) {49s.reads = append(s.reads, name)50content, ok := s.files[name]51if ok {52return content, nil53}54return nil, errors.New("file not found")55}5657func newResponseFromTestData(t *testing.T, file string) *http.Response {58return &http.Response{59Body: io.NopCloser(bytes.NewReader(loadTestData(t, file))),60StatusCode: 200,61}62}6364func mockException() *Exception {65return &Exception{66Stacktrace: &Stacktrace{67Frames: []Frame{68{69Colno: 6,70Filename: "http://localhost:1234/foo.js",71Function: "eval",72Lineno: 5,73},74{75Colno: 5,76Filename: "http://localhost:1234/foo.js",77Function: "callUndefined",78Lineno: 6,79},80},81},82}83}8485func Test_RealSourceMapStore_DownloadSuccess(t *testing.T) {86conf := SourceMapConfig{87Download: true,88DownloadFromOrigins: []string{"*"},89}9091httpClient := &mockHTTPClient{92responses: []struct {93*http.Response94error95}{96{newResponseFromTestData(t, "foo.js"), nil},97{newResponseFromTestData(t, "foo.js.map"), nil},98},99}100101logger := log.NewNopLogger()102103sourceMapStore := NewSourceMapStore(logger, conf, prometheus.NewRegistry(), httpClient, &mockFileService{})104105exception := mockException()106107transformed := TransformException(sourceMapStore, logger, exception, "123")108109require.Equal(t, []string{"http://localhost:1234/foo.js", "http://localhost:1234/foo.js.map"}, httpClient.requests)110111expected := &Exception{112Stacktrace: &Stacktrace{113Frames: []Frame{114{115Colno: 37,116Filename: "/__parcel_source_root/demo/src/actions.ts",117Function: "?",118Lineno: 6,119},120{121Colno: 2,122Filename: "/__parcel_source_root/demo/src/actions.ts",123Function: "?",124Lineno: 7,125},126},127},128}129130require.Equal(t, *expected, *transformed)131}132133func Test_RealSourceMapStore_DownloadError(t *testing.T) {134conf := SourceMapConfig{135Download: true,136DownloadFromOrigins: []string{"*"},137}138139resp := &http.Response{140StatusCode: 500,141Body: io.NopCloser(bytes.NewReader([]byte{})),142}143144httpClient := &mockHTTPClient{145responses: []struct {146*http.Response147error148}{149{resp, nil},150},151}152153logger := log.NewNopLogger()154155sourceMapStore := NewSourceMapStore(logger, conf, prometheus.NewRegistry(), httpClient, &mockFileService{})156157exception := mockException()158159transformed := TransformException(sourceMapStore, logger, exception, "123")160161require.Equal(t, []string{"http://localhost:1234/foo.js"}, httpClient.requests)162require.Equal(t, exception, transformed)163}164165func Test_RealSourceMapStore_DownloadHTTPOriginFiltering(t *testing.T) {166conf := SourceMapConfig{167Download: true,168DownloadFromOrigins: []string{"http://bar.com/"},169}170171httpClient := &mockHTTPClient{172responses: []struct {173*http.Response174error175}{176{newResponseFromTestData(t, "foo.js"), nil},177{newResponseFromTestData(t, "foo.js.map"), nil},178},179}180181logger := log.NewNopLogger()182183sourceMapStore := NewSourceMapStore(logger, conf, prometheus.NewRegistry(), httpClient, &mockFileService{})184185exception := &Exception{186Stacktrace: &Stacktrace{187Frames: []Frame{188{189Colno: 6,190Filename: "http://foo.com/foo.js",191Function: "eval",192Lineno: 5,193},194{195Colno: 5,196Filename: "http://bar.com/foo.js",197Function: "callUndefined",198Lineno: 6,199},200},201},202}203204transformed := TransformException(sourceMapStore, logger, exception, "123")205206require.Equal(t, []string{"http://bar.com/foo.js", "http://bar.com/foo.js.map"}, httpClient.requests)207208expected := &Exception{209Stacktrace: &Stacktrace{210Frames: []Frame{211{212Colno: 6,213Filename: "http://foo.com/foo.js",214Function: "eval",215Lineno: 5,216},217{218Colno: 2,219Filename: "/__parcel_source_root/demo/src/actions.ts",220Function: "?",221Lineno: 7,222},223},224},225}226227require.Equal(t, *expected, *transformed)228}229230func Test_RealSourceMapStore_ReadFromFileSystem(t *testing.T) {231conf := SourceMapConfig{232Download: false,233FileSystem: []SourceMapFileLocation{234{235MinifiedPathPrefix: "http://foo.com/",236Path: filepath.FromSlash("/var/build/latest/"),237},238{239MinifiedPathPrefix: "http://bar.com/",240Path: filepath.FromSlash("/var/build/{{ .Release }}/"),241},242},243}244245mapFile := loadTestData(t, "foo.js.map")246247fileService := &mockFileService{248files: map[string][]byte{249filepath.FromSlash("/var/build/latest/foo.js.map"): mapFile,250filepath.FromSlash("/var/build/123/foo.js.map"): mapFile,251},252}253254logger := log.NewNopLogger()255256sourceMapStore := NewSourceMapStore(logger, conf, prometheus.NewRegistry(), &mockHTTPClient{}, fileService)257258exception := &Exception{259Stacktrace: &Stacktrace{260Frames: []Frame{261{262Colno: 6,263Filename: "http://foo.com/foo.js",264Function: "eval",265Lineno: 5,266},267{268Colno: 6,269Filename: "http://foo.com/bar.js",270Function: "eval",271Lineno: 5,272},273{274Colno: 5,275Filename: "http://bar.com/foo.js",276Function: "callUndefined",277Lineno: 6,278},279{280Colno: 5,281Filename: "http://baz.com/foo.js",282Function: "callUndefined",283Lineno: 6,284},285},286},287}288289transformed := TransformException(sourceMapStore, logger, exception, "123")290291require.Equal(t, []string{292filepath.FromSlash("/var/build/latest/foo.js.map"),293filepath.FromSlash("/var/build/latest/bar.js.map"),294filepath.FromSlash("/var/build/123/foo.js.map"),295}, fileService.stats)296require.Equal(t, []string{297filepath.FromSlash("/var/build/latest/foo.js.map"),298filepath.FromSlash("/var/build/123/foo.js.map"),299}, fileService.reads)300301expected := &Exception{302Stacktrace: &Stacktrace{303Frames: []Frame{304{305Colno: 37,306Filename: "/__parcel_source_root/demo/src/actions.ts",307Function: "?",308Lineno: 6,309},310{311Colno: 6,312Filename: "http://foo.com/bar.js",313Function: "eval",314Lineno: 5,315},316{317Colno: 2,318Filename: "/__parcel_source_root/demo/src/actions.ts",319Function: "?",320Lineno: 7,321},322{323Colno: 5,324Filename: "http://baz.com/foo.js",325Function: "callUndefined",326Lineno: 6,327},328},329},330}331332require.Equal(t, *expected, *transformed)333}334335func Test_RealSourceMapStore_ReadFromFileSystemAndDownload(t *testing.T) {336conf := SourceMapConfig{337Download: true,338DownloadFromOrigins: []string{"*"},339FileSystem: []SourceMapFileLocation{340{341MinifiedPathPrefix: "http://foo.com/",342Path: filepath.FromSlash("/var/build/latest/"),343},344},345}346347mapFile := loadTestData(t, "foo.js.map")348349fileService := &mockFileService{350files: map[string][]byte{351filepath.FromSlash("/var/build/latest/foo.js.map"): mapFile,352},353}354355httpClient := &mockHTTPClient{356responses: []struct {357*http.Response358error359}{360{newResponseFromTestData(t, "foo.js"), nil},361{newResponseFromTestData(t, "foo.js.map"), nil},362},363}364365logger := log.NewNopLogger()366367sourceMapStore := NewSourceMapStore(logger, conf, prometheus.NewRegistry(), httpClient, fileService)368369exception := &Exception{370Stacktrace: &Stacktrace{371Frames: []Frame{372{373Colno: 6,374Filename: "http://foo.com/foo.js",375Function: "eval",376Lineno: 5,377},378{379Colno: 5,380Filename: "http://bar.com/foo.js",381Function: "callUndefined",382Lineno: 6,383},384},385},386}387388transformed := TransformException(sourceMapStore, logger, exception, "123")389390require.Equal(t, []string{filepath.FromSlash("/var/build/latest/foo.js.map")}, fileService.stats)391require.Equal(t, []string{filepath.FromSlash("/var/build/latest/foo.js.map")}, fileService.reads)392require.Equal(t, []string{"http://bar.com/foo.js", "http://bar.com/foo.js.map"}, httpClient.requests)393394expected := &Exception{395Stacktrace: &Stacktrace{396Frames: []Frame{397{398Colno: 37,399Filename: "/__parcel_source_root/demo/src/actions.ts",400Function: "?",401Lineno: 6,402},403{404Colno: 2,405Filename: "/__parcel_source_root/demo/src/actions.ts",406Function: "?",407Lineno: 7,408},409},410},411}412413require.Equal(t, *expected, *transformed)414}415416func Test_RealSourceMapStore_FilepathSanitized(t *testing.T) {417conf := SourceMapConfig{418Download: false,419FileSystem: []SourceMapFileLocation{420{421MinifiedPathPrefix: "http://foo.com/",422Path: filepath.FromSlash("/var/build/latest/"),423},424},425}426427fileService := &mockFileService{}428429logger := log.NewNopLogger()430431sourceMapStore := NewSourceMapStore(logger, conf, prometheus.NewRegistry(), &mockHTTPClient{}, fileService)432433exception := &Exception{434Stacktrace: &Stacktrace{435Frames: []Frame{436{437Colno: 6,438Filename: "http://foo.com/../../../etc/passwd",439Function: "eval",440Lineno: 5,441},442},443},444}445446transformed := TransformException(sourceMapStore, logger, exception, "123")447448require.Equal(t, []string{449filepath.FromSlash("/var/build/latest/etc/passwd.map"),450}, fileService.stats)451require.Len(t, fileService.reads, 0)452453require.Equal(t, *exception, *transformed)454}455456func Test_RealSourceMapStore_FilepathQueryParamsOmitted(t *testing.T) {457conf := SourceMapConfig{458Download: false,459FileSystem: []SourceMapFileLocation{460{461MinifiedPathPrefix: "http://foo.com/",462Path: filepath.FromSlash("/var/build/latest/"),463},464},465}466467fileService := &mockFileService{}468469logger := log.NewNopLogger()470471sourceMapStore := NewSourceMapStore(logger, conf, prometheus.NewRegistry(), &mockHTTPClient{}, fileService)472473exception := &Exception{474Stacktrace: &Stacktrace{475Frames: []Frame{476{477Colno: 6,478Filename: "http://foo.com/static/foo.js?v=1233",479Function: "eval",480Lineno: 5,481},482},483},484}485486transformed := TransformException(sourceMapStore, logger, exception, "123")487488require.Equal(t, []string{489filepath.FromSlash("/var/build/latest/static/foo.js.map"),490}, fileService.stats)491require.Len(t, fileService.reads, 0)492493require.Equal(t, *exception, *transformed)494}495496497