github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/packages/pyroscope-flamegraph/src/index.spec.tsx (about)

     1  import React from 'react';
     2  import { render, screen } from '@testing-library/react';
     3  import { FlamegraphRenderer } from './index';
     4  
     5  const RawProfile = {
     6    version: 1,
     7    flamebearer: {
     8      names: [
     9        'total',
    10        'runtime.mcall',
    11        'runtime.park_m',
    12        'runtime.schedule',
    13        'runtime.resetspinning',
    14        'runtime.wakep',
    15        'runtime.startm',
    16        'runtime.notewakeup',
    17        'runtime.futexwakeup',
    18        'runtime.futex',
    19        'runtime.findrunnable',
    20        'runtime.write',
    21        'runtime.write1',
    22        'runtime.stopm',
    23        'runtime.mput',
    24        'runtime.mPark',
    25        'runtime.notesleep',
    26        'runtime.futexsleep',
    27        'runtime.stealWork',
    28        'runtime.checkTimers',
    29        'runtime.runtimer',
    30        'runtime.runOneTimer',
    31        'time.sendTime',
    32        'runtime.selectnbsend',
    33        'runtime.chansend',
    34        'runtime.adjusttimers',
    35        'runtime.netpoll',
    36        'runtime.read',
    37        'runtime.epollwait',
    38        'runtime.siftdownTimer',
    39        'runtime.gosched_m',
    40        'runtime.unlockWithRank',
    41        'runtime.unlock2',
    42        'runtime.lockWithRank',
    43        'runtime.lock2',
    44        'runtime.procyield',
    45        'runtime.goschedImpl',
    46        'runtime.nanotime',
    47        'runtime.globrunqget',
    48        'runtime.(*gQueue).pop',
    49        'runtime.execute',
    50        'runtime.casgstatus',
    51        'runtime.gcBgMarkWorker',
    52        'runtime.systemstack',
    53        'runtime.gcBgMarkWorker.func2',
    54        'runtime.gcDrain',
    55        'runtime.spanOfUnchecked',
    56        'runtime.scanobject',
    57        'runtime.spanOf',
    58        'runtime.pageIndexOf',
    59        'runtime.markBits.isMarked',
    60        'runtime.greyobject',
    61        'runtime.findObject',
    62        'runtime.arenaIndex',
    63        'runtime.(*mspan).divideByElemSize',
    64        'runtime.(*gcWork).putFast',
    65        'runtime.heapBitsForAddr',
    66        'runtime.heapBits.next',
    67        'runtime.heapBits.bits',
    68        'runtime.gcFlushBgCredit',
    69        'runtime.bgsweep',
    70        'runtime.sweepone',
    71        'runtime.(*sweepLocked).sweep',
    72        'runtime.(*gcBitsArena).tryAlloc',
    73        'runtime.(*sweepLocker).dispose',
    74        'runtime.(*sweepLocker).blockCompletion',
    75        'net/http.(*conn).serve',
    76        'net/http.serverHandler.ServeHTTP',
    77        'net/http.HandlerFunc.ServeHTTP',
    78        'github.com/klauspost/compress/gzhttp.NewWrapper.func1.1',
    79        'github.com/gorilla/mux.(*Router).ServeHTTP',
    80        'github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).drainMiddleware.func1',
    81        'github.com/pyroscope-io/pyroscope/pkg/server.ingestHandler.ServeHTTP',
    82        'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.IterateRaw',
    83        'io.LimitReader',
    84        'runtime.newobject',
    85        'runtime.nextFreeFast',
    86        'io.Copy',
    87        'io.copyBuffer',
    88        'bytes.(*Buffer).ReadFrom',
    89        'io.(*LimitedReader).Read',
    90        'net/http.(*response).finishRequest',
    91        'bufio.(*Writer).Flush',
    92        'net/http.checkConnErrorWriter.Write',
    93        'net.(*conn).Write',
    94        'net.(*netFD).Write',
    95        'syscall.Write',
    96        'syscall.write',
    97        'syscall.Syscall',
    98        'github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop',
    99        'github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload',
   100        'github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile',
   101        'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Iterate',
   102        'runtime.growslice',
   103        'runtime.mallocgc',
   104        'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots',
   105        'runtime.selectgo',
   106        'runtime.gopark',
   107        'runtime.(*mcache).nextFree',
   108        'runtime.(*mcache).refill',
   109        'runtime.(*mcentral).cacheSpan',
   110        'runtime.mapiterinit',
   111        'runtime.makemap_small',
   112        'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot',
   113        'runtime/pprof.writeHeap',
   114        'runtime/pprof.writeHeapInternal',
   115        'runtime/pprof.writeHeapProto',
   116        'runtime/pprof.(*profileBuilder).pbSample',
   117        'runtime/pprof.(*profileBuilder).flush',
   118        'compress/flate.(*Writer).Write',
   119        'compress/flate.(*compressor).write',
   120        'compress/flate.(*compressor).encSpeed',
   121        'compress/flate.(*deflateFast).encode',
   122        'compress/flate.emitLiteral',
   123        'runtime/pprof.(*profileBuilder).appendLocsForStack',
   124        'runtime/pprof.allFrames',
   125        'runtime.(*Frames).Next',
   126        'runtime.funcline1',
   127        'runtime.pcvalue',
   128        'runtime.step',
   129        'runtime.GC',
   130        'runtime.(*spanSet).push',
   131        'runtime.(*headTailIndex).incTail',
   132        'runtime.(*mheap).freeSpan',
   133        'runtime.(*mheap).nextSpanForSweep',
   134        'runtime.(*spanSet).pop',
   135        'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).Get',
   136        'github.com/pyroscope-io/pyroscope/pkg/storage/tree.FindFunctionName',
   137        'runtime.asyncPreempt',
   138        'github.com/pyroscope-io/pyroscope/pkg/storage/tree.FindLocation',
   139        'sort.Search',
   140        'github.com/pyroscope-io/pyroscope/pkg/storage/tree.FindFunction',
   141        'github.com/pyroscope-io/pyroscope/pkg/storage/tree.FindFunction.func1',
   142        'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func3',
   143        'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots.func1',
   144        'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Insert',
   145        'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).findNodeAt',
   146        'runtime.(*mcentral).grow',
   147        'runtime.(*mheap).alloc',
   148        'runtime.(*mheap).alloc.func1',
   149        'runtime.(*mheap).allocSpan',
   150        'runtime.(*mheap).allocMSpanLocked',
   151        'runtime.(*fixalloc).alloc',
   152        'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile',
   153        'github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof',
   154        'google.golang.org/protobuf/proto.Unmarshal',
   155        'google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal',
   156        'google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal',
   157        'google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer',
   158        'google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo',
   159        'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).isDueForReset',
   160        'time.Time.Truncate',
   161        'github.com/dgraph-io/badger/v2.(*levelsController).runCompactor',
   162        'github.com/dgraph-io/badger/v2.(*levelsController).pickCompactLevels',
   163        'sort.Slice',
   164        'github.com/dgraph-io/badger/v2.(*DB).doWrites.func1',
   165        'github.com/dgraph-io/badger/v2.(*DB).writeRequests',
   166        'github.com/dgraph-io/badger/v2.(*valueLog).write',
   167        'github.com/dgraph-io/badger/v2.(*logFile).encodeEntry',
   168        'hash/crc32.New',
   169        'runtime.heapBitsSetType',
   170        'runtime.newstack',
   171        'runtime.copystack',
   172        'runtime.memmove',
   173      ],
   174      levels: [
   175        [0, 236, 0, 0],
   176        [
   177          0, 1, 0, 155, 0, 1, 0, 152, 0, 29, 0, 95, 0, 1, 0, 89, 0, 3, 0, 66, 0,
   178          11, 0, 60, 0, 154, 0, 42, 0, 36, 0, 1,
   179        ],
   180        [
   181          0, 1, 0, 156, 0, 1, 0, 153, 0, 1, 0, 150, 0, 23, 0, 103, 0, 1, 0, 102,
   182          0, 1, 1, 101, 0, 1, 0, 75, 0, 2, 1, 96, 0, 1, 0, 90, 0, 1, 0, 81, 0, 2,
   183          0, 67, 0, 2, 2, 65, 0, 3, 3, 64, 0, 6, 3, 61, 0, 154, 0, 43, 0, 19, 0,
   184          30, 0, 17, 0, 2,
   185        ],
   186        [
   187          0, 1, 0, 157, 0, 1, 1, 154, 0, 1, 1, 151, 0, 1, 0, 143, 0, 12, 0, 126,
   188          0, 7, 0, 120, 0, 3, 0, 104, 0, 1, 0, 75, 1, 1, 0, 94, 1, 1, 1, 97, 0, 1,
   189          0, 91, 0, 1, 0, 82, 0, 2, 0, 68, 8, 3, 2, 62, 0, 154, 0, 44, 0, 15, 0,
   190          36, 0, 2, 0, 33, 0, 2, 0, 31, 0, 17, 0, 3,
   191        ],
   192        [
   193          0, 1, 0, 158, 2, 1, 0, 144, 0, 7, 0, 133, 0, 5, 0, 127, 0, 7, 1, 61, 0,
   194          3, 0, 105, 0, 1, 1, 94, 1, 1, 0, 98, 2, 1, 0, 92, 0, 1, 0, 83, 0, 2, 0,
   195          69, 10, 1, 1, 63, 0, 154, 14, 45, 0, 1, 1, 41, 0, 14, 0, 3, 0, 2, 0, 34,
   196          0, 2, 2, 32, 0, 16, 1, 10, 0, 1, 0, 4,
   197        ],
   198        [
   199          0, 1, 0, 159, 2, 1, 0, 145, 0, 7, 0, 134, 0, 3, 0, 131, 0, 1, 0, 129, 0,
   200          1, 1, 128, 1, 1, 0, 124, 0, 5, 0, 62, 0, 3, 0, 106, 2, 1, 0, 99, 2, 1,
   201          0, 93, 0, 1, 0, 84, 0, 2, 0, 70, 25, 1, 1, 59, 0, 7, 7, 58, 0, 5, 5, 57,
   202          0, 6, 6, 56, 0, 119, 61, 47, 0, 2, 2, 46, 1, 2, 1, 40, 0, 4, 0, 10, 0,
   203          3, 0, 33, 0, 2, 2, 37, 0, 3, 0, 31, 0, 2, 2, 35, 3, 1, 0, 19, 0, 5, 0,
   204          26, 0, 2, 0, 18, 0, 6, 0, 13, 0, 1, 0, 11, 0, 1, 0, 5,
   205        ],
   206        [
   207          0, 1, 0, 75, 2, 1, 0, 146, 0, 7, 0, 135, 0, 3, 2, 130, 0, 1, 1, 130, 2,
   208          1, 1, 125, 0, 1, 0, 123, 0, 4, 3, 121, 0, 1, 0, 114, 0, 2, 0, 107, 2, 1,
   209          1, 100, 2, 1, 1, 94, 0, 1, 0, 85, 0, 2, 0, 68, 105, 2, 2, 55, 0, 3, 3,
   210          54, 0, 1, 1, 53, 0, 17, 17, 52, 0, 3, 3, 51, 0, 5, 5, 50, 0, 11, 11, 49,
   211          0, 16, 16, 48, 4, 1, 1, 41, 0, 1, 1, 39, 0, 1, 1, 38, 0, 1, 1, 37, 0, 1,
   212          0, 26, 0, 3, 0, 34, 2, 3, 3, 32, 5, 1, 0, 20, 0, 4, 4, 28, 0, 1, 1, 27,
   213          0, 2, 0, 19, 0, 5, 0, 15, 0, 1, 1, 14, 0, 1, 1, 12, 0, 1, 0, 6,
   214        ],
   215        [
   216          0, 1, 0, 94, 2, 1, 0, 147, 0, 7, 6, 136, 2, 1, 1, 132, 4, 1, 0, 43, 3,
   217          1, 1, 122, 0, 1, 0, 115, 0, 2, 0, 108, 6, 1, 0, 86, 0, 2, 0, 71, 171, 1,
   218          1, 28, 0, 3, 3, 35, 10, 1, 0, 21, 5, 1, 1, 25, 0, 1, 0, 20, 0, 5, 0, 16,
   219          2, 1, 0, 7,
   220        ],
   221        [
   222          0, 1, 0, 160, 2, 1, 0, 148, 6, 1, 0, 94, 7, 1, 0, 33, 4, 1, 0, 116, 0,
   223          2, 0, 109, 6, 1, 0, 87, 0, 2, 0, 72, 185, 1, 1, 29, 6, 1, 0, 21, 0, 5,
   224          0, 17, 2, 1, 0, 8,
   225        ],
   226        [
   227          0, 1, 0, 161, 2, 1, 0, 149, 6, 1, 0, 98, 7, 1, 1, 34, 4, 1, 0, 117, 0,
   228          2, 0, 110, 6, 1, 1, 88, 0, 2, 0, 73, 192, 1, 0, 22, 0, 5, 5, 9, 2, 1, 1,
   229          9,
   230        ],
   231        [
   232          0, 1, 0, 162, 2, 1, 1, 148, 6, 1, 0, 99, 12, 1, 0, 118, 0, 2, 0, 111, 7,
   233          1, 0, 77, 0, 1, 0, 74, 192, 1, 0, 23,
   234        ],
   235        [
   236          0, 1, 1, 163, 9, 1, 0, 100, 12, 1, 1, 119, 0, 2, 1, 112, 7, 1, 0, 78, 0,
   237          1, 0, 75, 192, 1, 1, 24,
   238        ],
   239        [10, 1, 0, 137, 14, 1, 1, 113, 7, 1, 0, 79, 0, 1, 1, 76],
   240        [10, 1, 0, 138, 22, 1, 1, 80],
   241        [10, 1, 0, 43],
   242        [10, 1, 0, 139],
   243        [10, 1, 0, 140],
   244        [10, 1, 0, 141],
   245        [10, 1, 1, 142],
   246      ],
   247      numTicks: 236,
   248      maxSelf: 61,
   249    },
   250    timeline: {
   251      startTime: 1646760440,
   252      samples: [237],
   253      durationDelta: 10,
   254      watermarks: {},
   255    },
   256    metadata: {
   257      format: 'single' as const,
   258      spyName: 'gospy' as const,
   259      sampleRate: 100,
   260      units: 'samples' as const,
   261      name: 'pyroscope.server.cpu 2022-03-08T17:27:23Z',
   262      appName: 'pyroscope.server.cpu',
   263      startTime: 1646760443,
   264      endTime: 1646760446,
   265      query: 'pyroscope.server.cpu{}',
   266      maxNodes: 1024,
   267    },
   268  };
   269  
   270  const SimpleTree = {
   271    topLevel: 0,
   272    rangeMin: 0,
   273    format: 'single' as const,
   274    numTicks: 988,
   275    sampleRate: 100,
   276    names: [
   277      'total',
   278      'runtime.main',
   279      'main.slowFunction',
   280      'main.work',
   281      'main.main',
   282      'main.fastFunction',
   283    ],
   284    levels: [
   285      [0, 988, 0, 0],
   286      [0, 988, 0, 1],
   287      [0, 214, 0, 5, 214, 3, 2, 4, 217, 771, 0, 2],
   288      [0, 214, 214, 3, 216, 1, 1, 5, 217, 771, 771, 3],
   289    ],
   290  
   291    rangeMax: 1,
   292    units: 'samples',
   293    fitMode: 'HEAD',
   294  
   295    spyName: 'gospy',
   296  };
   297  
   298  // describe.skip('Pyroscope Library', () => {
   299  //  it('should not be possible to override the pyroscope logo using props', () => {
   300  //    render(
   301  //      <FlamegraphRenderer
   302  //        flamebearer={SimpleTree}
   303  //        display="flamegraph"
   304  //        viewType="single"
   305  //        showPyroscopeLogo={false}
   306  //      />
   307  //    );
   308  //
   309  //    expect(
   310  //      screen.getByRole('link', { name: /pyroscope/i })
   311  //    ).toBeInTheDocument();
   312  //  });
   313  // });
   314  //
   315  //
   316  // TODO a test saying going over rendering an empty flamegraph
   317  describe.only('positions', () => {
   318    beforeAll(() => {
   319      window.HTMLElement.prototype.getBoundingClientRect = function () {
   320        return {
   321          x: 0,
   322          y: 0,
   323          bottom: 0,
   324          right: 0,
   325          toJSON: () => {},
   326          height: 0,
   327          top: 0,
   328          left: 0,
   329          width: 900,
   330        };
   331      };
   332    });
   333  
   334    describe('Allow changing visualization mode', () => {
   335      it('should allow changing view when "onlyDisplay" is not set', () => {
   336        const { getByTestId, queryByRole } = render(
   337          <FlamegraphRenderer profile={RawProfile} />
   338        );
   339  
   340        expect(getByTestId('table-ui')).toBeInTheDocument();
   341        expect(getByTestId('flamegraph-view')).toBeInTheDocument();
   342        expect(getByTestId('flamegraph')).toBeInTheDocument();
   343        expect(getByTestId('both')).toBeInTheDocument();
   344        expect(getByTestId('table')).toBeInTheDocument();
   345      });
   346  
   347      it('should restrict changing view when "onlyDisplay" is set', () => {
   348        const { getByTestId, queryByRole } = render(
   349          <FlamegraphRenderer profile={RawProfile} onlyDisplay="both" />
   350        );
   351  
   352        expect(getByTestId('table-ui')).toBeInTheDocument();
   353        expect(getByTestId('flamegraph-view')).toBeInTheDocument();
   354        expect(queryByRole('combobox', { name: 'view' })).not.toBeInTheDocument();
   355      });
   356    });
   357  
   358    it('should display only the flamegraph when specified', () => {
   359      const { getByTestId, queryByTestId } = render(
   360        <FlamegraphRenderer profile={RawProfile} onlyDisplay="flamegraph" />
   361      );
   362  
   363      expect(queryByTestId('table-ui')).not.toBeInTheDocument();
   364      expect(getByTestId('flamegraph-view')).toBeInTheDocument();
   365    });
   366  
   367    it('should display only the table when specified', () => {
   368      const { getByTestId, queryByTestId } = render(
   369        <FlamegraphRenderer profile={RawProfile} onlyDisplay="table" />
   370      );
   371  
   372      expect(getByTestId('table-ui')).toBeInTheDocument();
   373      expect(queryByTestId('flamegraph-view')).not.toBeInTheDocument();
   374    });
   375  });
   376  
   377  it('should work', () => {
   378    render(<FlamegraphRenderer flamebearer={SimpleTree as any} />);
   379  });
   380  
   381  it('should work with raw profile from /render endpoint', () => {
   382    render(<FlamegraphRenderer profile={RawProfile} />);
   383  });