Merge pull request #10 from JasonGore/jg/add-cook-test
Tests: Add tests for cook
This commit is contained in:
Коммит
f62e02d5b8
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "none",
|
||||
"comment": "Add cook tests. Move around some code without changing any functionality.",
|
||||
"packageName": "flamegrill",
|
||||
"email": "jagore@microsoft.com",
|
||||
"commit": "eb25d4d6f3e6216e0a543804cc794e9e0ce48957",
|
||||
"date": "2019-09-27T23:36:37.532Z"
|
||||
}
|
|
@ -1,64 +1,179 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as tmp from 'tmp';
|
||||
import puppeteer, { Browser, Page } from 'puppeteer';
|
||||
|
||||
import { cook, OutputFiles, Scenario, ScenarioConfig } from '../flamegrill';
|
||||
import { generateFlamegraph } from '../flamegraph/generate';
|
||||
import { checkForRegressions } from '../analysis/processData';
|
||||
|
||||
const profiles = require('../fixtures/profiles.json');
|
||||
const snapshotsDir = path.join(__dirname, '../fixtures/snapshots');
|
||||
|
||||
// TODO: these are black box tests for now but should be refactored to be unit tests
|
||||
// TODO: modules that output files should be modified not to and wrapped by a centralized file output helper
|
||||
// TODO: consider also making file output / github / CI integration another package within this repo
|
||||
|
||||
describe('flamegrill', () => {
|
||||
it('generates expected output', async () => {
|
||||
jest.setTimeout(30000);
|
||||
describe('cook', () => {
|
||||
const profiles = require('../fixtures/profiles.json');
|
||||
const expectedResults = require('../fixtures/results.json');
|
||||
const util = require('../util');
|
||||
const fixturesDir = path.join(__dirname, '../fixtures');
|
||||
const snapshotsDir = path.join(__dirname, '../fixtures/snapshots');
|
||||
|
||||
let scenarios: Scenario[];
|
||||
let scenarioNames: string[];
|
||||
let outdir: tmp.DirResult;
|
||||
let scenarioConfig: ScenarioConfig;
|
||||
let scenarioIndex: number = 0;
|
||||
|
||||
const testPage: Page = {
|
||||
close: jest.fn(() => Promise.resolve()),
|
||||
goto: jest.fn(() => {
|
||||
return Promise.resolve(null);
|
||||
}),
|
||||
setDefaultTimeout: jest.fn(() => {})
|
||||
} as unknown as Page;
|
||||
|
||||
const testBrowser: Browser = {
|
||||
newPage: jest.fn(() => {
|
||||
return Promise.resolve(testPage);
|
||||
}),
|
||||
close: jest.fn(() => {})
|
||||
} as unknown as Browser;
|
||||
|
||||
expect.assertions(89);
|
||||
beforeAll(() => {
|
||||
// Processing all profiles takes more than the default 5 seconds.
|
||||
jest.setTimeout(60000);
|
||||
|
||||
jest.spyOn(puppeteer, 'launch').mockImplementation(() => {
|
||||
return Promise.resolve(testBrowser);
|
||||
});
|
||||
|
||||
jest.spyOn(util, 'arr_diff').mockImplementation(() => {
|
||||
let logfile;
|
||||
// This code assumes scenarios are processed in the same order passed into cook, which
|
||||
// is true as of writing.
|
||||
const scenarioName = scenarioNames[Math.floor(scenarioIndex / 2)];
|
||||
if (scenarioIndex % 2) {
|
||||
logfile = profiles[scenarioName].reference.logFile;
|
||||
} else {
|
||||
logfile = profiles[scenarioName].logFile;
|
||||
}
|
||||
scenarioIndex += 1;
|
||||
|
||||
return [logfile];
|
||||
});
|
||||
|
||||
outdir = tmp.dirSync({ unsafeCleanup: true });
|
||||
scenarioConfig = {
|
||||
outDir: outdir.name,
|
||||
tempDir: fixturesDir
|
||||
};
|
||||
|
||||
scenarioNames = Object.keys(profiles);
|
||||
scenarios = scenarioNames.map(scenarioName => {
|
||||
return {
|
||||
name: scenarioName,
|
||||
scenario: scenarioName + ".url",
|
||||
reference: scenarioName + "_ref.url"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const outdir = tmp.dirSync({ unsafeCleanup: true });
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
outdir.removeCallback();
|
||||
})
|
||||
|
||||
await Promise.all(Object.keys(profiles).map(key => {
|
||||
let logfile = require.resolve(path.join('../fixtures', profiles[key].logFile));
|
||||
let outfile = path.join(outdir.name, key);
|
||||
return generateFlamegraph(logfile, outfile)
|
||||
}));
|
||||
it('generates expected output', async () => {
|
||||
const testResults = await cook(scenarios, scenarioConfig);
|
||||
|
||||
await Promise.all(Object.keys(profiles).map(key => {
|
||||
let logfile = require.resolve(path.join('../fixtures', profiles[key].reference.logFile));
|
||||
let outfile = path.join(outdir.name, key + '_ref');
|
||||
return generateFlamegraph(logfile, outfile)
|
||||
}));
|
||||
// The path will differ for every test run, so remove it before comparing results.
|
||||
// TODO: remove these !s after types are cleaned up
|
||||
Object.keys(testResults).forEach(result => {
|
||||
Object.keys(testResults[result].files!).forEach(file => {
|
||||
testResults[result].files![file as keyof OutputFiles]
|
||||
= path.basename(testResults[result].files![file as keyof OutputFiles]!);
|
||||
})
|
||||
Object.keys(testResults[result].reference!.files!).forEach(file => {
|
||||
testResults[result].reference!.files![file as keyof OutputFiles]
|
||||
= path.basename(testResults[result].reference!.files![file as keyof OutputFiles]!);
|
||||
})
|
||||
});
|
||||
|
||||
Object.keys(profiles).forEach(key => {
|
||||
// TODO: this code block is duplicating code in flamegrill.ts and should be removed as code is refactored.
|
||||
let datafileBefore = path.join(outdir.name, key + '_ref.data.js');
|
||||
let datafileAfter = path.join(outdir.name, key + '.data.js');
|
||||
let regressionfile = path.join(outdir.name, key + '.regression.txt');
|
||||
expect(testResults).toEqual(expectedResults);
|
||||
|
||||
const analysis = checkForRegressions(datafileBefore, datafileAfter);
|
||||
const snapshotFiles = fs.readdirSync(snapshotsDir);
|
||||
const testFiles = fs.readdirSync(outdir.name);
|
||||
|
||||
if(analysis.isRegression) {
|
||||
fs.writeFileSync(regressionfile, analysis.summary);
|
||||
}
|
||||
expect(testFiles).toEqual(snapshotFiles);
|
||||
|
||||
testFiles.forEach(file => {
|
||||
// Some generated output creates files with \r\n. Some environments spit out \n.
|
||||
// Ignore line break types when comparing results.
|
||||
const analysis = fs.readFileSync(path.join(snapshotsDir, file), 'utf8').split(/\r?\n/g);
|
||||
const output = fs.readFileSync(path.join(outdir.name, file), 'utf8').split(/\r?\n/g);
|
||||
|
||||
expect(output).toEqual(analysis);
|
||||
});
|
||||
|
||||
expect((testBrowser.close as jest.Mock).mock.calls.length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
// These tests are technically redundant with cook tests but are left for now as they may be useful
|
||||
// as unit tests are added.
|
||||
describe('generateFlamegraph, checkForRegressions', () => {
|
||||
const profiles = require('../fixtures/profiles.json');
|
||||
const snapshotsDir = path.join(__dirname, '../fixtures/snapshots');
|
||||
|
||||
it('generates expected output', async () => {
|
||||
// Processing all profiles takes more than the default 5 seconds.
|
||||
jest.setTimeout(30000);
|
||||
|
||||
expect.assertions(89);
|
||||
|
||||
const outdir = tmp.dirSync({ unsafeCleanup: true });
|
||||
|
||||
const snapshotFiles = fs.readdirSync(snapshotsDir);
|
||||
const testFiles = fs.readdirSync(outdir.name);
|
||||
await Promise.all(Object.keys(profiles).map(key => {
|
||||
let logfile = require.resolve(path.join('../fixtures', profiles[key].logFile));
|
||||
let outfile = path.join(outdir.name, key);
|
||||
return generateFlamegraph(logfile, outfile)
|
||||
}));
|
||||
|
||||
expect(testFiles).toEqual(snapshotFiles);
|
||||
await Promise.all(Object.keys(profiles).map(key => {
|
||||
let logfile = require.resolve(path.join('../fixtures', profiles[key].reference.logFile));
|
||||
let outfile = path.join(outdir.name, key + '_ref');
|
||||
return generateFlamegraph(logfile, outfile)
|
||||
}));
|
||||
|
||||
testFiles.forEach(file => {
|
||||
// Some generated output creates files with \r\n. Some environments spit out \n.
|
||||
// Ignore line break types when comparing results.
|
||||
const analysis = fs.readFileSync(path.join(snapshotsDir, file), 'utf8').split(/\r?\n/g);
|
||||
const output = fs.readFileSync(path.join(outdir.name, file), 'utf8').split(/\r?\n/g);
|
||||
Object.keys(profiles).forEach(key => {
|
||||
// TODO: this code block is duplicating code in flamegrill.ts and should be removed as code is refactored.
|
||||
let datafileBefore = path.join(outdir.name, key + '_ref.data.js');
|
||||
let datafileAfter = path.join(outdir.name, key + '.data.js');
|
||||
let regressionfile = path.join(outdir.name, key + '.regression.txt');
|
||||
|
||||
expect(output).toEqual(analysis);
|
||||
const analysis = checkForRegressions(datafileBefore, datafileAfter);
|
||||
|
||||
if(analysis.isRegression) {
|
||||
fs.writeFileSync(regressionfile, analysis.summary);
|
||||
}
|
||||
});
|
||||
|
||||
const snapshotFiles = fs.readdirSync(snapshotsDir);
|
||||
const testFiles = fs.readdirSync(outdir.name);
|
||||
|
||||
expect(testFiles).toEqual(snapshotFiles);
|
||||
|
||||
testFiles.forEach(file => {
|
||||
// Some generated output creates files with \r\n. Some environments spit out \n.
|
||||
// Ignore line break types when comparing results.
|
||||
const analysis = fs.readFileSync(path.join(snapshotsDir, file), 'utf8').split(/\r?\n/g);
|
||||
const output = fs.readFileSync(path.join(outdir.name, file), 'utf8').split(/\r?\n/g);
|
||||
|
||||
expect(output).toEqual(analysis);
|
||||
});
|
||||
|
||||
outdir.removeCallback();
|
||||
});
|
||||
|
||||
outdir.removeCallback();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import * as tmp from 'tmp';
|
||||
import { Browser, Page } from 'puppeteer';
|
||||
|
||||
import { runProfile } from '../profile';
|
||||
|
||||
// These tests should be in flamegrill.test.ts but there is some nasty side effect issue that causes them to fail.
|
||||
describe('runProfile', () => {
|
||||
let outdir: tmp.DirResult;
|
||||
let logfile: tmp.FileResult;
|
||||
|
||||
const testUrl = 'testUrl';
|
||||
const testPage: Page = {
|
||||
close: jest.fn(() => Promise.resolve()),
|
||||
goto: jest.fn(() => {
|
||||
return Promise.resolve(null);
|
||||
}),
|
||||
setDefaultTimeout: jest.fn(() => {})
|
||||
} as unknown as Page;
|
||||
|
||||
const testBrowser: Browser = {
|
||||
newPage: jest.fn(() => {
|
||||
logfile = tmp.fileSync({ dir: outdir.name });
|
||||
return Promise.resolve(testPage);
|
||||
})
|
||||
} as unknown as Browser;
|
||||
|
||||
beforeAll(() => {
|
||||
outdir = tmp.dirSync({ unsafeCleanup: true });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
outdir.removeCallback();
|
||||
})
|
||||
|
||||
it('performs expected operations', async () => {
|
||||
const result = await runProfile(testBrowser, testUrl, 'testScenario', outdir.name);
|
||||
|
||||
expect((testPage.setDefaultTimeout as jest.Mock).mock.calls.length).toEqual(1);
|
||||
expect((testPage.setDefaultTimeout as jest.Mock).mock.calls[0][0]).toEqual(0);
|
||||
expect((testPage.goto as jest.Mock).mock.calls.length).toEqual(1);
|
||||
expect((testPage.goto as jest.Mock).mock.calls[0][0]).toEqual(testUrl);
|
||||
expect((testPage.close as jest.Mock).mock.calls.length).toEqual(1);
|
||||
|
||||
expect(logfile).toBeDefined();
|
||||
expect(result).toEqual(logfile.name);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,338 @@
|
|||
{
|
||||
"BaseButton": {
|
||||
"files": {
|
||||
"dataFile": "BaseButton.data.js",
|
||||
"flamegraphFile": "BaseButton.html",
|
||||
"regressionFile": "BaseButton.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "BaseButton_ref.data.js",
|
||||
"flamegraphFile": "BaseButton_ref.html"
|
||||
},
|
||||
"numTicks": 345
|
||||
},
|
||||
"numTicks": 327,
|
||||
"isRegression": false
|
||||
},
|
||||
"BaseButtonNew": {
|
||||
"files": {
|
||||
"dataFile": "BaseButtonNew.data.js",
|
||||
"flamegraphFile": "BaseButtonNew.html",
|
||||
"regressionFile": "BaseButtonNew.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "BaseButtonNew_ref.data.js",
|
||||
"flamegraphFile": "BaseButtonNew_ref.html"
|
||||
},
|
||||
"numTicks": 426
|
||||
},
|
||||
"numTicks": 421,
|
||||
"isRegression": false
|
||||
},
|
||||
"button": {
|
||||
"files": {
|
||||
"dataFile": "button.data.js",
|
||||
"flamegraphFile": "button.html",
|
||||
"regressionFile": "button.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "button_ref.data.js",
|
||||
"flamegraphFile": "button_ref.html"
|
||||
},
|
||||
"numTicks": 28
|
||||
},
|
||||
"numTicks": 26,
|
||||
"isRegression": false
|
||||
},
|
||||
"DefaultButton": {
|
||||
"files": {
|
||||
"dataFile": "DefaultButton.data.js",
|
||||
"flamegraphFile": "DefaultButton.html",
|
||||
"regressionFile": "DefaultButton.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "DefaultButton_ref.data.js",
|
||||
"flamegraphFile": "DefaultButton_ref.html"
|
||||
},
|
||||
"numTicks": 528
|
||||
},
|
||||
"numTicks": 455,
|
||||
"isRegression": false
|
||||
},
|
||||
"DefaultButtonNew": {
|
||||
"files": {
|
||||
"dataFile": "DefaultButtonNew.data.js",
|
||||
"flamegraphFile": "DefaultButtonNew.html",
|
||||
"regressionFile": "DefaultButtonNew.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "DefaultButtonNew_ref.data.js",
|
||||
"flamegraphFile": "DefaultButtonNew_ref.html"
|
||||
},
|
||||
"numTicks": 923
|
||||
},
|
||||
"numTicks": 882,
|
||||
"isRegression": false
|
||||
},
|
||||
"DetailsRow": {
|
||||
"files": {
|
||||
"dataFile": "DetailsRow.data.js",
|
||||
"flamegraphFile": "DetailsRow.html",
|
||||
"regressionFile": "DetailsRow.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "DetailsRow_ref.data.js",
|
||||
"flamegraphFile": "DetailsRow_ref.html"
|
||||
},
|
||||
"numTicks": 1471
|
||||
},
|
||||
"numTicks": 2750,
|
||||
"isRegression": true
|
||||
},
|
||||
"DetailsRowFast": {
|
||||
"files": {
|
||||
"dataFile": "DetailsRowFast.data.js",
|
||||
"flamegraphFile": "DetailsRowFast.html",
|
||||
"regressionFile": "DetailsRowFast.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "DetailsRowFast_ref.data.js",
|
||||
"flamegraphFile": "DetailsRowFast_ref.html"
|
||||
},
|
||||
"numTicks": 1409
|
||||
},
|
||||
"numTicks": 2695,
|
||||
"isRegression": true
|
||||
},
|
||||
"DetailsRowNoStyles": {
|
||||
"files": {
|
||||
"dataFile": "DetailsRowNoStyles.data.js",
|
||||
"flamegraphFile": "DetailsRowNoStyles.html",
|
||||
"regressionFile": "DetailsRowNoStyles.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "DetailsRowNoStyles_ref.data.js",
|
||||
"flamegraphFile": "DetailsRowNoStyles_ref.html"
|
||||
},
|
||||
"numTicks": 1466
|
||||
},
|
||||
"numTicks": 1948,
|
||||
"isRegression": true
|
||||
},
|
||||
"DocumentCardTitle": {
|
||||
"files": {
|
||||
"dataFile": "DocumentCardTitle.data.js",
|
||||
"flamegraphFile": "DocumentCardTitle.html",
|
||||
"regressionFile": "DocumentCardTitle.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "DocumentCardTitle_ref.data.js",
|
||||
"flamegraphFile": "DocumentCardTitle_ref.html"
|
||||
},
|
||||
"numTicks": 15919
|
||||
},
|
||||
"numTicks": 16012,
|
||||
"isRegression": false
|
||||
},
|
||||
"MenuButton": {
|
||||
"files": {
|
||||
"dataFile": "MenuButton.data.js",
|
||||
"flamegraphFile": "MenuButton.html",
|
||||
"regressionFile": "MenuButton.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "MenuButton_ref.data.js",
|
||||
"flamegraphFile": "MenuButton_ref.html"
|
||||
},
|
||||
"numTicks": 590
|
||||
},
|
||||
"numTicks": 647,
|
||||
"isRegression": false
|
||||
},
|
||||
"MenuButtonNew": {
|
||||
"files": {
|
||||
"dataFile": "MenuButtonNew.data.js",
|
||||
"flamegraphFile": "MenuButtonNew.html",
|
||||
"regressionFile": "MenuButtonNew.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "MenuButtonNew_ref.data.js",
|
||||
"flamegraphFile": "MenuButtonNew_ref.html"
|
||||
},
|
||||
"numTicks": 1581
|
||||
},
|
||||
"numTicks": 1548,
|
||||
"isRegression": false
|
||||
},
|
||||
"PrimaryButton": {
|
||||
"files": {
|
||||
"dataFile": "PrimaryButton.data.js",
|
||||
"flamegraphFile": "PrimaryButton.html",
|
||||
"regressionFile": "PrimaryButton.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "PrimaryButton_ref.data.js",
|
||||
"flamegraphFile": "PrimaryButton_ref.html"
|
||||
},
|
||||
"numTicks": 496
|
||||
},
|
||||
"numTicks": 488,
|
||||
"isRegression": false
|
||||
},
|
||||
"PrimaryButtonNew": {
|
||||
"files": {
|
||||
"dataFile": "PrimaryButtonNew.data.js",
|
||||
"flamegraphFile": "PrimaryButtonNew.html",
|
||||
"regressionFile": "PrimaryButtonNew.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "PrimaryButtonNew_ref.data.js",
|
||||
"flamegraphFile": "PrimaryButtonNew_ref.html"
|
||||
},
|
||||
"numTicks": 1001
|
||||
},
|
||||
"numTicks": 922,
|
||||
"isRegression": false
|
||||
},
|
||||
"SplitButton": {
|
||||
"files": {
|
||||
"dataFile": "SplitButton.data.js",
|
||||
"flamegraphFile": "SplitButton.html",
|
||||
"regressionFile": "SplitButton.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "SplitButton_ref.data.js",
|
||||
"flamegraphFile": "SplitButton_ref.html"
|
||||
},
|
||||
"numTicks": 1355
|
||||
},
|
||||
"numTicks": 1293,
|
||||
"isRegression": false
|
||||
},
|
||||
"SplitButtonNew": {
|
||||
"files": {
|
||||
"dataFile": "SplitButtonNew.data.js",
|
||||
"flamegraphFile": "SplitButtonNew.html",
|
||||
"regressionFile": "SplitButtonNew.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "SplitButtonNew_ref.data.js",
|
||||
"flamegraphFile": "SplitButtonNew_ref.html"
|
||||
},
|
||||
"numTicks": 3048
|
||||
},
|
||||
"numTicks": 3155,
|
||||
"isRegression": false
|
||||
},
|
||||
"Stack": {
|
||||
"files": {
|
||||
"dataFile": "Stack.data.js",
|
||||
"flamegraphFile": "Stack.html",
|
||||
"regressionFile": "Stack.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "Stack_ref.data.js",
|
||||
"flamegraphFile": "Stack_ref.html"
|
||||
},
|
||||
"numTicks": 251
|
||||
},
|
||||
"numTicks": 263,
|
||||
"isRegression": false
|
||||
},
|
||||
"StackWithIntrinsicChildren": {
|
||||
"files": {
|
||||
"dataFile": "StackWithIntrinsicChildren.data.js",
|
||||
"flamegraphFile": "StackWithIntrinsicChildren.html",
|
||||
"regressionFile": "StackWithIntrinsicChildren.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "StackWithIntrinsicChildren_ref.data.js",
|
||||
"flamegraphFile": "StackWithIntrinsicChildren_ref.html"
|
||||
},
|
||||
"numTicks": 596
|
||||
},
|
||||
"numTicks": 563,
|
||||
"isRegression": false
|
||||
},
|
||||
"StackWithTextChildren": {
|
||||
"files": {
|
||||
"dataFile": "StackWithTextChildren.data.js",
|
||||
"flamegraphFile": "StackWithTextChildren.html",
|
||||
"regressionFile": "StackWithTextChildren.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "StackWithTextChildren_ref.data.js",
|
||||
"flamegraphFile": "StackWithTextChildren_ref.html"
|
||||
},
|
||||
"numTicks": 1928
|
||||
},
|
||||
"numTicks": 1978,
|
||||
"isRegression": false
|
||||
},
|
||||
"Text": {
|
||||
"files": {
|
||||
"dataFile": "Text.data.js",
|
||||
"flamegraphFile": "Text.html",
|
||||
"regressionFile": "Text.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "Text_ref.data.js",
|
||||
"flamegraphFile": "Text_ref.html"
|
||||
},
|
||||
"numTicks": 168
|
||||
},
|
||||
"numTicks": 206,
|
||||
"isRegression": false
|
||||
},
|
||||
"Toggle": {
|
||||
"files": {
|
||||
"dataFile": "Toggle.data.js",
|
||||
"flamegraphFile": "Toggle.html",
|
||||
"regressionFile": "Toggle.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "Toggle_ref.data.js",
|
||||
"flamegraphFile": "Toggle_ref.html"
|
||||
},
|
||||
"numTicks": 454
|
||||
},
|
||||
"numTicks": 882,
|
||||
"isRegression": true
|
||||
},
|
||||
"ToggleNew": {
|
||||
"files": {
|
||||
"dataFile": "ToggleNew.data.js",
|
||||
"flamegraphFile": "ToggleNew.html",
|
||||
"regressionFile": "ToggleNew.regression.txt"
|
||||
},
|
||||
"reference": {
|
||||
"files": {
|
||||
"dataFile": "ToggleNew_ref.data.js",
|
||||
"flamegraphFile": "ToggleNew_ref.html"
|
||||
},
|
||||
"numTicks": 1102
|
||||
},
|
||||
"numTicks": 1165,
|
||||
"isRegression": false
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import puppeteer, { Browser } from 'puppeteer';
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
import { runProfile } from './profile';
|
||||
import { generateFlamegraph, GeneratedFiles } from './flamegraph/generate';
|
||||
import { checkForRegressions } from './analysis/processData';
|
||||
|
||||
|
@ -83,10 +85,10 @@ export async function cook(scenarios: Scenario[], config: ScenarioConfig): Promi
|
|||
const perfTests: PerfTests = {};
|
||||
|
||||
for (const scenario of scenarios) {
|
||||
let logFile = await runPerfTest(browser, scenario.scenario, scenario.name, tempDir);
|
||||
let logFile = await runProfile(browser, scenario.scenario, scenario.name, tempDir);
|
||||
let logFileRef;
|
||||
if (scenario.reference) {
|
||||
logFileRef = await runPerfTest(browser, scenario.reference, scenario.name, tempDir);
|
||||
logFileRef = await runProfile(browser, scenario.reference, scenario.name, tempDir);
|
||||
}
|
||||
|
||||
let outFileRef = path.join(outDir, `${scenario.name}_ref`);
|
||||
|
@ -134,49 +136,6 @@ export async function cook(scenarios: Scenario[], config: ScenarioConfig): Promi
|
|||
return analyses;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} browser Launched puppeteer instance.
|
||||
* @param {string} testUrl Base URL supporting 'scenario' and 'iterations' query parameters.
|
||||
* @param {string} scenarioName Name of scenario that will be used with baseUrl.
|
||||
* @param {string} logDir Absolute path to output log profiles.
|
||||
* @returns {string} Log file path associated with test.
|
||||
*/
|
||||
async function runPerfTest(browser: Browser, testUrl: string, scenarioName: string, logDir: string): Promise<string> {
|
||||
const logFilesBefore = fs.readdirSync(logDir);
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
||||
// Default timeout is 30 seconds. This is good for most tests except for problematic components like DocumentCardTitle.
|
||||
// Disable timeout for now and tweak to a maximum setting once server condtiions are better known.
|
||||
// TODO: argument? should probably default to 30 seconds
|
||||
page.setDefaultTimeout(0);
|
||||
|
||||
const logFilesAfter = fs.readdirSync(logDir);
|
||||
|
||||
const testLogFile = arr_diff(logFilesBefore, logFilesAfter);
|
||||
|
||||
if (testLogFile.length !== 1) {
|
||||
// We have to be able to identify log file associated with tab. Throw error if we can't.
|
||||
// TODO: what should be the standard for erroring? console.error? throw? return failure?
|
||||
// TODO: make sure all async function calls have catch blocks
|
||||
// TODO: make sure invalid URLs (and other inputs) don't hang result
|
||||
throw new Error(`Could not determine log file for ${testUrl}. Log files detected: [ ${testLogFile} ]`);
|
||||
}
|
||||
|
||||
console.log(`Starting test for ${scenarioName} at ${testUrl}`);
|
||||
|
||||
console.time('Ran perf test in');
|
||||
await page.goto(testUrl);
|
||||
console.timeEnd('Ran perf test in');
|
||||
|
||||
console.log('testLogFile: ' + testLogFile[0]);
|
||||
|
||||
await page.close();
|
||||
|
||||
return path.join(logDir, testLogFile[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create test summary based on test results.
|
||||
*/
|
||||
|
@ -223,35 +182,6 @@ function getTicks(resultsFile: string): number | undefined {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Array diff utility that returns a list of elements that are not present in both arrays.
|
||||
*
|
||||
* @param {Array} a1 First array
|
||||
* @param {Array} a2 Second array
|
||||
*/
|
||||
function arr_diff(a1: string[], a2: string[]): string[] {
|
||||
let a = {} as any;
|
||||
let diff: string[] = [];
|
||||
|
||||
for (var i = 0; i < a1.length; i++) {
|
||||
a[a1[i]] = true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < a2.length; i++) {
|
||||
if (a[a2[i]]) {
|
||||
delete a[a2[i]];
|
||||
} else {
|
||||
a[a2[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (var k in a) {
|
||||
diff.push(k);
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
export default {
|
||||
cook
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { Browser } from 'puppeteer';
|
||||
|
||||
import { arr_diff } from './util';
|
||||
|
||||
/**
|
||||
* Run profiler against provided URL and return resulting profiler output.
|
||||
*
|
||||
* @param {*} browser Launched puppeteer instance.
|
||||
* @param {string} testUrl Base URL supporting 'scenario' and 'iterations' query parameters.
|
||||
* @param {string} scenarioName Name of scenario that will be used with baseUrl.
|
||||
* @param {string} logDir Absolute path to output log profiles.
|
||||
* @returns {string} Log file path associated with test.
|
||||
*/
|
||||
export async function runProfile(browser: Browser, testUrl: string, scenarioName: string, logDir: string): Promise<string> {
|
||||
const logFilesBefore = fs.readdirSync(logDir);
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
||||
// Default timeout is 30 seconds. This is good for most tests except for problematic components like DocumentCardTitle.
|
||||
// Disable timeout for now and tweak to a maximum setting once server condtiions are better known.
|
||||
// TODO: argument? should probably default to 30 seconds
|
||||
page.setDefaultTimeout(0);
|
||||
|
||||
const logFilesAfter = fs.readdirSync(logDir);
|
||||
|
||||
const testLogFile = arr_diff(logFilesBefore, logFilesAfter);
|
||||
|
||||
if (testLogFile.length !== 1) {
|
||||
// We have to be able to identify log file associated with tab. Throw error if we can't.
|
||||
// TODO: what should be the standard for erroring? console.error? throw? return failure?
|
||||
// TODO: make sure all async function calls have catch blocks
|
||||
// TODO: make sure invalid URLs (and other inputs) don't hang result
|
||||
throw new Error(`Could not determine log file for ${testUrl}. Log files detected: [ ${testLogFile} ]`);
|
||||
}
|
||||
|
||||
console.log(`Starting test for ${scenarioName} at ${testUrl}`);
|
||||
|
||||
console.time('Ran profile in');
|
||||
await page.goto(testUrl);
|
||||
console.timeEnd('Ran profile in');
|
||||
|
||||
console.log('testLogFile: ' + testLogFile[0]);
|
||||
|
||||
await page.close();
|
||||
|
||||
return path.join(logDir, testLogFile[0]);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/**
|
||||
* Array diff utility that returns a list of elements that are not present in both arrays.
|
||||
*
|
||||
* @param {Array} a1 First array
|
||||
* @param {Array} a2 Second array
|
||||
*/
|
||||
export function arr_diff(a1: string[], a2: string[]): string[] {
|
||||
let a = {} as any;
|
||||
let diff: string[] = [];
|
||||
|
||||
for (var i = 0; i < a1.length; i++) {
|
||||
a[a1[i]] = true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < a2.length; i++) {
|
||||
if (a[a2[i]]) {
|
||||
delete a[a2[i]];
|
||||
} else {
|
||||
a[a2[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (var k in a) {
|
||||
diff.push(k);
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
Загрузка…
Ссылка в новой задаче