github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/packages/pyroscope-flamegraph/src/FlameGraph/FlameGraphComponent/color.spec.ts (about)

     1  import Color from 'color';
     2  import {
     3    colorBasedOnDiffPercent,
     4    NewDiffColor,
     5    getPackageNameFromStackTrace,
     6  } from './color';
     7  import { DefaultPalette } from './colorPalette';
     8  
     9  describe.each([
    10    // red (diff > 0)
    11    [30, 60, DefaultPalette.badColor.toString()],
    12  
    13    // green (diff < 0%)
    14    [60, 0, DefaultPalette.goodColor.toString()],
    15  
    16    // grey (diff == 0)
    17    [0, 0, DefaultPalette.neutralColor.toString()],
    18  ])('.colorBasedOnDiffPercent(%i, %i)', (a, b, expected) => {
    19    it(`returns ${expected}`, () => {
    20      expect(colorBasedOnDiffPercent(DefaultPalette, a, b).rgb().toString()).toBe(
    21        expected
    22      );
    23    });
    24  });
    25  
    26  describe('NewDiffColor with white-to-black example palette', () => {
    27    describe.each([
    28      [-100, 'rgb(255, 255, 255)'],
    29      [0, 'rgb(128, 128, 128)'],
    30      [100, 'rgb(0, 0, 0)'],
    31    ])('.NewDiffColor(%i)', (a, expected) => {
    32      it(`returns ${expected}`, () => {
    33        const color = NewDiffColor({
    34          name: 'my palette',
    35          goodColor: Color('white'),
    36          neutralColor: Color('grey'),
    37          badColor: Color('black'),
    38        });
    39  
    40        expect(color(a).rgb().toString()).toBe(expected);
    41      });
    42    });
    43  });
    44  
    45  describe('getPackageNameFromStackTrace', () => {
    46    describe('golang', () => {
    47      describe.each([
    48        ['bufio.(*Reader).fill', 'bufio.'],
    49        ['cmpbody', 'cmpbody'],
    50        ['bytes.Compare', 'bytes.'],
    51        ['crypto/tls.(*Conn).clientHandshake', 'crypto/tls.'],
    52        [
    53          'github.com/DataDog/zstd._Cfunc_ZSTD_compress_wrapper',
    54          'github.com/DataDog/zstd.',
    55        ],
    56        [
    57          'github.com/dgraph-io/badger/v2.(*DB).calculateSize',
    58          'github.com/dgraph-io/badger/v2.',
    59        ],
    60        [
    61          'github.com/dgraph-io/badger/v2/table.(*blockIterator).next',
    62          'github.com/dgraph-io/badger/v2/table.',
    63        ],
    64        ['path/filepath.walk', 'path/filepath.'],
    65        ['os.(*File).write', 'os.'],
    66      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
    67        it(`returns '${expected}'`, () => {
    68          expect(getPackageNameFromStackTrace('gospy', a)).toBe(expected);
    69        });
    70      });
    71    });
    72  
    73    describe('pyspy', () => {
    74      describe.each([
    75        ['total', 'total'],
    76        [
    77          'System.Private.CoreLib!System.Threading.TimerQueue.FireNextTimers()',
    78          'System.Private.CoreLib!System.Threading',
    79        ],
    80        [
    81          'StackExchange.Redis!StackExchange.Redis.ConnectionMultiplexer.OnHeartbeat()',
    82          'StackExchange.Redis!StackExchange.Redis',
    83        ],
    84        [
    85          'Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestPipeReader.ReadAsync(value class System.Threading.CancellationToken)',
    86          'Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http',
    87        ],
    88        [
    89          'Google.Protobuf!Google.Protobuf.ParsingPrimitivesMessages.ReadRawMessage(value class Google.Protobuf.ParseContext\u0026,class Google.Protobuf.IMessage)',
    90          'Google.Protobuf!Google.Protobuf',
    91        ],
    92        [
    93          'Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.PipeExtensions.ReadSingleMessageAsync(class System.IO.Pipelines.PipeReader,class Grpc.AspNetCore.Server.Internal.HttpContextServerCallContext,class System.Func`2\u003cclass Grpc.Core.DeserializationContext,!!0\u003e)',
    94          'Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal',
    95        ],
    96        [
    97          'System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[System.__Canon].GetStateMachineBox(!!0\u0026,class System.Threading.Tasks.Task`1\u003c!0\u003e\u0026)',
    98          'System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[System',
    99        ],
   100      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   101        it(`returns '${expected}'`, () => {
   102          expect(getPackageNameFromStackTrace('dotnetspy', a)).toBe(expected);
   103        });
   104      });
   105    });
   106  
   107    describe('pyspy', () => {
   108      describe.each([
   109        ['total', 'total'],
   110        ['urllib3/response.py:579 - stream', 'urllib3/'],
   111        ['requests/models.py:580 - prepare_cookies', 'requests/'],
   112        ['logging/__init__.py:1548 - findCaller', 'logging/'],
   113        [
   114          'jaeger_client/thrift_gen/jaeger/ttypes.py:147 - write',
   115          'jaeger_client/thrift_gen/jaeger/',
   116        ],
   117  
   118        // TODO: this one looks incorrect, but keeping in the test for now
   119        [
   120          '\u003cfrozen importlib._bootstrap\u003e:1030 - _gcd_import',
   121          '<frozen importlib._bootstrap>:1030 - _gcd_import',
   122        ],
   123      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   124        it(`returns '${expected}'`, () => {
   125          expect(getPackageNameFromStackTrace('pyspy', a)).toBe(expected);
   126        });
   127      });
   128    });
   129  
   130    describe('rbspy', () => {
   131      describe.each([
   132        ['total', 'total'],
   133        ['webrick/utils.rb:194 - watch', 'webrick/'],
   134        ['webrick/server.rb:190 - block (2 levels) in start', 'webrick/'],
   135        [
   136          'gems/sinatra-2.0.3/lib/sinatra/base.rb:1537 - start_server',
   137          'gems/sinatra-2.0.3/lib/sinatra/',
   138        ],
   139        ['services/driver/client.rb:34 - get_drivers', 'services/driver/'],
   140        ['uri/common.rb:742 - URI', 'uri/'],
   141        ['net/protocol.rb:299 - block in write0', 'net/'],
   142      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   143        it(`returns '${expected}'`, () => {
   144          expect(getPackageNameFromStackTrace('rbspy', a)).toBe(expected);
   145        });
   146      });
   147    });
   148  
   149    describe('ebpfspy', () => {
   150      describe.each([
   151        ['total', 'total'],
   152        ['entry_SYSCALL_64_after_hwframe', 'entry_SYSCALL_64_after_hwframe'],
   153        ['[unknown]', '[unknown]'],
   154        [
   155          'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
   156          'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
   157        ],
   158        [
   159          'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
   160          'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
   161        ],
   162        [
   163          'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
   164          'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
   165        ],
   166      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   167        it(`returns '${expected}'`, () => {
   168          expect(getPackageNameFromStackTrace('ebpfspy', a)).toBe(expected);
   169        });
   170      });
   171    });
   172  
   173    describe('default', () => {
   174      describe.each([
   175        ['total', 'total'],
   176        ['entry_SYSCALL_64_after_hwframe', 'entry_SYSCALL_64_after_hwframe'],
   177        ['[unknown]', '[unknown]'],
   178        [
   179          'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
   180          'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
   181        ],
   182        [
   183          'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
   184          'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
   185        ],
   186        [
   187          'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
   188          'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
   189        ],
   190      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   191        it(`returns '${expected}'`, () => {
   192          expect(getPackageNameFromStackTrace('unknown', a)).toBe(expected);
   193        });
   194      });
   195    });
   196  
   197    describe('rust', () => {
   198      describe.each([
   199        ['total', 'total'],
   200        ['std::thread::local::LocalKey<T>::with', 'std'],
   201        [
   202          'tokio::runtime::basic_scheduler::CoreGuard::block_on::{{closure}}::{{closure}}::{{closure}}',
   203          'tokio',
   204        ],
   205        [
   206          '<core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll',
   207          '<core',
   208        ],
   209        [
   210          'reqwest::blocking::client::ClientHandle::new::{{closure}}::{{closure}}',
   211          'reqwest',
   212        ],
   213        ['core::time::Duration::as_secs', 'core'],
   214        ['clock_gettime@GLIBC_2.2.5', 'clock_gettime@GLIBC_2.2.5'],
   215        [
   216          'hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T>::poll_catch debugger eval code',
   217          'hyper',
   218        ],
   219        ['openssl::ssl::connector::SslConnector::builder', 'openssl'],
   220  
   221        // TODO looks incorrect
   222        [
   223          '<F as futures_core::future::TryFuture>::try_poll',
   224          '<F as futures_core',
   225        ],
   226      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   227        it(`returns '${expected}'`, () => {
   228          expect(getPackageNameFromStackTrace('pyroscope-rs', a)).toBe(expected);
   229        });
   230      });
   231    });
   232  
   233    describe('scrape (pull mode)', () => {
   234      describe.each([
   235        ['bufio.(*Reader).fill', 'bufio.'],
   236        ['cmpbody', 'cmpbody'],
   237        ['bytes.Compare', 'bytes.'],
   238        ['crypto/tls.(*Conn).clientHandshake', 'crypto/tls.'],
   239        [
   240          'github.com/DataDog/zstd._Cfunc_ZSTD_compress_wrapper',
   241          'github.com/DataDog/zstd.',
   242        ],
   243        [
   244          'github.com/dgraph-io/badger/v2.(*DB).calculateSize',
   245          'github.com/dgraph-io/badger/v2.',
   246        ],
   247        [
   248          'github.com/dgraph-io/badger/v2/table.(*blockIterator).next',
   249          'github.com/dgraph-io/badger/v2/table.',
   250        ],
   251        ['path/filepath.walk', 'path/filepath.'],
   252        ['os.(*File).write', 'os.'],
   253      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   254        it(`returns '${expected}'`, () => {
   255          expect(getPackageNameFromStackTrace('scrape', a)).toBe(expected);
   256        });
   257      });
   258    });
   259  
   260    describe('nodejs spy', () => {
   261      describe.each([
   262        ['total', 'total'],
   263        ['./node_modules/node-fetch/lib/index.js:fetch:1493', 'node-fetch'],
   264        [
   265          './node_modules/@pyroscope-node/dist/pull/index.js:sampleFunction:1827',
   266          '@pyroscope-node',
   267        ],
   268        ['node:net:Socket:320', 'node:net'],
   269        [':(idle):0', ''],
   270      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   271        it(`returns '${expected}'`, () => {
   272          expect(getPackageNameFromStackTrace('nodespy', a)).toBe(expected);
   273        });
   274      });
   275    });
   276  
   277    describe('java spy', () => {
   278      describe.each([
   279        [
   280          'org/apache/catalina/core/ApplicationFilterChain.doFilter',
   281          'org/apache/catalina/core/',
   282        ],
   283        [
   284          'org/apache/catalina/core/ApplicationFilterChain.internalDoFilter',
   285          'org/apache/catalina/core/',
   286        ],
   287        [
   288          'org/apache/coyote/AbstractProcessorLight.process',
   289          'org/apache/coyote/',
   290        ],
   291        [
   292          'org/springframework/web/servlet/DispatcherServlet.doService',
   293          'org/springframework/web/servlet/',
   294        ],
   295        [
   296          'org/example/rideshare/RideShareController.orderCar',
   297          'org/example/rideshare/',
   298        ],
   299        ['org/example/rideshare/OrderService.orderCar', 'org/example/rideshare/'],
   300        ['total', 'total'],
   301      ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
   302        it(`returns '${expected}'`, () => {
   303          expect(getPackageNameFromStackTrace('javaspy', a)).toBe(expected);
   304        });
   305      });
   306    });
   307  });