diff options
Diffstat (limited to 'lib/internal/coverage-gen')
-rw-r--r-- | lib/internal/coverage-gen/with_instrumentation.js | 36 | ||||
-rw-r--r-- | lib/internal/coverage-gen/with_profiler.js | 84 |
2 files changed, 120 insertions, 0 deletions
diff --git a/lib/internal/coverage-gen/with_instrumentation.js b/lib/internal/coverage-gen/with_instrumentation.js new file mode 100644 index 0000000000..711a3c3f12 --- /dev/null +++ b/lib/internal/coverage-gen/with_instrumentation.js @@ -0,0 +1,36 @@ +'use strict'; + +// This file contains hooks for nyc instrumented lib/ files to collect +// JS coverage for core. +// See `make coverage-build`. +function writeCoverage() { + if (!global.__coverage__) { + return; + } + + const path = require('path'); + const { mkdirSync, writeFileSync } = require('fs'); + + const dirname = path.join(path.dirname(process.execPath), '.coverage'); + const filename = `coverage-${process.pid}-${Date.now()}.json`; + try { + mkdirSync(dirname); + } catch (err) { + if (err.code !== 'EEXIST') { + console.error(err); + return; + } + } + + const target = path.join(dirname, filename); + const coverageInfo = JSON.stringify(global.__coverage__); + try { + writeFileSync(target, coverageInfo); + } catch (err) { + console.error(err); + } +} + +module.exports = { + writeCoverage +}; diff --git a/lib/internal/coverage-gen/with_profiler.js b/lib/internal/coverage-gen/with_profiler.js new file mode 100644 index 0000000000..6b17073939 --- /dev/null +++ b/lib/internal/coverage-gen/with_profiler.js @@ -0,0 +1,84 @@ +'use strict'; + +// Implements coverage collection exposed by the `NODE_V8_COVERAGE` +// environment variable which can also be used in the user land. + +let coverageConnection = null; +let coverageDirectory; + +function writeCoverage() { + if (!coverageConnection && coverageDirectory) { + return; + } + + const { join } = require('path'); + const { mkdirSync, writeFileSync } = require('fs'); + const { threadId } = require('internal/worker'); + + const filename = `coverage-${process.pid}-${Date.now()}-${threadId}.json`; + try { + mkdirSync(coverageDirectory, { recursive: true }); + } catch (err) { + if (err.code !== 'EEXIST') { + console.error(err); + return; + } + } + + const target = join(coverageDirectory, filename); + try { + disableAllAsyncHooks(); + let msg; + coverageConnection._coverageCallback = function(_msg) { + msg = _msg; + }; + coverageConnection.dispatch(JSON.stringify({ + id: 3, + method: 'Profiler.takePreciseCoverage' + })); + const coverageInfo = JSON.parse(msg).result; + writeFileSync(target, JSON.stringify(coverageInfo)); + } catch (err) { + console.error(err); + } finally { + coverageConnection.disconnect(); + coverageConnection = null; + } +} + +function disableAllAsyncHooks() { + const { getHookArrays } = require('internal/async_hooks'); + const [hooks_array] = getHookArrays(); + hooks_array.forEach((hook) => { hook.disable(); }); +} + +function startCoverageCollection() { + const { Connection } = internalBinding('inspector'); + coverageConnection = new Connection((res) => { + if (coverageConnection._coverageCallback) { + coverageConnection._coverageCallback(res); + } + }); + coverageConnection.dispatch(JSON.stringify({ + id: 1, + method: 'Profiler.enable' + })); + coverageConnection.dispatch(JSON.stringify({ + id: 2, + method: 'Profiler.startPreciseCoverage', + params: { + callCount: true, + detailed: true + } + })); +} + +function setCoverageDirectory(dir) { + coverageDirectory = dir; +} + +module.exports = { + startCoverageCollection, + writeCoverage, + setCoverageDirectory +}; |