2020-03-20 20:28:31 +00:00
|
|
|
import { expect } from 'chai';
|
2020-04-07 00:04:09 +00:00
|
|
|
import { app, contentTracing, TraceConfig, TraceCategoriesAndOptions } from 'electron/main';
|
2020-03-20 20:28:31 +00:00
|
|
|
import * as fs from 'fs';
|
|
|
|
import * as path from 'path';
|
2020-06-26 20:59:54 +00:00
|
|
|
import { ifdescribe, delay } from './spec-helpers';
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2019-07-15 08:23:35 +00:00
|
|
|
// FIXME: The tests are skipped on arm/arm64.
|
2020-07-17 16:08:44 +00:00
|
|
|
ifdescribe(!(process.platform !== 'win32' && ['arm', 'arm64'].includes(process.arch)))('contentTracing', () => {
|
2019-07-15 08:23:35 +00:00
|
|
|
const record = async (options: TraceConfig | TraceCategoriesAndOptions, outputFilePath: string | undefined, recordTimeInMilliseconds = 1e1) => {
|
2020-03-20 20:28:31 +00:00
|
|
|
await app.whenReady();
|
2019-01-31 02:53:55 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
await contentTracing.startRecording(options);
|
2020-06-26 20:59:54 +00:00
|
|
|
await delay(recordTimeInMilliseconds);
|
2020-03-20 20:28:31 +00:00
|
|
|
const resultFilePath = await contentTracing.stopRecording(outputFilePath);
|
2019-01-31 02:53:55 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
return resultFilePath;
|
|
|
|
};
|
2019-01-31 02:53:55 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
const outputFilePath = path.join(app.getPath('temp'), 'trace.json');
|
2018-12-20 12:11:17 +00:00
|
|
|
beforeEach(() => {
|
|
|
|
if (fs.existsSync(outputFilePath)) {
|
2020-03-20 20:28:31 +00:00
|
|
|
fs.unlinkSync(outputFilePath);
|
2018-12-20 12:11:17 +00:00
|
|
|
}
|
2020-03-20 20:28:31 +00:00
|
|
|
});
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
describe('startRecording', function () {
|
2020-03-20 20:28:31 +00:00
|
|
|
this.timeout(5e3);
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2019-07-15 08:23:35 +00:00
|
|
|
const getFileSizeInKiloBytes = (filePath: string) => {
|
2020-03-20 20:28:31 +00:00
|
|
|
const stats = fs.statSync(filePath);
|
|
|
|
const fileSizeInBytes = stats.size;
|
|
|
|
const fileSizeInKiloBytes = fileSizeInBytes / 1024;
|
|
|
|
return fileSizeInKiloBytes;
|
|
|
|
};
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
it('accepts an empty config', async () => {
|
2020-03-20 20:28:31 +00:00
|
|
|
const config = {};
|
|
|
|
await record(config, outputFilePath);
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
expect(fs.existsSync(outputFilePath)).to.be.true('output exists');
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath);
|
2018-12-20 12:11:17 +00:00
|
|
|
expect(fileSizeInKiloBytes).to.be.above(0,
|
2020-03-20 20:28:31 +00:00
|
|
|
`the trace output file is empty, check "${outputFilePath}"`);
|
|
|
|
});
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
it('accepts a trace config', async () => {
|
|
|
|
// (alexeykuzmin): All categories are excluded on purpose,
|
|
|
|
// so only metadata gets into the output file.
|
|
|
|
const config = {
|
|
|
|
excluded_categories: ['*']
|
2020-03-20 20:28:31 +00:00
|
|
|
};
|
|
|
|
await record(config, outputFilePath);
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
expect(fs.existsSync(outputFilePath)).to.be.true('output exists');
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
// If the `excluded_categories` param above is not respected
|
|
|
|
// the file size will be above 50KB.
|
2020-03-20 20:28:31 +00:00
|
|
|
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath);
|
|
|
|
const expectedMaximumFileSize = 10; // Depends on a platform.
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
expect(fileSizeInKiloBytes).to.be.above(0,
|
2020-03-20 20:28:31 +00:00
|
|
|
`the trace output file is empty, check "${outputFilePath}"`);
|
2018-12-20 12:11:17 +00:00
|
|
|
expect(fileSizeInKiloBytes).to.be.below(expectedMaximumFileSize,
|
|
|
|
`the trace output file is suspiciously large (${fileSizeInKiloBytes}KB),
|
2020-03-20 20:28:31 +00:00
|
|
|
check "${outputFilePath}"`);
|
|
|
|
});
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
it('accepts "categoryFilter" and "traceOptions" as a config', async () => {
|
|
|
|
// (alexeykuzmin): All categories are excluded on purpose,
|
|
|
|
// so only metadata gets into the output file.
|
|
|
|
const config = {
|
|
|
|
categoryFilter: '__ThisIsANonexistentCategory__',
|
|
|
|
traceOptions: ''
|
2020-03-20 20:28:31 +00:00
|
|
|
};
|
|
|
|
await record(config, outputFilePath);
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
expect(fs.existsSync(outputFilePath)).to.be.true('output exists');
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
// If the `categoryFilter` param above is not respected
|
|
|
|
// the file size will be above 50KB.
|
2020-03-20 20:28:31 +00:00
|
|
|
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath);
|
|
|
|
const expectedMaximumFileSize = 10; // Depends on a platform.
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
expect(fileSizeInKiloBytes).to.be.above(0,
|
2020-03-20 20:28:31 +00:00
|
|
|
`the trace output file is empty, check "${outputFilePath}"`);
|
2018-12-20 12:11:17 +00:00
|
|
|
expect(fileSizeInKiloBytes).to.be.below(expectedMaximumFileSize,
|
|
|
|
`the trace output file is suspiciously large (${fileSizeInKiloBytes}KB),
|
2020-03-20 20:28:31 +00:00
|
|
|
check "${outputFilePath}"`);
|
|
|
|
});
|
|
|
|
});
|
2018-12-20 12:11:17 +00:00
|
|
|
|
|
|
|
describe('stopRecording', function () {
|
2020-03-20 20:28:31 +00:00
|
|
|
this.timeout(5e3);
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2019-05-23 17:15:08 +00:00
|
|
|
it('does not crash on empty string', async () => {
|
|
|
|
const options = {
|
|
|
|
categoryFilter: '*',
|
|
|
|
traceOptions: 'record-until-full,enable-sampling'
|
2020-03-20 20:28:31 +00:00
|
|
|
};
|
2019-05-23 17:15:08 +00:00
|
|
|
|
2020-03-20 20:28:31 +00:00
|
|
|
await contentTracing.startRecording(options);
|
|
|
|
const path = await contentTracing.stopRecording('');
|
|
|
|
expect(path).to.be.a('string').that.is.not.empty('result path');
|
|
|
|
expect(fs.statSync(path).isFile()).to.be.true('output exists');
|
|
|
|
});
|
2019-05-23 17:15:08 +00:00
|
|
|
|
2018-12-20 12:11:17 +00:00
|
|
|
it('calls its callback with a result file path', async () => {
|
2020-03-20 20:28:31 +00:00
|
|
|
const resultFilePath = await record(/* options */ {}, outputFilePath);
|
|
|
|
expect(resultFilePath).to.be.a('string').and.be.equal(outputFilePath);
|
|
|
|
});
|
2018-12-20 12:11:17 +00:00
|
|
|
|
2019-04-05 18:19:06 +00:00
|
|
|
it('creates a temporary file when an empty string is passed', async function () {
|
2020-03-20 20:28:31 +00:00
|
|
|
const resultFilePath = await record(/* options */ {}, /* outputFilePath */ '');
|
|
|
|
expect(resultFilePath).to.be.a('string').that.is.not.empty('result path');
|
|
|
|
});
|
2019-05-28 21:15:42 +00:00
|
|
|
|
|
|
|
it('creates a temporary file when no path is passed', async function () {
|
2020-03-20 20:28:31 +00:00
|
|
|
const resultFilePath = await record(/* options */ {}, /* outputFilePath */ undefined);
|
|
|
|
expect(resultFilePath).to.be.a('string').that.is.not.empty('result path');
|
|
|
|
});
|
|
|
|
});
|
2020-08-21 16:25:30 +00:00
|
|
|
|
|
|
|
describe('captured events', () => {
|
|
|
|
it('include V8 samples from the main process', async () => {
|
|
|
|
await contentTracing.startRecording({
|
|
|
|
categoryFilter: 'disabled-by-default-v8.cpu_profiler',
|
|
|
|
traceOptions: 'record-until-full'
|
|
|
|
});
|
|
|
|
{
|
|
|
|
const start = +new Date();
|
|
|
|
let n = 0;
|
|
|
|
const f = () => {};
|
|
|
|
while (+new Date() - start < 200 || n < 500) {
|
|
|
|
await delay(0);
|
|
|
|
f();
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const path = await contentTracing.stopRecording();
|
|
|
|
const data = fs.readFileSync(path, 'utf8');
|
|
|
|
const parsed = JSON.parse(data);
|
|
|
|
expect(parsed.traceEvents.some((x: any) => x.cat === 'disabled-by-default-v8.cpu_profiler' && x.name === 'ProfileChunk')).to.be.true();
|
|
|
|
});
|
|
|
|
});
|
2020-03-20 20:28:31 +00:00
|
|
|
});
|