Skip to content
This repository has been archived by the owner on Sep 6, 2023. It is now read-only.

Commit

Permalink
Add Performance Trace hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
gioragutt committed Oct 10, 2020
1 parent 9a2dbda commit f09d7bc
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Object {
"column": 5,
"file": "lib/attach.ts",
"function": "endTest",
"line": 122,
"line": 120,
},
Object {
"column": 5,
Expand Down Expand Up @@ -74,6 +74,7 @@ Object {
"testFullName": "Sanity integration test Sanity integration test 1",
"testName": "Sanity integration test 1",
"timestamp": 2,
"traceOutputFileName": "performanceTrace.json",
},
"steps": Array [
Object {
Expand Down
6 changes: 2 additions & 4 deletions packages/root-cause-core/lib/attach.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { errorInStepHook } from './hooks/errorInStepHook';
import { createHtmlCollectionHook } from './hooks/htmlCollection';
import { networkLogsAfterAllHook, networkLogsBeforeAllHook } from './hooks/networkLogsHooks';
import { createProfilingHooks } from './hooks/profilingHooks';
import { instrumentProfilingHooks } from './hooks/profilingHooks';
import { puppeteerScreenshot } from './hooks/screenshotCollectionHook';
import { stacktraceHook } from './hooks/stacktraceHook';
import { stepMetadataCollectionHook } from './hooks/stepMetadataCollectionHook';
Expand Down Expand Up @@ -109,9 +109,7 @@ export async function attach<TPage extends RootCausePage>(
instrumentor.registerAfterAllHook(networkLogsAfterAllHook);
}

const { startProfilingHook, stopProfilingHook } = await createProfilingHooks(page);
instrumentor.registerBeforeAllHook(startProfilingHook);
instrumentor.registerAfterAllHook(stopProfilingHook);
await instrumentProfilingHooks(instrumentor, page);

instrumentor.registerAfterAllHook(testEndHook);

Expand Down
94 changes: 66 additions & 28 deletions packages/root-cause-core/lib/hooks/profilingHooks.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,78 @@
import { promises as fs } from 'fs';
import { join } from 'path';
import { AfterAllHook, BeforeAllHook, RootCausePage } from '../interfaces';
import { getChromeCDPSession, sendCDPMessage } from '../utils';
import { NOOP_HOOK } from './hookUtils';
import {
AfterAllHook,
BeforeAllHook,
IAutomationFrameworkInstrumentor,
RootCausePage,
} from '../interfaces';
import { getChromeCDPSession, isPlaywrightPage, sendCDPMessage } from '../utils';

export interface ProfilingHooks {
startProfilingHook: BeforeAllHook;
stopProfilingHook: AfterAllHook;
export async function instrumentProfilingHooks(
instrumentor: IAutomationFrameworkInstrumentor,
page: RootCausePage
) {
await instrumentCDPBasedHooks(instrumentor, page);
await instrumentPerformanceTrace(instrumentor, page);
}

export async function createProfilingHooks(page: RootCausePage): Promise<ProfilingHooks> {
async function instrumentPerformanceTrace(
instrumentor: IAutomationFrameworkInstrumentor,
page: RootCausePage
) {
if (isPlaywrightPage(page)) {
return;
}

const traceOutputFileName = 'performanceTrace.json';

const setup: BeforeAllHook = async function startPerformanceTraceHook({ testContext }) {
const outputPath = join(testContext.testArtifactsFolder, traceOutputFileName);
await page.tracing.start({
path: outputPath,
});

// TODO: it's kinda annoying that you have to create a separate hook for teardown.
// I'd expect to be able to do something like returning TeardownLogic like in RxJS.
};

const teardown: AfterAllHook = async function stopPerformanceTraceHook({ testContext }) {
await page.tracing.stop();
testContext.addTestMetadata({ traceOutputFileName });
};

instrumentor.registerBeforeAllHook(setup);
instrumentor.registerAfterAllHook(teardown);
}

// example taken from https://github.com/paulirish/automated-chrome-profiling/blob/master/get-cpu-profile.js
async function instrumentCDPBasedHooks(
instrumentor: IAutomationFrameworkInstrumentor,
page: RootCausePage
) {
const session = await getChromeCDPSession(page);

if (!session) {
return {
startProfilingHook: NOOP_HOOK,
stopProfilingHook: NOOP_HOOK,
};
return;
}

// example taken from https://github.com/paulirish/automated-chrome-profiling/blob/master/get-cpu-profile.js
return {
async startProfilingHook() {
await sendCDPMessage(session, 'Profiler.enable');
await sendCDPMessage(session, 'Profiler.setSamplingInterval', {
interval: 100,
});
await sendCDPMessage(session, 'Profiler.start');
},
async stopProfilingHook({ testContext }) {
const { profile } = await sendCDPMessage(session, 'Profiler.stop');

const profilingFile = `profile.cpuprofile`;
const outputFilePath = join(testContext.testArtifactsFolder, profilingFile);
await fs.writeFile(outputFilePath, JSON.stringify(profile, null, 2));
testContext.addTestMetadata({ profilingFile });
},
const setup: BeforeAllHook = async function startCpuProfilingHook() {
await sendCDPMessage(session, 'Profiler.enable');
await sendCDPMessage(session, 'Profiler.setSamplingInterval', {
interval: 100,
});
await sendCDPMessage(session, 'Profiler.start');
};

const teardown: AfterAllHook = async function stopCpuProfilingHook({ testContext }) {
const { profile } = await sendCDPMessage(session, 'Profiler.stop');

const profilingFile = `profile.cpuprofile`;
const outputFilePath = join(testContext.testArtifactsFolder, profilingFile);
await fs.writeFile(outputFilePath, JSON.stringify(profile, null, 2));
testContext.addTestMetadata({ profilingFile });
};

instrumentor.registerBeforeAllHook(setup);
instrumentor.registerAfterAllHook(teardown);
}
4 changes: 4 additions & 0 deletions packages/root-cause-core/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ export function isNotPlaywrightPage(page: RootCausePage): page is PuppeteerPage
return !('exposeBinding' in page);
}

export function isPlaywrightPage(page: RootCausePage): page is PlaywrightPage {
return !isNotPlaywrightPage(page);
}

export function isPlaywrightChromiumBrowserContext(
context: BrowserContext
): context is ChromiumBrowserContext {
Expand Down

0 comments on commit f09d7bc

Please sign in to comment.