-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add support for subprocess spawning (bcoe#11)
- Loading branch information
Showing
10 changed files
with
2,440 additions
and
408 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,34 @@ | ||
#!/usr/bin/env node | ||
'use strict' | ||
|
||
const CRI = require('chrome-remote-interface') | ||
const Exclude = require('test-exclude') | ||
const {isAbsolute} = require('path') | ||
const foreground = require('foreground-child') | ||
const mkdirp = require('mkdirp') | ||
const report = require('../lib/report') | ||
const {resolve} = require('path') | ||
const rimraf = require('rimraf') | ||
const spawn = require('../lib/spawn') | ||
const uuid = require('uuid') | ||
const v8ToIstanbul = require('v8-to-istanbul') | ||
const {writeFileSync} = require('fs') | ||
const sw = require('spawn-wrap') | ||
const { | ||
hideInstrumenteeArgs, | ||
hideInstrumenterArgs, | ||
yargs | ||
} = require('../lib/parse-args') | ||
|
||
const instrumenterArgs = hideInstrumenteeArgs() | ||
const argv = yargs.parse(instrumenterArgs) | ||
|
||
const exclude = Exclude({ | ||
include: argv.include, | ||
exclude: argv.exclude | ||
}) | ||
|
||
;(async function executeWithCoverage (instrumenteeArgv) { | ||
try { | ||
const bin = instrumenteeArgv.shift() | ||
const info = await spawn(bin, | ||
[`--inspect-brk=0`].concat(instrumenteeArgv)) | ||
const client = await CRI({port: info.port}) | ||
|
||
const initialPause = new Promise((resolve) => { | ||
client.once('Debugger.paused', resolve) | ||
}) | ||
|
||
const mainContextInfo = new Promise((resolve) => { | ||
client.once('Runtime.executionContextCreated', (message) => { | ||
resolve(message.context) | ||
}) | ||
}) | ||
|
||
const executionComplete = new Promise((resolve) => { | ||
client.on('Runtime.executionContextDestroyed', async (message) => { | ||
if (message.executionContextId === (await mainContextInfo).id) { | ||
resolve(message) | ||
} | ||
}) | ||
}) | ||
|
||
const {Debugger, Runtime, Profiler} = client | ||
await Promise.all([ | ||
Profiler.enable(), | ||
Runtime.enable(), | ||
Debugger.enable(), | ||
Profiler.startPreciseCoverage({callCount: true, detailed: true}), | ||
Runtime.runIfWaitingForDebugger(), | ||
initialPause | ||
]) | ||
await Debugger.resume() | ||
const argv = yargs.parse(instrumenterArgs) | ||
|
||
await executionComplete | ||
const allV8Coverage = await collectV8Coverage(Profiler) | ||
writeIstanbulFormatCoverage(allV8Coverage) | ||
await client.close() | ||
report({ | ||
reporter: Array.isArray(argv.reporter) ? argv.reporter : [argv.reporter], | ||
coverageDirectory: argv.coverageDirectory, | ||
watermarks: argv.watermarks | ||
}) | ||
} catch (err) { | ||
console.error(err) | ||
process.exit(1) | ||
} | ||
})(hideInstrumenterArgs(argv)) | ||
const tmpDirctory = resolve(argv.coverageDirectory, './tmp') | ||
rimraf.sync(tmpDirctory) | ||
mkdirp.sync(tmpDirctory) | ||
|
||
async function collectV8Coverage (Profiler) { | ||
let {result} = await Profiler.takePreciseCoverage() | ||
result = result.filter(({url}) => { | ||
url = url.replace('file://', '') | ||
return isAbsolute(url) && exclude.shouldInstrument(url) | ||
}) | ||
return result | ||
} | ||
sw([require.resolve('../lib/wrap')], { | ||
C8_ARGV: JSON.stringify(argv) | ||
}) | ||
|
||
function writeIstanbulFormatCoverage (allV8Coverage) { | ||
const tmpDirctory = resolve(argv.coverageDirectory, './tmp') | ||
rimraf.sync(tmpDirctory) | ||
mkdirp.sync(tmpDirctory) | ||
allV8Coverage.forEach((v8) => { | ||
const script = v8ToIstanbul(v8.url) | ||
script.applyCoverage(v8.functions) | ||
writeFileSync( | ||
resolve(tmpDirctory, `./${uuid.v4()}.json`), | ||
JSON.stringify(script.toIstanbul(), null, 2), | ||
'utf8' | ||
) | ||
foreground(hideInstrumenterArgs(argv), (out) => { | ||
report({ | ||
reporter: Array.isArray(argv.reporter) ? argv.reporter : [argv.reporter], | ||
coverageDirectory: argv.coverageDirectory, | ||
watermarks: argv.watermarks | ||
}) | ||
} | ||
}) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
#!/usr/bin/env node | ||
'use strict' | ||
|
||
const Exclude = require('test-exclude') | ||
const inspector = require('inspector') | ||
const {isAbsolute} = require('path') | ||
const onExit = require('signal-exit') | ||
const {resolve} = require('path') | ||
const sw = require('spawn-wrap') | ||
const uuid = require('uuid') | ||
const v8ToIstanbul = require('v8-to-istanbul') | ||
const {writeFileSync} = require('fs') | ||
|
||
const argv = JSON.parse(process.env.C8_ARGV) | ||
|
||
const exclude = Exclude({ | ||
include: argv.include, | ||
exclude: argv.exclude | ||
}) | ||
|
||
;(async function runInstrumented () { | ||
try { | ||
// bootstrap the inspector before kicking | ||
// off the user's code. | ||
inspector.open(0, true) | ||
const session = new inspector.Session() | ||
session.connect() | ||
|
||
session.post('Profiler.enable') | ||
session.post('Runtime.enable') | ||
session.post( | ||
'Profiler.startPreciseCoverage', | ||
{callCount: true, detailed: true} | ||
) | ||
|
||
// hook process.exit() and common exit signals, e.g., SIGTERM, | ||
// and output coverage report when these occur. | ||
onExit(() => { | ||
session.post('Profiler.takePreciseCoverage', (err, res) => { | ||
if (err) console.warn(err.message) | ||
else { | ||
try { | ||
const result = filterResult(res.result) | ||
writeIstanbulFormatCoverage(result) | ||
} catch (err) { | ||
console.warn(err.message) | ||
} | ||
} | ||
}) | ||
}, {alwaysLast: true}) | ||
|
||
// run the user's actual application. | ||
sw.runMain() | ||
} catch (err) { | ||
console.error(err) | ||
process.exit(1) | ||
} | ||
})() | ||
|
||
function filterResult (result) { | ||
result = result.filter(({url}) => { | ||
url = url.replace('file://', '') | ||
return isAbsolute(url) && | ||
exclude.shouldInstrument(url) && | ||
url !== __filename | ||
}) | ||
return result | ||
} | ||
|
||
function writeIstanbulFormatCoverage (allV8Coverage) { | ||
const tmpDirctory = resolve(argv.coverageDirectory, './tmp') | ||
allV8Coverage.forEach((v8) => { | ||
const script = v8ToIstanbul(v8.url) | ||
script.applyCoverage(v8.functions) | ||
writeFileSync( | ||
resolve(tmpDirctory, `./${uuid.v4()}.json`), | ||
JSON.stringify(script.toIstanbul(), null, 2), | ||
'utf8' | ||
) | ||
}) | ||
} |
Oops, something went wrong.