mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat: add unit test support for bisect (#7553)
This commit is contained in:
parent
686030fe0d
commit
a0b1f6b401
@ -292,12 +292,16 @@ The following steps are needed to update the Chromium version.
|
|||||||
|
|
||||||
### Bisecting upstream changes
|
### Bisecting upstream changes
|
||||||
|
|
||||||
Sometimes, performing a Chromium roll causes tests to fail. To figure out the cause, you need to bisect Chromium revisions to figure out the earliest possible revision that changed the behavior. The script in `utils/bisect.js` can be helpful here. Given a Node.js script that calls `process.exit(1)` for bad revisions, run this from the Puppeteer repository’s root directory:
|
Sometimes, performing a Chromium roll causes tests to fail. To figure out the cause, you need to bisect Chromium revisions to figure out the earliest possible revision that changed the behavior. The script in `utils/bisect.js` can be helpful here. Given a pattern for one or more unit tests, it will automatically bisect the current range:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
node utils/bisect.js --good 686378 --bad 706915 script.js
|
node utils/bisect.js --good 686378 --bad 706915 script.js
|
||||||
|
|
||||||
|
node utils/bisect.js --unit-test Response.fromCache
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default, it will use the Chromium revision in `src/revisions.ts` from the `main` branch and from the working tree to determine the range to bisect.
|
||||||
|
|
||||||
## Releasing to npm
|
## Releasing to npm
|
||||||
|
|
||||||
Releasing to npm consists of the following phases:
|
Releasing to npm consists of the following phases:
|
||||||
|
@ -21,7 +21,7 @@ const pptr = require('..');
|
|||||||
const browserFetcher = pptr.createBrowserFetcher();
|
const browserFetcher = pptr.createBrowserFetcher();
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { fork } = require('child_process');
|
const { fork, spawn, execSync } = require('child_process');
|
||||||
|
|
||||||
const COLOR_RESET = '\x1b[0m';
|
const COLOR_RESET = '\x1b[0m';
|
||||||
const COLOR_RED = '\x1b[31m';
|
const COLOR_RED = '\x1b[31m';
|
||||||
@ -35,12 +35,16 @@ Usage:
|
|||||||
node bisect.js --good <revision> --bad <revision> <script>
|
node bisect.js --good <revision> --bad <revision> <script>
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
--good revision that is known to be GOOD
|
--good revision that is known to be GOOD, defaults to the chromium revision in src/revision.ts in the main branch
|
||||||
--bad revision that is known to be BAD
|
--bad revision that is known to be BAD, defaults to the chromium revision in src/revision.ts
|
||||||
<script> path to the script that returns non-zero code for BAD revisions and 0 for good
|
--no-cache do not keep downloaded Chromium revisions
|
||||||
|
--unit-test pattern that identifies a unit tests that should be checked
|
||||||
|
--script path to a script that returns non-zero code for BAD revisions and 0 for good
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
node utils/bisect.js --good 577361 --bad 599821 simple.js
|
node utils/bisect.js --unit-test test
|
||||||
|
node utils/bisect.js --good 577361 --bad 599821 --script simple.js
|
||||||
|
node utils/bisect.js --good 577361 --bad 599821 --unit-test test
|
||||||
`;
|
`;
|
||||||
|
|
||||||
if (argv.h || argv.help) {
|
if (argv.h || argv.help) {
|
||||||
@ -49,23 +53,44 @@ if (argv.h || argv.help) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof argv.good !== 'number') {
|
if (typeof argv.good !== 'number') {
|
||||||
console.log(
|
argv.good = getChromiumRevision('main');
|
||||||
COLOR_RED + 'ERROR: expected --good argument to be a number' + COLOR_RESET
|
if (typeof argv.good !== 'number') {
|
||||||
);
|
console.log(
|
||||||
console.log(help);
|
COLOR_RED +
|
||||||
process.exit(1);
|
'ERROR: Could not parse current Chromium revision' +
|
||||||
|
COLOR_RESET
|
||||||
|
);
|
||||||
|
console.log(help);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof argv.bad !== 'number') {
|
if (typeof argv.bad !== 'number') {
|
||||||
|
argv.bad = getChromiumRevision();
|
||||||
|
if (typeof argv.bad !== 'number') {
|
||||||
|
console.log(
|
||||||
|
COLOR_RED +
|
||||||
|
'ERROR: Could not parse Chromium revision in the main branch' +
|
||||||
|
COLOR_RESET
|
||||||
|
);
|
||||||
|
console.log(help);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!argv.script && !argv['unit-test']) {
|
||||||
console.log(
|
console.log(
|
||||||
COLOR_RED + 'ERROR: expected --bad argument to be a number' + COLOR_RESET
|
COLOR_RED +
|
||||||
|
'ERROR: Expected to be given a script or a unit test to run' +
|
||||||
|
COLOR_RESET
|
||||||
);
|
);
|
||||||
console.log(help);
|
console.log(help);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const scriptPath = path.resolve(argv._[0]);
|
const scriptPath = argv.script ? path.resolve(argv.script) : null;
|
||||||
if (!fs.existsSync(scriptPath)) {
|
|
||||||
|
if (argv.script && !fs.existsSync(scriptPath)) {
|
||||||
console.log(
|
console.log(
|
||||||
COLOR_RED +
|
COLOR_RED +
|
||||||
'ERROR: Expected to be given a path to a script to run' +
|
'ERROR: Expected to be given a path to a script to run' +
|
||||||
@ -75,7 +100,7 @@ if (!fs.existsSync(scriptPath)) {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
(async (scriptPath, good, bad) => {
|
(async (scriptPath, good, bad, pattern, noCache) => {
|
||||||
const span = Math.abs(good - bad);
|
const span = Math.abs(good - bad);
|
||||||
console.log(
|
console.log(
|
||||||
`Bisecting ${COLOR_YELLOW}${span}${COLOR_RESET} revisions in ${COLOR_YELLOW}~${
|
`Bisecting ${COLOR_YELLOW}${span}${COLOR_RESET} revisions in ${COLOR_YELLOW}~${
|
||||||
@ -88,9 +113,11 @@ if (!fs.existsSync(scriptPath)) {
|
|||||||
const revision = await findDownloadableRevision(middle, good, bad);
|
const revision = await findDownloadableRevision(middle, good, bad);
|
||||||
if (!revision || revision === good || revision === bad) break;
|
if (!revision || revision === good || revision === bad) break;
|
||||||
let info = browserFetcher.revisionInfo(revision);
|
let info = browserFetcher.revisionInfo(revision);
|
||||||
const shouldRemove = !info.local;
|
const shouldRemove = noCache && !info.local;
|
||||||
info = await downloadRevision(revision);
|
info = await downloadRevision(revision);
|
||||||
const exitCode = await runScript(scriptPath, info);
|
const exitCode = await (pattern
|
||||||
|
? runUnitTest(pattern, info)
|
||||||
|
: runScript(scriptPath, info));
|
||||||
if (shouldRemove) await browserFetcher.remove(revision);
|
if (shouldRemove) await browserFetcher.remove(revision);
|
||||||
let outcome;
|
let outcome;
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
@ -124,7 +151,7 @@ if (!fs.existsSync(scriptPath)) {
|
|||||||
console.log(
|
console.log(
|
||||||
`RANGE: https://chromium.googlesource.com/chromium/src/+log/${fromSha}..${toSha}`
|
`RANGE: https://chromium.googlesource.com/chromium/src/+log/${fromSha}..${toSha}`
|
||||||
);
|
);
|
||||||
})(scriptPath, argv.good, argv.bad);
|
})(scriptPath, argv.good, argv.bad, argv['unit-test'], argv['no-cache']);
|
||||||
|
|
||||||
function runScript(scriptPath, revisionInfo) {
|
function runScript(scriptPath, revisionInfo) {
|
||||||
const log = debug('bisect:runscript');
|
const log = debug('bisect:runscript');
|
||||||
@ -142,6 +169,23 @@ function runScript(scriptPath, revisionInfo) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runUnitTest(pattern, revisionInfo) {
|
||||||
|
const log = debug('bisect:rununittest');
|
||||||
|
log('Running unit test');
|
||||||
|
const child = spawn('npm run unit', ['--', '-g', pattern], {
|
||||||
|
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
||||||
|
shell: true,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
PUPPETEER_EXECUTABLE_PATH: revisionInfo.executablePath,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
child.on('error', (err) => reject(err));
|
||||||
|
child.on('exit', (code) => resolve(code));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function downloadRevision(revision) {
|
async function downloadRevision(revision) {
|
||||||
const log = debug('bisect:download');
|
const log = debug('bisect:download');
|
||||||
log(`Downloading ${revision}`);
|
log(`Downloading ${revision}`);
|
||||||
@ -227,3 +271,18 @@ function fetchJSON(url) {
|
|||||||
req.end();
|
req.end();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChromiumRevision(gitRevision = null) {
|
||||||
|
const fileName = 'src/revisions.ts';
|
||||||
|
const command = gitRevision
|
||||||
|
? `git show ${gitRevision}:${fileName}`
|
||||||
|
: `cat ${fileName}`;
|
||||||
|
const result = execSync(command, {
|
||||||
|
encoding: 'utf8',
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const m = result.match(/chromium: '(\d+)'/);
|
||||||
|
if (!m) return null;
|
||||||
|
return parseInt(m[1], 10);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user