Skip to content

Commit

Permalink
test(profiling-node): Switch to vitest
Browse files Browse the repository at this point in the history
  • Loading branch information
AbhiPrasad committed Jul 24, 2024
1 parent 04a26a4 commit 0a462ba
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 119 deletions.
2 changes: 1 addition & 1 deletion packages/browser/test/unit/profiling/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('BrowserProfilingIntegration', () => {
tracesSampleRate: 1,
profilesSampleRate: 1,
environment: 'test-environment',
dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
transport: _opts => {
return {
flush,
Expand Down
2 changes: 1 addition & 1 deletion packages/profiling-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import * as Sentry from '@sentry/node';
import { nodeProfilingIntegration } from '@sentry/profiling-node';

Sentry.init({
dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
debug: true,
tracesSampleRate: 1,
profilesSampleRate: 1, // Set profiling sampling rate.
Expand Down
6 changes: 0 additions & 6 deletions packages/profiling-node/jest.config.js

This file was deleted.

4 changes: 2 additions & 2 deletions packages/profiling-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@
"build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch",
"build:watch": "run-p build:transpile:watch build:types:watch",
"build:tarball": "npm pack",
"test:watch": "cross-env SENTRY_PROFILER_BINARY_DIR=build jest --watch",
"test:watch": "cross-env SENTRY_PROFILER_BINARY_DIR=build vitest --watch",
"test:bundle": "node test-binaries.esbuild.js",
"test": "cross-env SENTRY_PROFILER_BINARY_DIR=lib jest --config jest.config.js"
"test": "cross-env SENTRY_PROFILER_BINARY_DIR=lib vitest run"
},
"dependencies": {
"@sentry/core": "8.19.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/profiling-node/src/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ export const _nodeProfilingIntegration = ((): ProfilingIntegration => {
const options = client.getOptions();

const mode =
(options.profilesSampleRate === undefined || options.profilesSampleRate === 0) && !options.profilesSampler
(options.profilesSampleRate == undefined || options.profilesSampleRate === 0) && !options.profilesSampler
? 'continuous'
: 'span';
switch (mode) {
Expand Down
9 changes: 7 additions & 2 deletions packages/profiling-node/test/bindings.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { platform } from 'os';
import { describe, expect, it } from 'vitest';

import { platform } from 'node:os';
// Contains unit tests for some of the C++ bindings. These functions
// are exported on the private bindings object, so we can test them and
// they should not be used outside of this file.
Expand All @@ -22,7 +24,10 @@ const cases = [
describe('GetFrameModule', () => {
it.each(
platform() === 'win32'
? cases.map(([abs_path, expected]) => [abs_path ? `C:${abs_path.replace(/\//g, '\\')}` : '', expected])
? (cases.map(([abs_path, expected]) => [
abs_path ? `C:${abs_path.replace(/\//g, '\\')}` : '',
expected,
]) as string[][])
: cases,
)('%s => %s', (abs_path: string, expected: string) => {
expect(PrivateCpuProfilerBindings.getFrameModule(abs_path)).toBe(expected);
Expand Down
48 changes: 25 additions & 23 deletions packages/profiling-node/test/cpu_profiler.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { describe, expect, it } from 'vitest';

import type { ContinuousThreadCpuProfile, ThreadCpuProfile } from '@sentry/types';
import { CpuProfilerBindings, PrivateCpuProfilerBindings } from '../src/cpu_profiler';
import type { RawThreadCpuProfile } from '../src/types';
import { constructItWithTimeout } from './test-utils';

// Required because we test a hypothetical long profile
// and we cannot use advance timers as the c++ relies on
// actual event loop ticks that we cannot advance from jest.
jest.setTimeout(60_000);
// actual event loop ticks that we cannot advance from vitest.
const itWithTimeout = constructItWithTimeout(60_000);

function fail(message: string): never {
throw new Error(message);
Expand Down Expand Up @@ -68,7 +71,7 @@ const assertValidMeasurements = (measurement: RawThreadCpuProfile['measurements'
};

describe('Private bindings', () => {
it('does not crash if collect resources is false', async () => {
itWithTimeout('does not crash if collect resources is false', async () => {
PrivateCpuProfilerBindings.startProfiling('profiled-program');
await wait(100);
expect(() => {
Expand All @@ -77,7 +80,7 @@ describe('Private bindings', () => {
}).not.toThrow();
});

it('throws if invalid format is supplied', async () => {
itWithTimeout('throws if invalid format is supplied', async () => {
PrivateCpuProfilerBindings.startProfiling('profiled-program');
await wait(100);
expect(() => {
Expand All @@ -86,7 +89,7 @@ describe('Private bindings', () => {
}).toThrow('StopProfiling expects a valid format type as second argument.');
});

it('collects resources', async () => {
itWithTimeout('collects resources', async () => {
PrivateCpuProfilerBindings.startProfiling('profiled-program');
await wait(100);

Expand All @@ -103,7 +106,7 @@ describe('Private bindings', () => {
}
});

it('does not collect resources', async () => {
itWithTimeout('does not collect resources', async () => {
PrivateCpuProfilerBindings.startProfiling('profiled-program');
await wait(100);

Expand All @@ -115,12 +118,12 @@ describe('Private bindings', () => {
});

describe('Profiler bindings', () => {
it('exports profiler binding methods', () => {
itWithTimeout('exports profiler binding methods', () => {
expect(typeof CpuProfilerBindings['startProfiling']).toBe('function');
expect(typeof CpuProfilerBindings['stopProfiling']).toBe('function');
});

it('profiles a program', async () => {
itWithTimeout('profiles a program', async () => {
const profile = await profiled('profiled-program', async () => {
await wait(100);
});
Expand All @@ -130,7 +133,7 @@ describe('Profiler bindings', () => {
assertValidSamplesAndStacks(profile.stacks, profile.samples);
});

it('adds thread_id info', async () => {
itWithTimeout('adds thread_id info', async () => {
const profile = await profiled('profiled-program', async () => {
await wait(100);
});
Expand All @@ -146,7 +149,7 @@ describe('Profiler bindings', () => {
}
});

it('caps stack depth at 128', async () => {
itWithTimeout('caps stack depth at 128', async () => {
const recurseToDepth = async (depth: number): Promise<number> => {
if (depth === 0) {
// Wait a bit to make sure stack gets sampled here
Expand All @@ -168,7 +171,7 @@ describe('Profiler bindings', () => {
}
});

it('does not record two profiles when titles match', () => {
itWithTimeout('does not record two profiles when titles match', () => {
CpuProfilerBindings.startProfiling('same-title');
CpuProfilerBindings.startProfiling('same-title');

Expand All @@ -179,19 +182,19 @@ describe('Profiler bindings', () => {
expect(second).toBe(null);
});

it('multiple calls with same title', () => {
itWithTimeout('multiple calls with same title', () => {
CpuProfilerBindings.startProfiling('same-title');
expect(() => {
CpuProfilerBindings.stopProfiling('same-title', 0);
CpuProfilerBindings.stopProfiling('same-title', 0);
}).not.toThrow();
});

it('does not crash if stopTransaction is called before startTransaction', () => {
itWithTimeout('does not crash if stopTransaction is called before startTransaction', () => {
expect(CpuProfilerBindings.stopProfiling('does not exist', 0)).toBe(null);
});

it('does crash if name is invalid', () => {
itWithTimeout('does crash if name is invalid', () => {
expect(() => CpuProfilerBindings.stopProfiling('', 0)).toThrow();
// @ts-expect-error test invalid input
expect(() => CpuProfilerBindings.stopProfiling(undefined)).toThrow();
Expand All @@ -201,12 +204,12 @@ describe('Profiler bindings', () => {
expect(() => CpuProfilerBindings.stopProfiling({})).toThrow();
});

it('does not throw if stopTransaction is called before startTransaction', () => {
itWithTimeout('does not throw if stopTransaction is called before startTransaction', () => {
expect(CpuProfilerBindings.stopProfiling('does not exist', 0)).toBe(null);
expect(() => CpuProfilerBindings.stopProfiling('does not exist', 0)).not.toThrow();
});

it('compiles with eager logging by default', async () => {
itWithTimeout('compiles with eager logging by default', async () => {
const profile = await profiled('profiled-program', async () => {
await wait(100);
});
Expand All @@ -215,7 +218,7 @@ describe('Profiler bindings', () => {
expect(profile.profiler_logging_mode).toBe('eager');
});

it('chunk format type', async () => {
itWithTimeout('chunk format type', async () => {
const profile = await profiled(
'non nullable stack',
async () => {
Expand All @@ -240,7 +243,7 @@ describe('Profiler bindings', () => {
}
});

it('stacks are not null', async () => {
itWithTimeout('stacks are not null', async () => {
const profile = await profiled('non nullable stack', async () => {
await wait(1000);
fibonacci(36);
Expand All @@ -251,7 +254,7 @@ describe('Profiler bindings', () => {
assertValidSamplesAndStacks(profile.stacks, profile.samples);
});

it('samples at ~99hz', async () => {
itWithTimeout('samples at ~99hz', async () => {
CpuProfilerBindings.startProfiling('profile');
await wait(100);
const profile = CpuProfilerBindings.stopProfiling('profile', 0);
Expand All @@ -275,7 +278,7 @@ describe('Profiler bindings', () => {
}
});

it('collects memory footprint', async () => {
itWithTimeout('collects memory footprint', async () => {
CpuProfilerBindings.startProfiling('profile');
await wait(1000);
const profile = CpuProfilerBindings.stopProfiling('profile', 0);
Expand All @@ -291,7 +294,7 @@ describe('Profiler bindings', () => {
assertValidMeasurements(profile.measurements['memory_footprint']);
});

it('collects cpu usage', async () => {
itWithTimeout('collects cpu usage', async () => {
CpuProfilerBindings.startProfiling('profile');
await wait(1000);
const profile = CpuProfilerBindings.stopProfiling('profile', 0);
Expand All @@ -307,7 +310,7 @@ describe('Profiler bindings', () => {
assertValidMeasurements(profile.measurements['cpu_usage']);
});

it('does not overflow measurement buffer if profile runs longer than 30s', async () => {
itWithTimeout('does not overflow measurement buffer if profile runs longer than 30s', async () => {
CpuProfilerBindings.startProfiling('profile');
await wait(35000);
const profile = CpuProfilerBindings.stopProfiling('profile', 0);
Expand All @@ -316,7 +319,6 @@ describe('Profiler bindings', () => {
expect(profile?.measurements?.['memory_footprint']?.values.length).toBeLessThanOrEqual(300);
});

// eslint-disable-next-line jest/no-disabled-tests
it.skip('includes deopt reason', async () => {
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#52-the-object-being-iterated-is-not-a-simple-enumerable
function iterateOverLargeHashTable() {
Expand Down
20 changes: 11 additions & 9 deletions packages/profiling-node/test/integration.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { EventEmitter } from 'events';
import { afterEach, describe, expect, it, vi } from 'vitest';

import { EventEmitter } from 'node:events';

import type { Transport } from '@sentry/types';

Expand All @@ -7,16 +9,16 @@ import { _nodeProfilingIntegration } from '../src/integration';

describe('ProfilingIntegration', () => {
afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
it('has a name', () => {
expect(_nodeProfilingIntegration().name).toBe('ProfilingIntegration');
});

it('does not call transporter if null profile is received', () => {
const transport: Transport = {
send: jest.fn().mockImplementation(() => Promise.resolve()),
flush: jest.fn().mockImplementation(() => Promise.resolve()),
send: vi.fn().mockImplementation(() => Promise.resolve()),
flush: vi.fn().mockImplementation(() => Promise.resolve()),
};
const integration = _nodeProfilingIntegration();
const emitter = new EventEmitter();
Expand All @@ -43,14 +45,14 @@ describe('ProfilingIntegration', () => {

it('binds to spanStart, spanEnd and beforeEnvelope', () => {
const transport: Transport = {
send: jest.fn().mockImplementation(() => Promise.resolve()),
flush: jest.fn().mockImplementation(() => Promise.resolve()),
send: vi.fn().mockImplementation(() => Promise.resolve()),
flush: vi.fn().mockImplementation(() => Promise.resolve()),
};
const integration = _nodeProfilingIntegration();

const client = {
on: jest.fn(),
emit: jest.fn(),
on: vi.fn(),
emit: vi.fn(),
getOptions: () => {
return {
_metadata: {},
Expand All @@ -63,7 +65,7 @@ describe('ProfilingIntegration', () => {
getTransport: () => transport,
} as unknown as NodeClient;

const spy = jest.spyOn(client, 'on');
const spy = vi.spyOn(client, 'on');

integration?.setup?.(client);

Expand Down
Loading

0 comments on commit 0a462ba

Please sign in to comment.